diff options
Diffstat (limited to 'services/java')
68 files changed, 7833 insertions, 4671 deletions
diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java index b8c44d9..32ac8e1 100644 --- a/services/java/com/android/server/AlarmManagerService.java +++ b/services/java/com/android/server/AlarmManagerService.java @@ -34,9 +34,9 @@ import android.os.Message; import android.os.PowerManager; import android.os.SystemClock; import android.os.SystemProperties; +import android.os.WorkSource; import android.text.TextUtils; import android.text.format.Time; -import android.util.EventLog; import android.util.Slog; import android.util.TimeUtils; @@ -50,6 +50,7 @@ import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.Iterator; +import java.util.LinkedList; import java.util.Map; import java.util.TimeZone; @@ -89,6 +90,7 @@ class AlarmManagerService extends IAlarmManager.Stub { private int mDescriptor; private int mBroadcastRefCount = 0; private PowerManager.WakeLock mWakeLock; + private LinkedList<PendingIntent> mInFlight = new LinkedList<PendingIntent>(); private final AlarmThread mWaitThread = new AlarmThread(); private final AlarmHandler mHandler = new AlarmHandler(); private ClockReceiver mClockReceiver; @@ -477,7 +479,8 @@ class AlarmManagerService extends IAlarmManager.Stub { : bs.filterStats.entrySet()) { pw.print(" "); pw.print(fe.getValue().count); pw.print(" alarms: "); - pw.println(fe.getKey().getIntent().toShortString(false, true, false)); + pw.println(fe.getKey().getIntent().toShortString( + false, true, false, true)); } } } @@ -667,10 +670,12 @@ class AlarmManagerService extends IAlarmManager.Stub { Intent.EXTRA_ALARM_COUNT, alarm.count), mResultReceiver, mHandler); - // we have an active broadcast so stay awake. + // we have an active broadcast so stay awake. if (mBroadcastRefCount == 0) { + setWakelockWorkSource(alarm.operation); mWakeLock.acquire(); } + mInFlight.add(alarm.operation); mBroadcastRefCount++; BroadcastStats bs = getStatsLocked(alarm.operation); @@ -699,7 +704,22 @@ class AlarmManagerService extends IAlarmManager.Stub { } } } - + + void setWakelockWorkSource(PendingIntent pi) { + try { + final int uid = ActivityManagerNative.getDefault() + .getUidForIntentSender(pi.getTarget()); + if (uid >= 0) { + mWakeLock.setWorkSource(new WorkSource(uid)); + return; + } + } catch (Exception e) { + } + + // Something went wrong; fall back to attributing the lock to the OS + mWakeLock.setWorkSource(null); + } + private class AlarmHandler extends Handler { public static final int ALARM_EVENT = 1; public static final int MINUTE_CHANGE_EVENT = 2; @@ -875,9 +895,20 @@ class AlarmManagerService extends IAlarmManager.Stub { fs.count++; } } + mInFlight.removeFirst(); mBroadcastRefCount--; if (mBroadcastRefCount == 0) { mWakeLock.release(); + } else { + // the next of our alarms is now in flight. reattribute the wakelock. + final PendingIntent nowInFlight = mInFlight.peekFirst(); + if (nowInFlight != null) { + setWakelockWorkSource(nowInFlight); + } else { + // should never happen + Slog.e(TAG, "Alarm wakelock still held but sent queue empty"); + mWakeLock.setWorkSource(null); + } } } } 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/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index eab60a7..352decf 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -2179,8 +2179,9 @@ private NetworkStateTracker makeWimaxStateTracker() { String dnsString = dns.getHostAddress(); if (changed || !dnsString.equals(SystemProperties.get("net.dns" + j + "." + pid))) { changed = true; - SystemProperties.set("net.dns" + j++ + "." + pid, dns.getHostAddress()); + SystemProperties.set("net.dns" + j + "." + pid, dns.getHostAddress()); } + j++; } return changed; } diff --git a/services/java/com/android/server/CountryDetectorService.java b/services/java/com/android/server/CountryDetectorService.java index ab61a3c..3112b50 100644 --- a/services/java/com/android/server/CountryDetectorService.java +++ b/services/java/com/android/server/CountryDetectorService.java @@ -81,6 +81,9 @@ public class CountryDetectorService extends ICountryDetector.Stub implements Run private final static String TAG = "CountryDetector"; + /** Whether to dump the state of the country detector service to bugreports */ + private static final boolean DEBUG = false; + private final HashMap<IBinder, Receiver> mReceivers; private final Context mContext; private ComprehensiveCountryDetector mCountryDetector; @@ -206,8 +209,10 @@ public class CountryDetectorService extends ICountryDetector.Stub implements Run return mSystemReady; } + @SuppressWarnings("unused") @Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) { + if (!DEBUG) return; try { final Printer p = new PrintWriterPrinter(fout); p.println("CountryDetectorService state:"); diff --git a/services/java/com/android/server/DropBoxManagerService.java b/services/java/com/android/server/DropBoxManagerService.java index d37c9ab..932cba1 100644 --- a/services/java/com/android/server/DropBoxManagerService.java +++ b/services/java/com/android/server/DropBoxManagerService.java @@ -28,6 +28,7 @@ import android.os.Debug; import android.os.DropBoxManager; import android.os.FileUtils; import android.os.Handler; +import android.os.Message; import android.os.StatFs; import android.os.SystemClock; import android.provider.Settings; @@ -64,6 +65,9 @@ public final class DropBoxManagerService extends IDropBoxManagerService.Stub { private static final int DEFAULT_RESERVE_PERCENT = 10; private static final int QUOTA_RESCAN_MILLIS = 5000; + // mHandler 'what' value. + private static final int MSG_SEND_BROADCAST = 1; + private static final boolean PROFILE_DUMP = false; // TODO: This implementation currently uses one file per entry, which is @@ -88,11 +92,11 @@ public final class DropBoxManagerService extends IDropBoxManagerService.Stub { private int mCachedQuotaBlocks = 0; // Space we can use: computed from free space, etc. private long mCachedQuotaUptimeMillis = 0; - // Ensure that all log entries have a unique timestamp - private long mLastTimestamp = 0; - private volatile boolean mBooted = false; + // Provide a way to perform sendBroadcast asynchronously to avoid deadlocks. + private final Handler mHandler; + /** Receives events that might indicate a need to clean up files. */ private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override @@ -143,11 +147,21 @@ public final class DropBoxManagerService extends IDropBoxManagerService.Stub { mContentResolver.registerContentObserver( Settings.Secure.CONTENT_URI, true, new ContentObserver(new Handler()) { + @Override public void onChange(boolean selfChange) { mReceiver.onReceive(context, (Intent) null); } }); + mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + if (msg.what == MSG_SEND_BROADCAST) { + mContext.sendBroadcast((Intent)msg.obj, android.Manifest.permission.READ_LOGS); + } + } + }; + // The real work gets done lazily in init() -- that way service creation always // succeeds, and things like disk problems cause individual method failures. } @@ -157,6 +171,7 @@ public final class DropBoxManagerService extends IDropBoxManagerService.Stub { mContext.unregisterReceiver(mReceiver); } + @Override public void add(DropBoxManager.Entry entry) { File temp = null; OutputStream output = null; @@ -227,14 +242,17 @@ public final class DropBoxManagerService extends IDropBoxManagerService.Stub { long time = createEntry(temp, tag, flags); temp = null; - Intent dropboxIntent = new Intent(DropBoxManager.ACTION_DROPBOX_ENTRY_ADDED); + final Intent dropboxIntent = new Intent(DropBoxManager.ACTION_DROPBOX_ENTRY_ADDED); dropboxIntent.putExtra(DropBoxManager.EXTRA_TAG, tag); dropboxIntent.putExtra(DropBoxManager.EXTRA_TIME, time); if (!mBooted) { dropboxIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); } - mContext.sendBroadcast(dropboxIntent, android.Manifest.permission.READ_LOGS); - + // Call sendBroadcast after returning from this call to avoid deadlock. In particular + // the caller may be holding the WindowManagerService lock but sendBroadcast requires a + // lock in ActivityManagerService. ActivityManagerService has been caught holding that + // very lock while waiting for the WindowManagerService lock. + mHandler.sendMessage(mHandler.obtainMessage(MSG_SEND_BROADCAST, dropboxIntent)); } catch (IOException e) { Slog.e(TAG, "Can't write: " + tag, e); } finally { diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java index c705646..96ee2f0 100644 --- a/services/java/com/android/server/InputMethodManagerService.java +++ b/services/java/com/android/server/InputMethodManagerService.java @@ -1132,6 +1132,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub private boolean needsToShowImeSwitchOngoingNotification() { if (!mShowOngoingImeSwitcherForPhones) return false; + if (isScreenLocked()) return false; synchronized (mMethodMap) { List<InputMethodInfo> imis = mSettings.getEnabledInputMethodListLocked(); final int N = imis.size(); @@ -2148,15 +2149,18 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mContext.startActivity(intent); } + private boolean isScreenLocked() { + return mKeyguardManager != null + && mKeyguardManager.isKeyguardLocked() && mKeyguardManager.isKeyguardSecure(); + } private void showInputMethodMenuInternal(boolean showSubtypes) { if (DEBUG) Slog.v(TAG, "Show switching menu"); final Context context = mContext; final PackageManager pm = context.getPackageManager(); - final boolean isScreenLocked = mKeyguardManager != null - && mKeyguardManager.isKeyguardLocked() && mKeyguardManager.isKeyguardSecure(); + final boolean isScreenLocked = isScreenLocked(); - String lastInputMethodId = Settings.Secure.getString(context + final String lastInputMethodId = Settings.Secure.getString(context .getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD); int lastInputMethodSubtypeId = getSelectedInputMethodSubtypeId(lastInputMethodId); if (DEBUG) Slog.v(TAG, "Current IME: " + lastInputMethodId); 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/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index 308661f..0b5eaff 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -34,8 +34,8 @@ import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.LinkedList; /** * Generic connector class for interfacing with a native daemon which uses the @@ -50,11 +50,15 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo private OutputStream mOutputStream; private LocalLog mLocalLog; - private final BlockingQueue<NativeDaemonEvent> mResponseQueue; + private final ResponseQueue mResponseQueue; private INativeDaemonConnectorCallbacks mCallbacks; private Handler mCallbackHandler; + private AtomicInteger mSequenceNumber; + + private static final int DEFAULT_TIMEOUT = 1 * 60 * 1000; /* 1 minute */ + /** Lock held whenever communicating with native daemon. */ private final Object mDaemonLock = new Object(); @@ -64,7 +68,8 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo int responseQueueSize, String logTag, int maxLogSize) { mCallbacks = callbacks; mSocket = socket; - mResponseQueue = new LinkedBlockingQueue<NativeDaemonEvent>(responseQueueSize); + mResponseQueue = new ResponseQueue(responseQueueSize); + mSequenceNumber = new AtomicInteger(0); TAG = logTag != null ? logTag : "NativeDaemonConnector"; mLocalLog = new LocalLog(maxLogSize); } @@ -79,7 +84,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo try { listenToSocket(); } catch (Exception e) { - Slog.e(TAG, "Error in NativeDaemonConnector", e); + loge("Error in NativeDaemonConnector: " + e); SystemClock.sleep(5000); } } @@ -90,12 +95,10 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo String event = (String) msg.obj; try { if (!mCallbacks.onEvent(msg.what, event, event.split(" "))) { - Slog.w(TAG, String.format( - "Unhandled event '%s'", event)); + log(String.format("Unhandled event '%s'", event)); } } catch (Exception e) { - Slog.e(TAG, String.format( - "Error handling '%s'", event), e); + loge("Error handling '" + event + "': " + e); } return true; } @@ -111,7 +114,9 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo socket.connect(address); InputStream inputStream = socket.getInputStream(); - mOutputStream = socket.getOutputStream(); + synchronized (mDaemonLock) { + mOutputStream = socket.getOutputStream(); + } mCallbacks.onDaemonConnected(); @@ -120,7 +125,10 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo while (true) { int count = inputStream.read(buffer, start, BUFFER_SIZE - start); - if (count < 0) break; + if (count < 0) { + loge("got " + count + " reading with start = " + start); + break; + } // Add our starting point to the count and reset the start. count += start; @@ -140,14 +148,10 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo mCallbackHandler.sendMessage(mCallbackHandler.obtainMessage( event.getCode(), event.getRawEvent())); } else { - try { - mResponseQueue.put(event); - } catch (InterruptedException ex) { - Slog.e(TAG, "Failed to put response onto queue: " + ex); - } + mResponseQueue.add(event.getCmdNumber(), event); } } catch (IllegalArgumentException e) { - Slog.w(TAG, "Problem parsing message: " + rawEvent, e); + log("Problem parsing message: " + rawEvent + " - " + e); } start = i + 1; @@ -169,15 +173,16 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo } } } catch (IOException ex) { - Slog.e(TAG, "Communications error", ex); + loge("Communications error: " + ex); throw ex; } finally { synchronized (mDaemonLock) { if (mOutputStream != null) { try { + loge("closing stream for " + mSocket); mOutputStream.close(); } catch (IOException e) { - Slog.w(TAG, "Failed closing output stream", e); + loge("Failed closing output stream: " + e); } mOutputStream = null; } @@ -188,24 +193,22 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo socket.close(); } } catch (IOException ex) { - Slog.w(TAG, "Failed closing socket", ex); + loge("Failed closing socket: " + ex); } } } /** - * Send command to daemon, escaping arguments as needed. - * - * @return the final command issued. + * Make command for daemon, escaping arguments as needed. */ - private String sendCommandLocked(String cmd, Object... args) + private void makeCommand(StringBuilder builder, String cmd, Object... args) throws NativeDaemonConnectorException { // TODO: eventually enforce that cmd doesn't contain arguments if (cmd.indexOf('\0') >= 0) { throw new IllegalArgumentException("unexpected command: " + cmd); } - final StringBuilder builder = new StringBuilder(cmd); + builder.append(cmd); for (Object arg : args) { final String argString = String.valueOf(arg); if (argString.indexOf('\0') >= 0) { @@ -215,23 +218,6 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo builder.append(' '); appendEscaped(builder, argString); } - - final String unterminated = builder.toString(); - log("SND -> {" + unterminated + "}"); - - builder.append('\0'); - - if (mOutputStream == null) { - throw new NativeDaemonConnectorException("missing output stream"); - } else { - try { - mOutputStream.write(builder.toString().getBytes(Charsets.UTF_8)); - } catch (IOException e) { - throw new NativeDaemonConnectorException("problem sending command", e); - } - } - - return unterminated; } /** @@ -292,39 +278,63 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo */ public NativeDaemonEvent[] executeForList(String cmd, Object... args) throws NativeDaemonConnectorException { - synchronized (mDaemonLock) { - return executeLocked(cmd, args); - } + return execute(DEFAULT_TIMEOUT, cmd, args); } - private NativeDaemonEvent[] executeLocked(String cmd, Object... args) + /** + * Issue the given command to the native daemon and return any + * {@linke NativeDaemonEvent@isClassContinue()} responses, including the + * final terminal response. Note that the timeout does not count time in + * deep sleep. + * + * @throws NativeDaemonConnectorException when problem communicating with + * native daemon, or if the response matches + * {@link NativeDaemonEvent#isClassClientError()} or + * {@link NativeDaemonEvent#isClassServerError()}. + */ + public NativeDaemonEvent[] execute(int timeout, String cmd, Object... args) throws NativeDaemonConnectorException { final ArrayList<NativeDaemonEvent> events = Lists.newArrayList(); - while (mResponseQueue.size() > 0) { - try { - log("ignoring {" + mResponseQueue.take() + "}"); - } catch (Exception e) {} - } + final int sequenceNumber = mSequenceNumber.incrementAndGet(); + final StringBuilder cmdBuilder = + new StringBuilder(Integer.toString(sequenceNumber)).append(' '); + + makeCommand(cmdBuilder, cmd, args); - final String sentCommand = sendCommandLocked(cmd, args); + final String logCmd = cmdBuilder.toString(); /* includes cmdNum, cmd, args */ + log("SND -> {" + logCmd + "}"); + + cmdBuilder.append('\0'); + final String sentCmd = cmdBuilder.toString(); /* logCmd + \0 */ + + synchronized (mDaemonLock) { + if (mOutputStream == null) { + throw new NativeDaemonConnectorException("missing output stream"); + } else { + try { + mOutputStream.write(sentCmd.getBytes(Charsets.UTF_8)); + } catch (IOException e) { + throw new NativeDaemonConnectorException("problem sending command", e); + } + } + } NativeDaemonEvent event = null; do { - try { - event = mResponseQueue.take(); - } catch (InterruptedException e) { - Slog.w(TAG, "interrupted waiting for event line"); - continue; + event = mResponseQueue.remove(sequenceNumber, timeout, sentCmd); + if (event == null) { + loge("timed-out waiting for response to " + logCmd); + throw new NativeDaemonFailureException(logCmd, event); } events.add(event); } while (event.isClassContinue()); if (event.isClassClientError()) { - throw new NativeDaemonArgumentException(sentCommand, event); + throw new NativeDaemonArgumentException(logCmd, event); } if (event.isClassServerError()) { - throw new NativeDaemonFailureException(sentCommand, event); + throw new NativeDaemonFailureException(logCmd, event); } return events.toArray(new NativeDaemonEvent[events.size()]); @@ -448,10 +458,120 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { mLocalLog.dump(fd, pw, args); + pw.println(); + mResponseQueue.dump(fd, pw, args); } private void log(String logstring) { if (LOGD) Slog.d(TAG, logstring); mLocalLog.log(logstring); } + + private void loge(String logstring) { + Slog.e(TAG, logstring); + mLocalLog.log(logstring); + } + + private static class ResponseQueue { + + private static class Response { + public int cmdNum; + public LinkedList<NativeDaemonEvent> responses = new LinkedList<NativeDaemonEvent>(); + public String request; + public Response(int c, String r) {cmdNum = c; request = r;} + } + + private final LinkedList<Response> mResponses; + private int mMaxCount; + + ResponseQueue(int maxCount) { + mResponses = new LinkedList<Response>(); + mMaxCount = maxCount; + } + + public void add(int cmdNum, NativeDaemonEvent response) { + Response found = null; + synchronized (mResponses) { + for (Response r : mResponses) { + if (r.cmdNum == cmdNum) { + found = r; + break; + } + } + if (found == null) { + // didn't find it - make sure our queue isn't too big before adding + // another.. + while (mResponses.size() >= mMaxCount) { + Slog.e("NativeDaemonConnector.ResponseQueue", + "more buffered than allowed: " + mResponses.size() + + " >= " + mMaxCount); + // let any waiter timeout waiting for this + Response r = mResponses.remove(); + Slog.e("NativeDaemonConnector.ResponseQueue", + "Removing request: " + r.request + " (" + r.cmdNum + ")"); + } + found = new Response(cmdNum, null); + mResponses.add(found); + } + found.responses.add(response); + } + synchronized (found) { + found.notify(); + } + } + + // note that the timeout does not count time in deep sleep. If you don't want + // the device to sleep, hold a wakelock + public NativeDaemonEvent remove(int cmdNum, int timeoutMs, String origCmd) { + long endTime = SystemClock.uptimeMillis() + timeoutMs; + long nowTime; + Response found = null; + while (true) { + synchronized (mResponses) { + for (Response response : mResponses) { + if (response.cmdNum == cmdNum) { + found = response; + // how many response fragments are left + switch (response.responses.size()) { + case 0: // haven't got any - must wait + break; + case 1: // last one - remove this from the master list + mResponses.remove(response); // fall through + default: // take one and move on + response.request = origCmd; + return response.responses.remove(); + } + } + } + nowTime = SystemClock.uptimeMillis(); + if (endTime <= nowTime) { + Slog.e("NativeDaemonConnector.ResponseQueue", + "Timeout waiting for response"); + return null; + } + /* pre-allocate so we have something unique to wait on */ + if (found == null) { + found = new Response(cmdNum, origCmd); + mResponses.add(found); + } + } + try { + synchronized (found) { + found.wait(endTime - nowTime); + } + } catch (InterruptedException e) { + // loop around to check if we're done or if it's time to stop waiting + } + } + } + + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println("Pending requests:"); + synchronized (mResponses) { + for (Response response : mResponses) { + pw.println(" Cmd " + response.cmdNum + " - " + response.request); + } + } + } + } } diff --git a/services/java/com/android/server/NativeDaemonEvent.java b/services/java/com/android/server/NativeDaemonEvent.java index 62084c0..d5e9f66 100644 --- a/services/java/com/android/server/NativeDaemonEvent.java +++ b/services/java/com/android/server/NativeDaemonEvent.java @@ -28,16 +28,22 @@ public class NativeDaemonEvent { // TODO: keep class ranges in sync with ResponseCode.h // TODO: swap client and server error ranges to roughly mirror HTTP spec + private final int mCmdNumber; private final int mCode; private final String mMessage; private final String mRawEvent; - private NativeDaemonEvent(int code, String message, String rawEvent) { + private NativeDaemonEvent(int cmdNumber, int code, String message, String rawEvent) { + mCmdNumber = cmdNumber; mCode = code; mMessage = message; mRawEvent = rawEvent; } + public int getCmdNumber() { + return mCmdNumber; + } + public int getCode() { return mCode; } @@ -89,7 +95,11 @@ public class NativeDaemonEvent { * Test if event represents an unsolicited event from native daemon. */ public boolean isClassUnsolicited() { - return mCode >= 600 && mCode < 700; + return isClassUnsolicited(mCode); + } + + private static boolean isClassUnsolicited(int code) { + return code >= 600 && code < 700; } /** @@ -110,20 +120,37 @@ public class NativeDaemonEvent { * from native side. */ public static NativeDaemonEvent parseRawEvent(String rawEvent) { - final int splitIndex = rawEvent.indexOf(' '); - if (splitIndex == -1) { - throw new IllegalArgumentException("unable to find ' ' separator"); + final String[] parsed = rawEvent.split(" "); + if (parsed.length < 2) { + throw new IllegalArgumentException("Insufficient arguments"); } + int skiplength = 0; + final int code; try { - code = Integer.parseInt(rawEvent.substring(0, splitIndex)); + code = Integer.parseInt(parsed[0]); + skiplength = parsed[0].length() + 1; } catch (NumberFormatException e) { throw new IllegalArgumentException("problem parsing code", e); } - final String message = rawEvent.substring(splitIndex + 1); - return new NativeDaemonEvent(code, message, rawEvent); + int cmdNumber = -1; + if (isClassUnsolicited(code) == false) { + if (parsed.length < 3) { + throw new IllegalArgumentException("Insufficient arguemnts"); + } + try { + cmdNumber = Integer.parseInt(parsed[1]); + skiplength += parsed[1].length() + 1; + } catch (NumberFormatException e) { + throw new IllegalArgumentException("problem parsing cmdNumber", e); + } + } + + final String message = rawEvent.substring(skiplength); + + return new NativeDaemonEvent(cmdNumber, code, message, rawEvent); } /** diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java index 7bb7938..09d0698 100644 --- a/services/java/com/android/server/NetworkManagementService.java +++ b/services/java/com/android/server/NetworkManagementService.java @@ -117,6 +117,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub public static final int InterfaceTxThrottleResult = 219; public static final int QuotaCounterResult = 220; public static final int TetheringStatsResult = 221; + public static final int DnsProxyQueryResult = 222; public static final int InterfaceChange = 600; public static final int BandwidthControl = 601; @@ -879,7 +880,6 @@ public class NetworkManagementService extends INetworkManagementService.Stub mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); try { wifiFirmwareReload(wlanIface, "AP"); - mConnector.execute("softap", "start", wlanIface); if (wifiConfig == null) { mConnector.execute("softap", "set", wlanIface, softapIface); } else { diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java index 624ee98..3db4601 100755 --- a/services/java/com/android/server/NotificationManagerService.java +++ b/services/java/com/android/server/NotificationManagerService.java @@ -79,6 +79,7 @@ public class NotificationManagerService extends INotificationManager.Stub private static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250}; private static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION; + private static final boolean SCORE_ONGOING_HIGHER = false; final Context mContext; final IActivityManager mAm; @@ -171,6 +172,7 @@ public class NotificationManagerService extends INotificationManager.Stub pw.println(prefix + " deleteIntent=" + notification.deleteIntent); pw.println(prefix + " tickerText=" + notification.tickerText); pw.println(prefix + " contentView=" + notification.contentView); + pw.println(prefix + " uid=" + uid); pw.println(prefix + " defaults=0x" + Integer.toHexString(notification.defaults)); pw.println(prefix + " flags=0x" + Integer.toHexString(notification.flags)); pw.println(prefix + " sound=" + notification.sound); @@ -720,7 +722,7 @@ public class NotificationManagerService extends INotificationManager.Stub // Migrate notification flags to scores if (0 != (notification.flags & Notification.FLAG_HIGH_PRIORITY)) { if (notification.priority < Notification.PRIORITY_MAX) notification.priority = Notification.PRIORITY_MAX; - } else if (0 != (notification.flags & Notification.FLAG_ONGOING_EVENT)) { + } else if (SCORE_ONGOING_HIGHER && 0 != (notification.flags & Notification.FLAG_ONGOING_EVENT)) { if (notification.priority < Notification.PRIORITY_HIGH) notification.priority = Notification.PRIORITY_HIGH; } diff --git a/services/java/com/android/server/NsdService.java b/services/java/com/android/server/NsdService.java new file mode 100644 index 0000000..768be7d --- /dev/null +++ b/services/java/com/android/server/NsdService.java @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.net.nsd.DnsSdServiceInfo; +import android.net.nsd.DnsSdTxtRecord; +import android.net.nsd.INsdManager; +import android.net.nsd.NsdManager; +import android.os.Binder; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Message; +import android.os.Messenger; +import android.os.IBinder; +import android.util.Slog; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.concurrent.CountDownLatch; +import java.util.List; + +import com.android.internal.app.IBatteryStats; +import com.android.internal.telephony.TelephonyIntents; +import com.android.internal.util.AsyncChannel; +import com.android.server.am.BatteryStatsService; +import com.android.server.NativeDaemonConnector.Command; +import com.android.internal.R; + +/** + * Network Service Discovery Service handles remote service discovery operation requests by + * implementing the INsdManager interface. + * + * @hide + */ +public class NsdService extends INsdManager.Stub { + private static final String TAG = "NsdService"; + private static final String MDNS_TAG = "mDnsConnector"; + + private static final boolean DBG = true; + + private Context mContext; + + /** + * Clients receiving asynchronous messages + */ + private List<AsyncChannel> mClients = new ArrayList<AsyncChannel>(); + + private AsyncChannel mReplyChannel = new AsyncChannel(); + + /** + * Handles client(app) connections + */ + private class AsyncServiceHandler extends Handler { + + AsyncServiceHandler(android.os.Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: + if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { + AsyncChannel c = (AsyncChannel) msg.obj; + if (DBG) Slog.d(TAG, "New client listening to asynchronous messages"); + c.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED); + mClients.add(c); + } else { + Slog.e(TAG, "Client connection failure, error=" + msg.arg1); + } + break; + case AsyncChannel.CMD_CHANNEL_DISCONNECTED: + if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) { + Slog.e(TAG, "Send failed, client connection lost"); + } else { + if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1); + } + mClients.remove((AsyncChannel) msg.obj); + break; + case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: + AsyncChannel ac = new AsyncChannel(); + ac.connect(mContext, this, msg.replyTo); + break; + case NsdManager.DISCOVER_SERVICES: + if (DBG) Slog.d(TAG, "Discover services"); + DnsSdServiceInfo s = (DnsSdServiceInfo) msg.obj; + discoverServices(1, s.getServiceType()); + mReplyChannel.replyToMessage(msg, NsdManager.DISCOVER_SERVICES_STARTED); + break; + case NsdManager.STOP_DISCOVERY: + if (DBG) Slog.d(TAG, "Stop service discovery"); + mReplyChannel.replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED); + break; + case NsdManager.REGISTER_SERVICE: + if (DBG) Slog.d(TAG, "Register service"); + mReplyChannel.replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED); + break; + case NsdManager.UPDATE_SERVICE: + if (DBG) Slog.d(TAG, "Update service"); + mReplyChannel.replyToMessage(msg, NsdManager.UPDATE_SERVICE_FAILED); + break; + default: + Slog.d(TAG, "NsdServicehandler.handleMessage ignoring msg=" + msg); + break; + } + } + } + private AsyncServiceHandler mAsyncServiceHandler; + + private NativeDaemonConnector mNativeConnector; + private final CountDownLatch mNativeDaemonConnected = new CountDownLatch(1); + + private NsdService(Context context) { + mContext = context; + + HandlerThread nsdThread = new HandlerThread("NsdService"); + nsdThread.start(); + mAsyncServiceHandler = new AsyncServiceHandler(nsdThread.getLooper()); + + /* + mNativeConnector = new NativeDaemonConnector(new NativeCallbackReceiver(), "mdns", 10, + MDNS_TAG, 25); + Thread th = new Thread(mNativeConnector, MDNS_TAG); + th.start(); + */ + } + + public static NsdService create(Context context) throws InterruptedException { + NsdService service = new NsdService(context); + /* service.mNativeDaemonConnected.await(); */ + return service; + } + + public Messenger getMessenger() { + return new Messenger(mAsyncServiceHandler); + } + + /* These should be in sync with system/netd/mDnsResponseCode.h */ + class NativeResponseCode { + public static final int SERVICE_FOUND = 101; + public static final int SERVICE_LOST = 102; + public static final int SERVICE_DISCOVERY_FAILED = 103; + + public static final int SERVICE_REGISTERED = 104; + public static final int SERVICE_REGISTRATION_FAILED = 105; + + public static final int SERVICE_UPDATED = 106; + public static final int SERVICE_UPDATE_FAILED = 107; + + public static final int SERVICE_RESOLVED = 108; + public static final int SERVICE_RESOLUTION_FAILED = 109; + } + + + class NativeCallbackReceiver implements INativeDaemonConnectorCallbacks { + public void onDaemonConnected() { + mNativeDaemonConnected.countDown(); + } + + public boolean onEvent(int code, String raw, String[] cooked) { + switch (code) { + case NativeResponseCode.SERVICE_FOUND: + /* NNN uniqueId serviceName regType */ + break; + case NativeResponseCode.SERVICE_LOST: + /* NNN uniqueId serviceName regType */ + break; + case NativeResponseCode.SERVICE_DISCOVERY_FAILED: + /* NNN uniqueId errorCode */ + break; + case NativeResponseCode.SERVICE_REGISTERED: + /* NNN regId serviceName regType */ + break; + case NativeResponseCode.SERVICE_REGISTRATION_FAILED: + /* NNN regId errorCode */ + break; + case NativeResponseCode.SERVICE_UPDATED: + /* NNN regId */ + break; + case NativeResponseCode.SERVICE_UPDATE_FAILED: + /* NNN regId errorCode */ + break; + case NativeResponseCode.SERVICE_RESOLVED: + /* NNN resolveId fullName hostName port txtlen txtdata */ + break; + case NativeResponseCode.SERVICE_RESOLUTION_FAILED: + /* NNN resovleId errorCode */ + break; + default: + break; + } + return false; + } + } + + private void registerService(int regId, DnsSdServiceInfo service) { + try { + //Add txtlen and txtdata + mNativeConnector.execute("mdnssd", "register", regId, service.getServiceName(), + service.getServiceType(), service.getPort()); + } catch(NativeDaemonConnectorException e) { + Slog.e(TAG, "Failed to execute registerService"); + } + } + + private void updateService(int regId, DnsSdTxtRecord t) { + try { + if (t == null) return; + mNativeConnector.execute("mdnssd", "update", regId, t.size(), t.getRawData()); + } catch(NativeDaemonConnectorException e) { + Slog.e(TAG, "Failed to updateServices"); + } + } + + private void discoverServices(int discoveryId, String serviceType) { + try { + mNativeConnector.execute("mdnssd", "discover", discoveryId, serviceType); + } catch(NativeDaemonConnectorException e) { + Slog.e(TAG, "Failed to discoverServices"); + } + } + + private void stopServiceDiscovery(int discoveryId) { + try { + mNativeConnector.execute("mdnssd", "stopdiscover", discoveryId); + } catch(NativeDaemonConnectorException e) { + Slog.e(TAG, "Failed to stopServiceDiscovery"); + } + } + + private void resolveService(DnsSdServiceInfo service) { + try { + mNativeConnector.execute("mdnssd", "resolve", service.getServiceName(), + service.getServiceType()); + } catch(NativeDaemonConnectorException e) { + Slog.e(TAG, "Failed to resolveService"); + } + } + + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) + != PackageManager.PERMISSION_GRANTED) { + pw.println("Permission Denial: can't dump ServiceDiscoverService from from pid=" + + Binder.getCallingPid() + + ", uid=" + Binder.getCallingUid()); + return; + } + + pw.println("Internal state:"); + } +} diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java index 7b4372f..52a4110 100644 --- a/services/java/com/android/server/PowerManagerService.java +++ b/services/java/com/android/server/PowerManagerService.java @@ -45,6 +45,7 @@ import android.os.HandlerThread; import android.os.IBinder; import android.os.IPowerManager; import android.os.LocalPowerManager; +import android.os.Message; import android.os.Power; import android.os.PowerManager; import android.os.Process; @@ -57,6 +58,7 @@ import android.util.EventLog; import android.util.Log; import android.util.Slog; import android.view.WindowManagerPolicy; +import static android.view.WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR; import static android.provider.Settings.System.DIM_SCREEN; import static android.provider.Settings.System.SCREEN_BRIGHTNESS; import static android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE; @@ -76,6 +78,7 @@ import java.util.Observer; public class PowerManagerService extends IPowerManager.Stub implements LocalPowerManager, Watchdog.Monitor { + private static final int NOMINAL_FRAME_TIME_MS = 1000/60; private static final String TAG = "PowerManagerService"; static final String PARTIAL_NAME = "PowerManagerService"; @@ -131,6 +134,7 @@ public class PowerManagerService extends IPowerManager.Stub private static final int DEFAULT_SCREEN_BRIGHTNESS = 192; // flags for setPowerState + private static final int ALL_LIGHTS_OFF = 0x00000000; private static final int SCREEN_ON_BIT = 0x00000001; private static final int SCREEN_BRIGHT_BIT = 0x00000002; private static final int BUTTON_BRIGHT_BIT = 0x00000004; @@ -157,11 +161,12 @@ public class PowerManagerService extends IPowerManager.Stub // used for noChangeLights in setPowerState() private static final int LIGHTS_MASK = SCREEN_BRIGHT_BIT | BUTTON_BRIGHT_BIT | KEYBOARD_BRIGHT_BIT; + // animate screen lights in PowerManager (as opposed to SurfaceFlinger) boolean mAnimateScreenLights = true; - static final int ANIM_STEPS = 60/4; + static final int ANIM_STEPS = 60; // nominal # of frames at 60Hz // Slower animation for autobrightness changes - static final int AUTOBRIGHTNESS_ANIM_STEPS = 60; + static final int AUTOBRIGHTNESS_ANIM_STEPS = 2 * ANIM_STEPS; // Number of steps when performing a more immediate brightness change. static final int IMMEDIATE_ANIM_STEPS = 4; @@ -221,12 +226,11 @@ public class PowerManagerService extends IPowerManager.Stub private UnsynchronizedWakeLock mPreventScreenOnPartialLock; private UnsynchronizedWakeLock mProximityPartialLock; private HandlerThread mHandlerThread; - private HandlerThread mScreenOffThread; private Handler mScreenOffHandler; + private Handler mScreenBrightnessHandler; private Handler mHandler; private final TimeoutTask mTimeoutTask = new TimeoutTask(); - private final BrightnessState mScreenBrightness - = new BrightnessState(SCREEN_BRIGHT_BIT); + private ScreenBrightnessAnimator mScreenBrightnessAnimator; private boolean mStillNeedSleepNotification; private boolean mIsPowered = false; private IActivityManager mActivityService; @@ -271,6 +275,7 @@ public class PowerManagerService extends IPowerManager.Stub private int mWarningSpewThrottleCount; private long mWarningSpewThrottleTime; private int mAnimationSetting = ANIM_SETTING_OFF; + private float mWindowScaleAnimation; // Must match with the ISurfaceComposer constants in C++. private static final int ANIM_SETTING_ON = 0x01; @@ -285,7 +290,8 @@ public class PowerManagerService extends IPowerManager.Stub private static final boolean mSpew = false; private static final boolean mDebugProximitySensor = (false || mSpew); private static final boolean mDebugLightSensor = (false || mSpew); - + private static final boolean mDebugLightAnimation = (false || mSpew); + private native void nativeInit(); private native void nativeSetPowerState(boolean screenOn, boolean screenBright); private native void nativeStartSurfaceFlingerAnimation(int mode); @@ -487,10 +493,10 @@ public class PowerManagerService extends IPowerManager.Stub // recalculate everything setScreenOffTimeoutsLocked(); - final float windowScale = getFloat(WINDOW_ANIMATION_SCALE, 1.0f); + mWindowScaleAnimation = getFloat(WINDOW_ANIMATION_SCALE, 1.0f); final float transitionScale = getFloat(TRANSITION_ANIMATION_SCALE, 1.0f); mAnimationSetting = 0; - if (windowScale > 0.5f) { + if (mWindowScaleAnimation > 0.5f) { mAnimationSetting |= ANIM_SETTING_OFF; } if (transitionScale > 0.5f) { @@ -540,28 +546,20 @@ public class PowerManagerService extends IPowerManager.Stub } mInitComplete = false; - mScreenOffThread = new HandlerThread("PowerManagerService.mScreenOffThread") { - @Override - protected void onLooperPrepared() { - mScreenOffHandler = new Handler(); - synchronized (mScreenOffThread) { - mInitComplete = true; - mScreenOffThread.notifyAll(); - } - } - }; - mScreenOffThread.start(); + mScreenBrightnessAnimator = new ScreenBrightnessAnimator("mScreenBrightnessUpdaterThread", + Process.THREAD_PRIORITY_DISPLAY); + mScreenBrightnessAnimator.start(); - synchronized (mScreenOffThread) { + synchronized (mScreenBrightnessAnimator) { while (!mInitComplete) { try { - mScreenOffThread.wait(); + mScreenBrightnessAnimator.wait(); } catch (InterruptedException e) { // Ignore } } } - + mInitComplete = false; mHandlerThread = new HandlerThread("PowerManagerService") { @Override @@ -581,7 +579,7 @@ public class PowerManagerService extends IPowerManager.Stub } } } - + nativeInit(); Power.powerInitNative(); synchronized (mLocks) { @@ -1079,7 +1077,6 @@ public class PowerManagerService extends IPowerManager.Stub int oldPokey = mPokey; int cumulative = 0; - boolean oldAwakeOnSet = mPokeAwakeOnSet; boolean awakeOnSet = false; for (PokeLock p: mPokeLocks.values()) { cumulative |= p.pokey; @@ -1199,7 +1196,7 @@ public class PowerManagerService extends IPowerManager.Stub + " mLightSensorKeyboardBrightness=" + mLightSensorKeyboardBrightness); pw.println(" mUseSoftwareAutoBrightness=" + mUseSoftwareAutoBrightness); pw.println(" mAutoBrightessEnabled=" + mAutoBrightessEnabled); - mScreenBrightness.dump(pw, " mScreenBrightness: "); + mScreenBrightnessAnimator.dump(pw, " mScreenBrightnessAnimator: "); int N = mLocks.size(); pw.println(); @@ -1431,7 +1428,7 @@ public class PowerManagerService extends IPowerManager.Stub private WindowManagerPolicy.ScreenOnListener mScreenOnListener = new WindowManagerPolicy.ScreenOnListener() { - @Override public void onScreenOn() { + public void onScreenOn() { synchronized (mLocks) { if (mPreparingForScreenOn) { mPreparingForScreenOn = false; @@ -1720,7 +1717,8 @@ public class PowerManagerService extends IPowerManager.Stub + Integer.toHexString(mPowerState) + " mSkippedScreenOn=" + mSkippedScreenOn); } - mScreenBrightness.forceValueLocked(Power.BRIGHTNESS_OFF); + mScreenBrightnessHandler.removeMessages(ScreenBrightnessAnimator.ANIMATE_LIGHTS); + mScreenBrightnessAnimator.animateTo(Power.BRIGHTNESS_OFF, SCREEN_BRIGHT_BIT, 0); } } int err = Power.setScreenState(on); @@ -1860,6 +1858,7 @@ public class PowerManagerService extends IPowerManager.Stub } else { // Update the lights *before* taking care of turning the // screen off, so we can initiate any animations that are desired. + mScreenOffReason = reason; if (stateChanged) { updateLightsLocked(newState, 0); } @@ -1878,8 +1877,7 @@ public class PowerManagerService extends IPowerManager.Stub Binder.restoreCallingIdentity(identity); } mPowerState &= ~SCREEN_ON_BIT; - mScreenOffReason = reason; - if (!mScreenBrightness.animating) { + if (!mScreenBrightnessAnimator.isAnimating()) { err = screenOffFinishedAnimatingLocked(reason); } else { err = 0; @@ -1953,11 +1951,11 @@ public class PowerManagerService extends IPowerManager.Stub // If the screen is not currently on, we will want to delay actually // turning the lights on if we are still getting the UI put up. - if ((oldState&SCREEN_ON_BIT) == 0 || mSkippedScreenOn) { + if ((oldState & SCREEN_ON_BIT) == 0 || mSkippedScreenOn) { // Don't turn screen on until we know we are really ready to. // This is to avoid letting the screen go on before things like the // lock screen have been displayed. - if ((mSkippedScreenOn=shouldDeferScreenOnLocked())) { + if ((mSkippedScreenOn = shouldDeferScreenOnLocked())) { newState &= ~(SCREEN_ON_BIT|SCREEN_BRIGHT_BIT); } } @@ -2017,7 +2015,7 @@ public class PowerManagerService extends IPowerManager.Stub case SCREEN_BRIGHT_BIT: default: // not possible - nominalCurrentValue = (int)mScreenBrightness.curValue; + nominalCurrentValue = (int)mScreenBrightnessAnimator.getCurrentBrightness(); break; } } @@ -2067,8 +2065,8 @@ public class PowerManagerService extends IPowerManager.Stub Binder.restoreCallingIdentity(identity); } if (!mSkippedScreenOn) { - mScreenBrightness.setTargetLocked(brightness, steps, - INITIAL_SCREEN_BRIGHTNESS, nominalCurrentValue); + int dt = steps * NOMINAL_FRAME_TIME_MS; + mScreenBrightnessAnimator.animateTo(brightness, SCREEN_BRIGHT_BIT, dt); if (DEBUG_SCREEN_ON) { RuntimeException e = new RuntimeException("here"); e.fillInStackTrace(); @@ -2111,154 +2109,168 @@ public class PowerManagerService extends IPowerManager.Stub } } - private void setLightBrightness(int mask, int value) { - int brightnessMode = (mAutoBrightessEnabled - ? LightsService.BRIGHTNESS_MODE_SENSOR - : LightsService.BRIGHTNESS_MODE_USER); - if ((mask & SCREEN_BRIGHT_BIT) != 0) { - if (DEBUG_SCREEN_ON) { - RuntimeException e = new RuntimeException("here"); - e.fillInStackTrace(); - Slog.i(TAG, "Set LCD brightness: " + value, e); - } - mLcdLight.setBrightness(value, brightnessMode); - } - if ((mask & BUTTON_BRIGHT_BIT) != 0) { - mButtonLight.setBrightness(value); - } - if ((mask & KEYBOARD_BRIGHT_BIT) != 0) { - mKeyboardLight.setBrightness(value); + /** + * Note: by design this class does not hold mLocks while calling native methods. + * Nor should it. Ever. + */ + class ScreenBrightnessAnimator extends HandlerThread { + static final int ANIMATE_LIGHTS = 10; + static final int ANIMATE_POWER_OFF = 11; + volatile int startValue; + volatile int endValue; + volatile int currentValue; + private int currentMask; + private int duration; + private long startTimeMillis; + private final String prefix; + + public ScreenBrightnessAnimator(String name, int priority) { + super(name, priority); + prefix = name; } - } - class BrightnessState implements Runnable { - final int mask; + @Override + protected void onLooperPrepared() { + mScreenBrightnessHandler = new Handler() { + public void handleMessage(Message msg) { + int brightnessMode = (mAutoBrightessEnabled && !mInitialAnimation + ? LightsService.BRIGHTNESS_MODE_SENSOR + : LightsService.BRIGHTNESS_MODE_USER); + if (msg.what == ANIMATE_LIGHTS) { + final int mask = msg.arg1; + int value = msg.arg2; + long tStart = SystemClock.uptimeMillis(); + if ((mask & SCREEN_BRIGHT_BIT) != 0) { + if (mDebugLightAnimation) Log.v(TAG, "Set brightness: " + value); + mLcdLight.setBrightness(value, brightnessMode); + } + long elapsed = SystemClock.uptimeMillis() - tStart; + if ((mask & BUTTON_BRIGHT_BIT) != 0) { + mButtonLight.setBrightness(value); + } + if ((mask & KEYBOARD_BRIGHT_BIT) != 0) { + mKeyboardLight.setBrightness(value); + } - boolean initialized; - int targetValue; - float curValue; - float delta; - boolean animating; + if (elapsed > 100) { + Log.e(TAG, "Excessive delay setting brightness: " + elapsed + + "ms, mask=" + mask); + } - BrightnessState(int m) { - mask = m; + // Throttle brightness updates to frame refresh rate + int delay = elapsed < NOMINAL_FRAME_TIME_MS ? NOMINAL_FRAME_TIME_MS : 0; + synchronized(this) { + currentValue = value; + } + animateInternal(mask, false, delay); + } else if (msg.what == ANIMATE_POWER_OFF) { + int mode = msg.arg1; + nativeStartSurfaceFlingerAnimation(mode); + } + } + }; + synchronized (this) { + mInitComplete = true; + notifyAll(); + } } - public void dump(PrintWriter pw, String prefix) { - pw.println(prefix + "animating=" + animating - + " targetValue=" + targetValue - + " curValue=" + curValue - + " delta=" + delta); - } + private void animateInternal(int mask, boolean turningOff, int delay) { + synchronized (this) { + if (currentValue != endValue) { + final long now = SystemClock.elapsedRealtime(); + final int elapsed = (int) (now - startTimeMillis); + int newValue; + if (elapsed < duration) { + int delta = endValue - startValue; + newValue = startValue + delta * elapsed / duration; + newValue = Math.max(Power.BRIGHTNESS_OFF, newValue); + newValue = Math.min(Power.BRIGHTNESS_ON, newValue); + } else { + newValue = endValue; + mInitialAnimation = false; + } - void forceValueLocked(int value) { - targetValue = -1; - curValue = value; - setLightBrightness(mask, value); - if (animating) { - finishAnimationLocked(false, value); - } - } + if (mDebugLightAnimation) { + Log.v(TAG, "Animating light: " + "start:" + startValue + + ", end:" + endValue + ", elapsed:" + elapsed + + ", duration:" + duration + ", current:" + currentValue + + ", delay:" + delay); + } - void setTargetLocked(int target, int stepsToTarget, int initialValue, - int nominalCurrentValue) { - if (!initialized) { - initialized = true; - curValue = (float)initialValue; - } else if (targetValue == target) { - return; - } - targetValue = target; - delta = (targetValue - - (nominalCurrentValue >= 0 ? nominalCurrentValue : curValue)) - / stepsToTarget; - if (mSpew || DEBUG_SCREEN_ON) { - String noticeMe = nominalCurrentValue == curValue ? "" : " ******************"; - Slog.i(TAG, "setTargetLocked mask=" + mask + " curValue=" + curValue - + " target=" + target + " targetValue=" + targetValue + " delta=" + delta - + " nominalCurrentValue=" + nominalCurrentValue - + noticeMe); + if (turningOff && !mHeadless && !mAnimateScreenLights) { + int mode = mScreenOffReason == OFF_BECAUSE_OF_PROX_SENSOR + ? 0 : mAnimationSetting; + if (mDebugLightAnimation) Log.v(TAG, "Doing power-off anim, mode=" + mode); + mScreenBrightnessHandler.obtainMessage(ANIMATE_POWER_OFF, mode, 0) + .sendToTarget(); + } + Message msg = mScreenBrightnessHandler + .obtainMessage(ANIMATE_LIGHTS, mask, newValue); + mScreenBrightnessHandler.sendMessageDelayed(msg, delay); + } } - animating = true; + } - if (mSpew) { - Slog.i(TAG, "scheduling light animator"); - } - mScreenOffHandler.removeCallbacks(this); - mScreenOffHandler.post(this); + public void dump(PrintWriter pw, String string) { + pw.println(prefix + "animating: " + "start:" + startValue + ", end:" + endValue + + ", duration:" + duration + ", current:" + currentValue); } - boolean stepLocked() { - if (!animating) return false; - if (false && mSpew) { - Slog.i(TAG, "Step target " + mask + ": cur=" + curValue - + " target=" + targetValue + " delta=" + delta); - } - curValue += delta; - int curIntValue = (int)curValue; - boolean more = true; - if (delta == 0) { - curValue = curIntValue = targetValue; - more = false; - } else if (delta > 0) { - if (curIntValue >= targetValue) { - curValue = curIntValue = targetValue; - more = false; + public void animateTo(int target, int mask, int animationDuration) { + synchronized(this) { + startValue = currentValue; + endValue = target; + currentMask = mask; + duration = (int) (mWindowScaleAnimation * animationDuration); + startTimeMillis = SystemClock.elapsedRealtime(); + mInitialAnimation = currentValue == 0 && target > 0; + + if (mDebugLightAnimation) { + Log.v(TAG, "animateTo(target=" + target + ", mask=" + mask + + ", duration=" + animationDuration +")" + + ", currentValue=" + currentValue + + ", startTime=" + startTimeMillis); } - } else { - if (curIntValue <= targetValue) { - curValue = curIntValue = targetValue; - more = false; + + if (target != currentValue) { + final boolean doScreenAnim = (mask & (SCREEN_BRIGHT_BIT | SCREEN_ON_BIT)) != 0; + final boolean turningOff = endValue == Power.BRIGHTNESS_OFF; + if (turningOff && doScreenAnim) { + // Cancel all pending animations since we're turning off + mScreenBrightnessHandler.removeCallbacksAndMessages(null); + screenOffFinishedAnimatingLocked(mScreenOffReason); + duration = 200; // TODO: how long should this be? + } + if (doScreenAnim) { + animateInternal(mask, turningOff, 0); + } + // TODO: Handle keyboard light animation when we have devices that support it } } - if (mSpew) Slog.d(TAG, "Animating curIntValue=" + curIntValue + ": " + mask); - setLightBrightness(mask, curIntValue); - finishAnimationLocked(more, curIntValue); - return more; } - void jumpToTargetLocked() { - if (mSpew) Slog.d(TAG, "jumpToTargetLocked targetValue=" + targetValue + ": " + mask); - setLightBrightness(mask, targetValue); - final int tv = targetValue; - curValue = tv; - targetValue = -1; - finishAnimationLocked(false, tv); + public int getCurrentBrightness() { + synchronized (this) { + return currentValue; + } } - private void finishAnimationLocked(boolean more, int curIntValue) { - animating = more; - if (!more) { - if (mask == SCREEN_BRIGHT_BIT && curIntValue == Power.BRIGHTNESS_OFF) { - screenOffFinishedAnimatingLocked(mScreenOffReason); - } + public boolean isAnimating() { + synchronized (this) { + return currentValue != endValue; } } - public void run() { - synchronized (mLocks) { - // we're turning off - final boolean turningOff = animating && targetValue == Power.BRIGHTNESS_OFF; - if (mAnimateScreenLights || !turningOff) { - long now = SystemClock.uptimeMillis(); - boolean more = mScreenBrightness.stepLocked(); - if (more) { - mScreenOffHandler.postAtTime(this, now+(1000/60)); - } - } else { - if (!mHeadless) { - // It's pretty scary to hold mLocks for this long, and we should - // redesign this, but it works for now. - nativeStartSurfaceFlingerAnimation( - mScreenOffReason == WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR - ? 0 : mAnimationSetting); - } - mScreenBrightness.jumpToTargetLocked(); - } - } + public void cancelAnimation() { + animateTo(endValue, currentMask, 0); } } + private void setLightBrightness(int mask, int value) { + mScreenBrightnessAnimator.animateTo(value, mask, 0); + } + private int getPreferredBrightness() { if (mScreenBrightnessOverride >= 0) { return mScreenBrightnessOverride; @@ -2326,7 +2338,8 @@ public class PowerManagerService extends IPowerManager.Stub } private boolean isScreenTurningOffLocked() { - return (mScreenBrightness.animating && mScreenBrightness.targetValue == 0); + return (mScreenBrightnessAnimator.isAnimating() + && mScreenBrightnessAnimator.endValue == Power.BRIGHTNESS_OFF); } private boolean shouldLog(long time) { @@ -2347,7 +2360,7 @@ public class PowerManagerService extends IPowerManager.Stub private void forceUserActivityLocked() { if (isScreenTurningOffLocked()) { // cancel animation so userActivity will succeed - mScreenBrightness.animating = false; + mScreenBrightnessAnimator.cancelAnimation(); } boolean savedActivityAllowed = mUserActivityAllowed; mUserActivityAllowed = true; @@ -2526,6 +2539,8 @@ public class PowerManagerService extends IPowerManager.Stub } }; + private boolean mInitialAnimation; // used to prevent lightsensor changes while turning on + private void dockStateChanged(int state) { synchronized (mLocks) { mIsDocked = (state != Intent.EXTRA_DOCK_STATE_UNDOCKED); @@ -2587,10 +2602,11 @@ public class PowerManagerService extends IPowerManager.Stub } if (mAutoBrightessEnabled && mScreenBrightnessOverride < 0) { - if (!mSkippedScreenOn) { - mScreenBrightness.setTargetLocked(lcdValue, - immediate ? IMMEDIATE_ANIM_STEPS : AUTOBRIGHTNESS_ANIM_STEPS, - INITIAL_SCREEN_BRIGHTNESS, (int)mScreenBrightness.curValue); + if (!mSkippedScreenOn && !mInitialAnimation) { + int steps = immediate ? IMMEDIATE_ANIM_STEPS : AUTOBRIGHTNESS_ANIM_STEPS; + mScreenBrightnessAnimator.cancelAnimation(); + mScreenBrightnessAnimator.animateTo(lcdValue, + SCREEN_BRIGHT_BIT, steps * NOMINAL_FRAME_TIME_MS); } } if (mButtonBrightnessOverride < 0) { @@ -2642,7 +2658,7 @@ public class PowerManagerService extends IPowerManager.Stub synchronized (this) { ShutdownThread.reboot(mContext, finalReason, false); } - + } }; // ShutdownThread must run on a looper capable of displaying the UI. @@ -2996,9 +3012,7 @@ public class PowerManagerService extends IPowerManager.Stub } finally { Binder.restoreCallingIdentity(identity); } - - mScreenBrightness.targetValue = brightness; - mScreenBrightness.jumpToTargetLocked(); + mScreenBrightnessAnimator.animateTo(brightness, SCREEN_BRIGHT_BIT, 0); } } diff --git a/services/java/com/android/server/StatusBarManagerService.java b/services/java/com/android/server/StatusBarManagerService.java index a9ff6c5..8429086 100644 --- a/services/java/com/android/server/StatusBarManagerService.java +++ b/services/java/com/android/server/StatusBarManagerService.java @@ -292,27 +292,27 @@ public class StatusBarManagerService extends IStatusBarService.Stub } } - public void setSystemUiVisibility(int vis) { + public void setSystemUiVisibility(int vis, int mask) { // also allows calls from window manager which is in this process. enforceStatusBarService(); if (SPEW) Slog.d(TAG, "setSystemUiVisibility(0x" + Integer.toHexString(vis) + ")"); synchronized (mLock) { - updateUiVisibilityLocked(vis); + updateUiVisibilityLocked(vis, mask); disableLocked(vis & StatusBarManager.DISABLE_MASK, mSysUiVisToken, "WindowManager.LayoutParams"); } } - private void updateUiVisibilityLocked(final int vis) { + private void updateUiVisibilityLocked(final int vis, final int mask) { if (mSystemUiVisibility != vis) { mSystemUiVisibility = vis; mHandler.post(new Runnable() { public void run() { if (mBar != null) { try { - mBar.setSystemUiVisibility(vis); + mBar.setSystemUiVisibility(vis, mask); } catch (RemoteException ex) { } } @@ -352,6 +352,24 @@ public class StatusBarManagerService extends IStatusBarService.Stub } } + @Override + public void preloadRecentApps() { + if (mBar != null) { + try { + mBar.preloadRecentApps(); + } catch (RemoteException ex) {} + } + } + + @Override + public void cancelPreloadRecentApps() { + if (mBar != null) { + try { + mBar.cancelPreloadRecentApps(); + } catch (RemoteException ex) {} + } + } + private void enforceStatusBar() { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR, "StatusBarManagerService"); diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index c9b5997..7dd736d 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -47,6 +47,7 @@ import android.view.WindowManager; import com.android.internal.app.ShutdownThread; import com.android.internal.os.BinderInternal; import com.android.internal.os.SamplingProfilerIntegration; +import com.android.internal.widget.LockSettingsService; import com.android.server.accessibility.AccessibilityManagerService; import com.android.server.am.ActivityManagerService; import com.android.server.net.NetworkPolicyManagerService; @@ -120,6 +121,7 @@ class ServerThread extends Thread { ConnectivityService connectivity = null; WifiP2pService wifiP2p = null; WifiService wifi = null; + NsdService serviceDiscovery= null; IPackageManager pm = null; Context context = null; WindowManagerService wm = null; @@ -219,6 +221,7 @@ class ServerThread extends Thread { factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL, !firstBoot); ServiceManager.addService(Context.WINDOW_SERVICE, wm); + ServiceManager.addService(Context.INPUT_SERVICE, wm.getInputManagerService()); ActivityManagerService.self().setWindowManager(wm); @@ -265,6 +268,7 @@ class ServerThread extends Thread { LocationManagerService location = null; CountryDetectorService countryDetector = null; TextServicesManagerService tsms = null; + LockSettingsService lockSettings = null; // Bring up services needed for UI. if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) { @@ -307,6 +311,14 @@ class ServerThread extends Thread { if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) { try { + Slog.i(TAG, "LockSettingsService"); + lockSettings = new LockSettingsService(context); + ServiceManager.addService("lock_settings", lockSettings); + } catch (Throwable e) { + reportWtf("starting LockSettingsService service", e); + } + + try { Slog.i(TAG, "Device Policy"); devicePolicy = new DevicePolicyManagerService(context); ServiceManager.addService(Context.DEVICE_POLICY_SERVICE, devicePolicy); @@ -394,6 +406,15 @@ class ServerThread extends Thread { } try { + Slog.i(TAG, "Network Service Discovery Service"); + serviceDiscovery = NsdService.create(context); + ServiceManager.addService( + Context.NSD_SERVICE, serviceDiscovery); + } catch (Throwable e) { + reportWtf("starting Service Discovery Service", e); + } + + try { Slog.i(TAG, "Throttle Service"); throttle = new ThrottleService(context); ServiceManager.addService( @@ -402,6 +423,14 @@ class ServerThread extends Thread { reportWtf("starting ThrottleService", e); } + try { + Slog.i(TAG, "UpdateLock Service"); + ServiceManager.addService(Context.UPDATE_LOCK_SERVICE, + new UpdateLockService(context)); + } catch (Throwable e) { + reportWtf("starting UpdateLockService", e); + } + if (!"0".equals(SystemProperties.get("system_init.startmountservice"))) { try { /* @@ -643,6 +672,11 @@ class ServerThread extends Thread { } catch (Throwable e) { reportWtf("making Package Manager Service ready", e); } + try { + lockSettings.systemReady(); + } catch (Throwable e) { + reportWtf("making Lock Settings Service ready", e); + } // These are needed to propagate to the runnable below. final Context contextF = context; diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/java/com/android/server/TelephonyRegistry.java index 8c8e725..1b1638a 100644 --- a/services/java/com/android/server/TelephonyRegistry.java +++ b/services/java/com/android/server/TelephonyRegistry.java @@ -29,6 +29,7 @@ import android.telephony.CellLocation; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.SignalStrength; +import android.telephony.CellInfo; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Slog; @@ -107,6 +108,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { private int mOtaspMode = ServiceStateTracker.OTASP_UNKNOWN; + private CellInfo mCellInfo = null; + static final int PHONE_STATE_PERMISSION_MASK = PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR | PhoneStateListener.LISTEN_CALL_STATE | @@ -236,6 +239,13 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { remove(r.binder); } } + if ((events & PhoneStateListener.LISTEN_CELL_INFO) != 0) { + try { + r.callback.onCellInfoChanged(new CellInfo(mCellInfo)); + } catch (RemoteException ex) { + remove(r.binder); + } + } } } } else { @@ -325,6 +335,26 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { broadcastSignalStrengthChanged(signalStrength); } + public void notifyCellInfo(CellInfo cellInfo) { + if (!checkNotifyPermission("notifyCellInfo()")) { + return; + } + + synchronized (mRecords) { + mCellInfo = cellInfo; + for (Record r : mRecords) { + if ((r.events & PhoneStateListener.LISTEN_CELL_INFO) != 0) { + try { + r.callback.onCellInfoChanged(new CellInfo(cellInfo)); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } + } + } + handleRemoveListLocked(); + } + } + public void notifyMessageWaitingChanged(boolean mwi) { if (!checkNotifyPermission("notifyMessageWaitingChanged()")) { return; @@ -530,6 +560,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { pw.println(" mDataConnectionLinkProperties=" + mDataConnectionLinkProperties); pw.println(" mDataConnectionLinkCapabilities=" + mDataConnectionLinkCapabilities); pw.println(" mCellLocation=" + mCellLocation); + pw.println(" mCellInfo=" + mCellInfo); pw.println("registrations: count=" + recordCount); for (Record r : mRecords) { pw.println(" " + r.pkgForDebug + " 0x" + Integer.toHexString(r.events)); @@ -655,6 +686,12 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } + if ((events & PhoneStateListener.LISTEN_CELL_INFO) != 0) { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.ACCESS_COARSE_LOCATION, null); + + } + if ((events & PHONE_STATE_PERMISSION_MASK) != 0) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.READ_PHONE_STATE, null); diff --git a/services/java/com/android/server/UiModeManagerService.java b/services/java/com/android/server/UiModeManagerService.java index c5c2901..84daead 100644 --- a/services/java/com/android/server/UiModeManagerService.java +++ b/services/java/com/android/server/UiModeManagerService.java @@ -189,8 +189,8 @@ class UiModeManagerService extends IUiModeManager.Stub { } try { ActivityManagerNative.getDefault().startActivityWithConfig( - null, homeIntent, null, null, 0, null, null, 0, false, false, - newConfig); + null, homeIntent, null, null, null, 0, 0, + newConfig, null); mHoldingConfiguration = false; } catch (RemoteException e) { Slog.w(TAG, e.getCause()); diff --git a/services/java/com/android/server/UpdateLockService.java b/services/java/com/android/server/UpdateLockService.java new file mode 100644 index 0000000..1ffd196 --- /dev/null +++ b/services/java/com/android/server/UpdateLockService.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.Binder; +import android.os.Handler; +import android.os.IBinder; +import android.os.IUpdateLock; +import android.os.RemoteException; +import android.os.SystemClock; +import android.os.TokenWatcher; +import android.os.UpdateLock; +import android.util.Slog; + +import java.io.FileDescriptor; +import java.io.PrintWriter; + +public class UpdateLockService extends IUpdateLock.Stub { + static final boolean DEBUG = false; + static final String TAG = "UpdateLockService"; + + // signatureOrSystem required to use update locks + static final String PERMISSION = "android.permission.UPDATE_LOCK"; + + Context mContext; + LockWatcher mLocks; + + class LockWatcher extends TokenWatcher { + LockWatcher(Handler h, String tag) { + super(h, tag); + } + + public void acquired() { + if (DEBUG) { + Slog.d(TAG, "first acquire; broadcasting convenient=false"); + } + sendLockChangedBroadcast(false); + } + public void released() { + if (DEBUG) { + Slog.d(TAG, "last release; broadcasting convenient=true"); + } + sendLockChangedBroadcast(true); + } + } + + UpdateLockService(Context context) { + mContext = context; + mLocks = new LockWatcher(new Handler(), "UpdateLocks"); + + // Consider just-booting to be a reasonable time to allow + // interruptions for update installation etc. + sendLockChangedBroadcast(true); + } + + void sendLockChangedBroadcast(boolean state) { + // Safe early during boot because this broadcast only goes to registered receivers. + long oldIdent = Binder.clearCallingIdentity(); + try { + Intent intent = new Intent(UpdateLock.UPDATE_LOCK_CHANGED) + .putExtra(UpdateLock.NOW_IS_CONVENIENT, state) + .putExtra(UpdateLock.TIMESTAMP, System.currentTimeMillis()) + .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + mContext.sendStickyBroadcast(intent); + } finally { + Binder.restoreCallingIdentity(oldIdent); + } + } + + @Override + public void acquireUpdateLock(IBinder token, String tag) throws RemoteException { + if (DEBUG) { + Slog.d(TAG, "acquire(" + token + ") by " + makeTag(tag)); + } + + mContext.enforceCallingOrSelfPermission(PERMISSION, "acquireUpdateLock"); + mLocks.acquire(token, makeTag(tag)); + } + + @Override + public void releaseUpdateLock(IBinder token) throws RemoteException { + if (DEBUG) { + Slog.d(TAG, "release(" + token + ')'); + } + + mContext.enforceCallingOrSelfPermission(PERMISSION, "releaseUpdateLock"); + mLocks.release(token); + }; + + private String makeTag(String tag) { + return "{tag=" + tag + + " uid=" + Binder.getCallingUid() + + " pid=" + Binder.getCallingPid() + '}'; + } + + @Override + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) + != PackageManager.PERMISSION_GRANTED) { + pw.println("Permission Denial: can't dump update lock service from from pid=" + + Binder.getCallingPid() + + ", uid=" + Binder.getCallingUid()); + return; + } + + mLocks.dump(pw); + } +} 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/WifiService.java b/services/java/com/android/server/WifiService.java index 5208785..e2a2c83 100644 --- a/services/java/com/android/server/WifiService.java +++ b/services/java/com/android/server/WifiService.java @@ -101,9 +101,6 @@ public class WifiService extends IWifiManager.Stub { private boolean mEmergencyCallbackMode = false; private int mPluggedType; - /* Chipset supports background scan */ - private final boolean mBackgroundScanSupported; - private final LockList mLocks = new LockList(); // some wifi lock statistics private int mFullHighPerfLocksAcquired; @@ -263,47 +260,46 @@ public class WifiService extends IWifiManager.Stub { ac.connect(mContext, this, msg.replyTo); break; } - case WifiManager.CMD_ENABLE_TRAFFIC_STATS_POLL: { + case WifiManager.ENABLE_TRAFFIC_STATS_POLL: { mEnableTrafficStatsPoll = (msg.arg1 == 1); mTrafficStatsPollToken++; if (mEnableTrafficStatsPoll) { notifyOnDataActivity(); - sendMessageDelayed(Message.obtain(this, WifiManager.CMD_TRAFFIC_STATS_POLL, + sendMessageDelayed(Message.obtain(this, WifiManager.TRAFFIC_STATS_POLL, mTrafficStatsPollToken, 0), POLL_TRAFFIC_STATS_INTERVAL_MSECS); } break; } - case WifiManager.CMD_TRAFFIC_STATS_POLL: { + case WifiManager.TRAFFIC_STATS_POLL: { if (msg.arg1 == mTrafficStatsPollToken) { notifyOnDataActivity(); - sendMessageDelayed(Message.obtain(this, WifiManager.CMD_TRAFFIC_STATS_POLL, + sendMessageDelayed(Message.obtain(this, WifiManager.TRAFFIC_STATS_POLL, mTrafficStatsPollToken, 0), POLL_TRAFFIC_STATS_INTERVAL_MSECS); } break; } - case WifiManager.CMD_CONNECT_NETWORK: { - if (msg.obj != null) { - mWifiStateMachine.connectNetwork((WifiConfiguration)msg.obj); - } else { - mWifiStateMachine.connectNetwork(msg.arg1); - } + case WifiManager.CONNECT_NETWORK: { + mWifiStateMachine.sendMessage(Message.obtain(msg)); break; } - case WifiManager.CMD_SAVE_NETWORK: { - mWifiStateMachine.saveNetwork((WifiConfiguration)msg.obj); + case WifiManager.SAVE_NETWORK: { + mWifiStateMachine.sendMessage(Message.obtain(msg)); break; } - case WifiManager.CMD_FORGET_NETWORK: { - mWifiStateMachine.forgetNetwork(msg.arg1); + case WifiManager.FORGET_NETWORK: { + mWifiStateMachine.sendMessage(Message.obtain(msg)); break; } - case WifiManager.CMD_START_WPS: { - //replyTo has the original source - mWifiStateMachine.startWps(msg.replyTo, (WpsInfo)msg.obj); + case WifiManager.START_WPS: { + mWifiStateMachine.sendMessage(Message.obtain(msg)); break; } - case WifiManager.CMD_DISABLE_NETWORK: { - mWifiStateMachine.disableNetwork(msg.replyTo, msg.arg1, msg.arg2); + case WifiManager.CANCEL_WPS: { + mWifiStateMachine.sendMessage(Message.obtain(msg)); + break; + } + case WifiManager.DISABLE_NETWORK: { + mWifiStateMachine.sendMessage(Message.obtain(msg)); break; } default: { @@ -436,9 +432,6 @@ public class WifiService extends IWifiManager.Stub { Settings.Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, 900) * 1000l; mNotificationEnabledSettingObserver = new NotificationEnabledSettingObserver(new Handler()); mNotificationEnabledSettingObserver.register(); - - mBackgroundScanSupported = mContext.getResources().getBoolean( - com.android.internal.R.bool.config_wifi_background_scan_support); } /** @@ -914,7 +907,7 @@ public class WifiService extends IWifiManager.Stub { * Get a reference to handler. This is used by a client to establish * an AsyncChannel communication with WifiService */ - public Messenger getMessenger() { + public Messenger getWifiServiceMessenger() { /* Enforce the highest permissions TODO: when we consider exposing the asynchronous API, think about how to provide both access and change permissions seperately @@ -924,6 +917,13 @@ public class WifiService extends IWifiManager.Stub { return new Messenger(mAsyncServiceHandler); } + /** Get a reference to WifiStateMachine handler for AsyncChannel communication */ + public Messenger getWifiStateMachineMessenger() { + enforceAccessPermission(); + enforceChangePermission(); + return mWifiStateMachine.getMessenger(); + } + /** * Get the IP and proxy configuration file */ @@ -950,11 +950,6 @@ public class WifiService extends IWifiManager.Stub { mAlarmManager.cancel(mIdleIntent); mScreenOff = false; evaluateTrafficStatsPolling(); - mWifiStateMachine.enableRssiPolling(true); - if (mBackgroundScanSupported) { - mWifiStateMachine.enableBackgroundScanCommand(false); - } - mWifiStateMachine.enableAllNetworks(); setDeviceIdleAndUpdateWifi(false); } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { if (DBG) { @@ -962,10 +957,6 @@ public class WifiService extends IWifiManager.Stub { } mScreenOff = true; evaluateTrafficStatsPolling(); - mWifiStateMachine.enableRssiPolling(false); - if (mBackgroundScanSupported) { - mWifiStateMachine.enableBackgroundScanCommand(true); - } /* * Set a timer to put Wi-Fi to sleep, but only if the screen is off * AND the "stay on while plugged in" setting doesn't match the @@ -1587,10 +1578,10 @@ public class WifiService extends IWifiManager.Stub { Message msg; if (mNetworkInfo.getDetailedState() == DetailedState.CONNECTED && !mScreenOff) { msg = Message.obtain(mAsyncServiceHandler, - WifiManager.CMD_ENABLE_TRAFFIC_STATS_POLL, 1, 0); + WifiManager.ENABLE_TRAFFIC_STATS_POLL, 1, 0); } else { msg = Message.obtain(mAsyncServiceHandler, - WifiManager.CMD_ENABLE_TRAFFIC_STATS_POLL, 0, 0); + WifiManager.ENABLE_TRAFFIC_STATS_POLL, 0, 0); } msg.sendToTarget(); } 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/accessibility/AccessibilityInputFilter.java b/services/java/com/android/server/accessibility/AccessibilityInputFilter.java index 769cb6a..31aa21e 100644 --- a/services/java/com/android/server/accessibility/AccessibilityInputFilter.java +++ b/services/java/com/android/server/accessibility/AccessibilityInputFilter.java @@ -16,7 +16,7 @@ package com.android.server.accessibility; -import com.android.server.wm.InputFilter; +import com.android.server.input.InputFilter; import android.content.Context; import android.util.Slog; diff --git a/services/java/com/android/server/accessibility/TouchExplorer.java b/services/java/com/android/server/accessibility/TouchExplorer.java index 41cf9a6..d07aa7a 100644 --- a/services/java/com/android/server/accessibility/TouchExplorer.java +++ b/services/java/com/android/server/accessibility/TouchExplorer.java @@ -29,7 +29,7 @@ import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import com.android.server.accessibility.AccessibilityInputFilter.Explorer; -import com.android.server.wm.InputFilter; +import com.android.server.input.InputFilter; import java.util.Arrays; diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 3ac446c..80e59cd 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -16,6 +16,8 @@ package com.android.server.am; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; + import com.android.internal.R; import com.android.internal.os.BatteryStatsImpl; import com.android.internal.os.ProcessStats; @@ -32,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; @@ -49,19 +52,20 @@ import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; -import android.app.WallpaperManager; import android.app.backup.IBackupManager; import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; +import android.content.ClipData; import android.content.ComponentCallbacks2; import android.content.ComponentName; +import android.content.ContentProvider; import android.content.ContentResolver; import android.content.Context; import android.content.DialogInterface; -import android.content.Intent; -import android.content.IntentFilter; import android.content.IIntentReceiver; import android.content.IIntentSender; +import android.content.Intent; +import android.content.IntentFilter; import android.content.IntentSender; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; @@ -71,12 +75,12 @@ import android.content.pm.IPackageManager; import android.content.pm.InstrumentationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PathPermission; import android.content.pm.ProviderInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.UserInfo; -import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.graphics.Bitmap; @@ -107,11 +111,12 @@ import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserId; import android.provider.Settings; +import android.text.format.Time; import android.util.EventLog; -import android.util.Pair; -import android.util.Slog; import android.util.Log; +import android.util.Pair; import android.util.PrintWriterPrinter; +import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; import android.util.TimeUtils; @@ -135,7 +140,6 @@ import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.StringWriter; -import java.lang.IllegalStateException; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Collection; @@ -147,6 +151,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; @@ -194,6 +199,8 @@ public final class ActivityManagerService extends ActivityManagerNative private static final String SYSTEM_DEBUGGABLE = "ro.debuggable"; + static final boolean IS_USER_BUILD = "user".equals(Build.TYPE); + // Maximum number of recent tasks that we can remember. static final int MAX_RECENT_TASKS = 20; @@ -283,9 +290,7 @@ public final class ActivityManagerService extends ActivityManagerNative static class PendingActivityLaunch { ActivityRecord r; ActivityRecord sourceRecord; - Uri[] grantedUriPermissions; - int grantedMode; - boolean onlyIfNeeded; + int startFlags; } final ArrayList<PendingActivityLaunch> mPendingActivityLaunches @@ -746,6 +751,7 @@ public final class ActivityManagerService extends ActivityManagerNative ParcelFileDescriptor mProfileFd; int mProfileType = 0; boolean mAutoStopProfiler = false; + String mOpenGlTraceApp = null; final RemoteCallbackList<IProcessObserver> mProcessObservers = new RemoteCallbackList<IProcessObserver>(); @@ -897,10 +903,15 @@ public final class ActivityManagerService extends ActivityManagerNative null, null, 0, null, null, null, false, false, MY_PID, Process.SYSTEM_UID, 0 /* TODO: Verify */); - Dialog d = new AppNotRespondingDialog(ActivityManagerService.this, - mContext, proc, (ActivityRecord)data.get("activity")); - d.show(); - proc.anrDialog = d; + if (mShowDialogs) { + Dialog d = new AppNotRespondingDialog(ActivityManagerService.this, + mContext, proc, (ActivityRecord)data.get("activity")); + d.show(); + proc.anrDialog = d; + } else { + // Just kill the app if there is no dialog to be shown. + killAppAtUsersRequest(proc, null); + } } ensureBootCompleted(); @@ -1074,7 +1085,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: { @@ -1284,7 +1296,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) { @@ -1786,7 +1798,8 @@ public final class ActivityManagerService extends ActivityManagerNative final ProcessRecord getProcessRecordLocked( String processName, int uid) { - if (uid == Process.SYSTEM_UID) { + // Temporary hack to make Settings run per user + if (uid == Process.SYSTEM_UID && !processName.equals("com.android.settings")) { // The system gets to run in any process. If there are multiple // processes with the same uid, just pick the first (this // should never happen). @@ -2091,8 +2104,8 @@ public final class ActivityManagerService extends ActivityManagerNative aInfo.applicationInfo.uid); if (app == null || app.instrumentationClass == null) { intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK); - mMainStack.startActivityLocked(null, intent, null, null, 0, aInfo, - null, null, 0, 0, 0, false, false, null); + mMainStack.startActivityLocked(null, intent, null, aInfo, + null, null, 0, 0, 0, 0, null, false, null); } } @@ -2146,8 +2159,8 @@ public final class ActivityManagerService extends ActivityManagerNative intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setComponent(new ComponentName( ri.activityInfo.packageName, ri.activityInfo.name)); - mMainStack.startActivityLocked(null, intent, null, null, 0, ri.activityInfo, - null, null, 0, 0, 0, false, false, null); + mMainStack.startActivityLocked(null, intent, null, ri.activityInfo, + null, null, 0, 0, 0, 0, null, false, null); } } } @@ -2253,17 +2266,15 @@ public final class ActivityManagerService extends ActivityManagerNative for (int i=0; i<N; i++) { PendingActivityLaunch pal = mPendingActivityLaunches.get(i); mMainStack.startActivityUncheckedLocked(pal.r, pal.sourceRecord, - pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded, - doResume && i == (N-1)); + pal.startFlags, doResume && i == (N-1), null); } mPendingActivityLaunches.clear(); } public final int startActivity(IApplicationThread caller, - Intent intent, String resolvedType, Uri[] grantedUriPermissions, - int grantedMode, IBinder resultTo, - String resultWho, int requestCode, boolean onlyIfNeeded, boolean debug, - String profileFile, ParcelFileDescriptor profileFd, boolean autoStopProfiler) { + Intent intent, String resolvedType, IBinder resultTo, + String resultWho, int requestCode, int startFlags, + String profileFile, ParcelFileDescriptor profileFd, Bundle options) { enforceNotIsolatedCaller("startActivity"); int userId = 0; if (intent.getCategories() != null && intent.getCategories().contains(Intent.CATEGORY_HOME)) { @@ -2280,42 +2291,38 @@ public final class ActivityManagerService extends ActivityManagerNative } } return mMainStack.startActivityMayWait(caller, -1, intent, resolvedType, - grantedUriPermissions, grantedMode, resultTo, resultWho, requestCode, onlyIfNeeded, - debug, profileFile, profileFd, autoStopProfiler, null, null, userId); + resultTo, resultWho, requestCode, startFlags, profileFile, profileFd, + null, null, options, userId); } public final WaitResult startActivityAndWait(IApplicationThread caller, - Intent intent, String resolvedType, Uri[] grantedUriPermissions, - int grantedMode, IBinder resultTo, - String resultWho, int requestCode, boolean onlyIfNeeded, boolean debug, - String profileFile, ParcelFileDescriptor profileFd, boolean autoStopProfiler) { + Intent intent, String resolvedType, IBinder resultTo, + String resultWho, int requestCode, int startFlags, String profileFile, + ParcelFileDescriptor profileFd, Bundle options) { enforceNotIsolatedCaller("startActivityAndWait"); WaitResult res = new WaitResult(); int userId = Binder.getOrigCallingUser(); mMainStack.startActivityMayWait(caller, -1, intent, resolvedType, - grantedUriPermissions, grantedMode, resultTo, resultWho, - requestCode, onlyIfNeeded, debug, profileFile, profileFd, autoStopProfiler, - res, null, userId); + resultTo, resultWho, requestCode, startFlags, profileFile, profileFd, + res, null, options, userId); return res; } - + public final int startActivityWithConfig(IApplicationThread caller, - Intent intent, String resolvedType, Uri[] grantedUriPermissions, - int grantedMode, IBinder resultTo, - String resultWho, int requestCode, boolean onlyIfNeeded, - boolean debug, Configuration config) { + Intent intent, String resolvedType, IBinder resultTo, + String resultWho, int requestCode, int startFlags, Configuration config, + Bundle options) { enforceNotIsolatedCaller("startActivityWithConfig"); int ret = mMainStack.startActivityMayWait(caller, -1, intent, resolvedType, - grantedUriPermissions, grantedMode, resultTo, resultWho, - requestCode, onlyIfNeeded, - debug, null, null, false, null, config, Binder.getOrigCallingUser()); + resultTo, resultWho, requestCode, startFlags, + null, null, null, config, options, Binder.getOrigCallingUser()); return ret; } public int startActivityIntentSender(IApplicationThread caller, IntentSender intent, Intent fillInIntent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, - int flagsMask, int flagsValues) { + int flagsMask, int flagsValues, Bundle options) { enforceNotIsolatedCaller("startActivityIntentSender"); // Refuse possible leaked file descriptors if (fillInIntent != null && fillInIntent.hasFileDescriptors()) { @@ -2338,13 +2345,13 @@ public final class ActivityManagerService extends ActivityManagerNative mAppSwitchesAllowedTime = 0; } } - int ret = pir.sendInner(0, fillInIntent, resolvedType, null, - null, resultTo, resultWho, requestCode, flagsMask, flagsValues); + int ret = pir.sendInner(0, fillInIntent, resolvedType, null, null, + resultTo, resultWho, requestCode, flagsMask, flagsValues, options); return ret; } public boolean startNextMatchingActivity(IBinder callingActivity, - Intent intent) { + Intent intent, Bundle options) { // Refuse possible leaked file descriptors if (intent != null && intent.hasFileDescriptors() == true) { throw new IllegalArgumentException("File descriptors passed in Intent"); @@ -2353,10 +2360,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); @@ -2370,7 +2379,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; @@ -2392,6 +2402,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (aInfo == null) { // Nobody who is next! + ActivityOptions.abort(options); return false; } @@ -2421,16 +2432,14 @@ 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, null, 0, aInfo, - resultTo != null ? resultTo.appToken : null, resultWho, - requestCode, -1, r.launchedFromUid, false, false, null); + r.resolvedType, aInfo, resultTo != null ? resultTo.appToken : null, + resultWho, requestCode, -1, r.launchedFromUid, 0, + options, false, null); Binder.restoreCallingIdentity(origId); r.finishing = wasFinishing; - if (res != START_SUCCESS) { + if (res != ActivityManager.START_SUCCESS) { return false; } return true; @@ -2439,7 +2448,7 @@ public final class ActivityManagerService extends ActivityManagerNative public final int startActivityInPackage(int uid, Intent intent, String resolvedType, IBinder resultTo, - String resultWho, int requestCode, boolean onlyIfNeeded) { + String resultWho, int requestCode, int startFlags, Bundle options) { // This is so super not safe, that only the system (or okay root) // can do it. @@ -2451,21 +2460,22 @@ public final class ActivityManagerService extends ActivityManagerNative } int ret = mMainStack.startActivityMayWait(null, uid, intent, resolvedType, - null, 0, resultTo, resultWho, requestCode, onlyIfNeeded, false, - null, null, false, null, null, userId); + resultTo, resultWho, requestCode, startFlags, + null, null, null, null, options, userId); return ret; } public final int startActivities(IApplicationThread caller, - Intent[] intents, String[] resolvedTypes, IBinder resultTo) { + Intent[] intents, String[] resolvedTypes, IBinder resultTo, Bundle options) { enforceNotIsolatedCaller("startActivities"); int ret = mMainStack.startActivities(caller, -1, intents, resolvedTypes, resultTo, - Binder.getOrigCallingUser()); + options, Binder.getOrigCallingUser()); return ret; } public final int startActivitiesInPackage(int uid, - Intent[] intents, String[] resolvedTypes, IBinder resultTo) { + Intent[] intents, String[] resolvedTypes, IBinder resultTo, + Bundle options) { // This is so super not safe, that only the system (or okay root) // can do it. @@ -2475,7 +2485,7 @@ public final class ActivityManagerService extends ActivityManagerNative "startActivityInPackage only available to the system"); } int ret = mMainStack.startActivities(null, uid, intents, resolvedTypes, resultTo, - UserId.getUserId(uid)); + options, UserId.getUserId(uid)); return ret; } @@ -2965,6 +2975,12 @@ public final class ActivityManagerService extends ActivityManagerNative return null; } + dumpStackTraces(tracesPath, firstPids, processStats, lastPids); + return tracesFile; + } + + private static void dumpStackTraces(String tracesPath, ArrayList<Integer> firstPids, + ProcessStats processStats, SparseArray<Boolean> lastPids) { // Use a FileObserver to detect when traces finish writing. // The order of traces is considered important to maintain for legibility. FileObserver observer = new FileObserver(tracesPath, FileObserver.CLOSE_WRITE) { @@ -2975,16 +2991,18 @@ public final class ActivityManagerService extends ActivityManagerNative observer.startWatching(); // First collect all of the stacks of the most important pids. - try { - int num = firstPids.size(); - for (int i = 0; i < num; i++) { - synchronized (observer) { - Process.sendSignal(firstPids.get(i), Process.SIGNAL_QUIT); - observer.wait(200); // Wait for write-close, give up after 200msec + if (firstPids != null) { + try { + int num = firstPids.size(); + for (int i = 0; i < num; i++) { + synchronized (observer) { + Process.sendSignal(firstPids.get(i), Process.SIGNAL_QUIT); + observer.wait(200); // Wait for write-close, give up after 200msec + } } + } catch (InterruptedException e) { + Log.wtf(TAG, e); } - } catch (InterruptedException e) { - Log.wtf(TAG, e); } // Next measure CPU usage. @@ -3020,13 +3038,83 @@ public final class ActivityManagerService extends ActivityManagerNative } } - return tracesFile; - } finally { observer.stopWatching(); } } + final void logAppTooSlow(ProcessRecord app, long startTime, String msg) { + if (true || IS_USER_BUILD) { + return; + } + String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null); + if (tracesPath == null || tracesPath.length() == 0) { + return; + } + + StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads(); + StrictMode.allowThreadDiskWrites(); + try { + final File tracesFile = new File(tracesPath); + final File tracesDir = tracesFile.getParentFile(); + final File tracesTmp = new File(tracesDir, "__tmp__"); + try { + if (!tracesDir.exists()) tracesFile.mkdirs(); + FileUtils.setPermissions(tracesDir.getPath(), 0775, -1, -1); // drwxrwxr-x + + if (tracesFile.exists()) { + tracesTmp.delete(); + tracesFile.renameTo(tracesTmp); + } + StringBuilder sb = new StringBuilder(); + Time tobj = new Time(); + tobj.set(System.currentTimeMillis()); + sb.append(tobj.format("%Y-%m-%d %H:%M:%S")); + sb.append(": "); + TimeUtils.formatDuration(SystemClock.uptimeMillis()-startTime, sb); + sb.append(" since "); + sb.append(msg); + FileOutputStream fos = new FileOutputStream(tracesFile); + fos.write(sb.toString().getBytes()); + if (app == null) { + fos.write("\n*** No application process!".getBytes()); + } + fos.close(); + FileUtils.setPermissions(tracesFile.getPath(), 0666, -1, -1); // -rw-rw-rw- + } catch (IOException e) { + Slog.w(TAG, "Unable to prepare slow app traces file: " + tracesPath, e); + return; + } + + if (app != null) { + ArrayList<Integer> firstPids = new ArrayList<Integer>(); + firstPids.add(app.pid); + dumpStackTraces(tracesPath, firstPids, null, null); + } + + File lastTracesFile = null; + File curTracesFile = null; + for (int i=9; i>=0; i--) { + String name = String.format("slow%02d.txt", i); + curTracesFile = new File(tracesDir, name); + if (curTracesFile.exists()) { + if (lastTracesFile != null) { + curTracesFile.renameTo(lastTracesFile); + } else { + curTracesFile.delete(); + } + } + lastTracesFile = curTracesFile; + } + tracesFile.renameTo(curTracesFile); + if (tracesTmp.exists()) { + tracesTmp.renameTo(tracesFile); + } + } finally { + StrictMode.setThreadPolicy(oldPolicy); + } + } + final void appNotResponding(ProcessRecord app, ActivityRecord activity, ActivityRecord parent, final String annotation) { ArrayList<Integer> firstPids = new ArrayList<Integer>(5); @@ -3213,7 +3301,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) { @@ -3234,7 +3322,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); @@ -3261,13 +3349,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) { @@ -3334,16 +3423,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) { @@ -3352,7 +3439,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 " @@ -3467,7 +3554,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) { @@ -3501,9 +3588,12 @@ 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))) { if (app.setAdj >= minOomAdj) { if (!doit) { return true; @@ -3524,13 +3614,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) { } } @@ -3554,7 +3644,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) { @@ -3574,14 +3665,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)) { @@ -3605,7 +3695,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) { @@ -3833,6 +3923,11 @@ public final class ActivityManagerService extends ActivityManagerNative profileFd = mProfileFd; profileAutoStop = mAutoStopProfiler; } + boolean enableOpenGlTrace = false; + if (mOpenGlTraceApp != null && mOpenGlTraceApp.equals(processName)) { + enableOpenGlTrace = true; + mOpenGlTraceApp = null; + } // If the app is being launched for restore or full backup, set it up specially boolean isRestrictedBackupMode = false; @@ -3858,8 +3953,8 @@ public final class ActivityManagerService extends ActivityManagerNative } thread.bindApplication(processName, appInfo, providers, app.instrumentationClass, profileFile, profileFd, profileAutoStop, - app.instrumentationArguments, app.instrumentationWatcher, testMode, - isRestrictedBackupMode || !normalMode, app.persistent, + app.instrumentationArguments, app.instrumentationWatcher, testMode, + enableOpenGlTrace, isRestrictedBackupMode || !normalMode, app.persistent, new Configuration(mConfiguration), app.compat, getCommonServicesLocked(), mCoreSettingsObserver.getCoreSettingsLocked()); updateLruProcessLocked(app, false, true); @@ -4024,16 +4119,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. @@ -4169,7 +4273,8 @@ public final class ActivityManagerService extends ActivityManagerNative public IIntentSender getIntentSender(int type, String packageName, IBinder token, String resultWho, - int requestCode, Intent[] intents, String[] resolvedTypes, int flags) { + int requestCode, Intent[] intents, String[] resolvedTypes, + int flags, Bundle options) { enforceNotIsolatedCaller("getIntentSender"); // Refuse possible leaked file descriptors if (intents != null) { @@ -4182,7 +4287,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (intent.hasFileDescriptors()) { throw new IllegalArgumentException("File descriptors passed in Intent"); } - if (type == INTENT_SENDER_BROADCAST && + if (type == ActivityManager.INTENT_SENDER_BROADCAST && (intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) { throw new IllegalArgumentException( "Can't use FLAG_RECEIVER_BOOT_UPGRADE here"); @@ -4195,14 +4300,19 @@ public final class ActivityManagerService extends ActivityManagerNative "Intent array length does not match resolvedTypes length"); } } + if (options != null) { + if (options.hasFileDescriptors()) { + throw new IllegalArgumentException("File descriptors passed in options"); + } + } synchronized(this) { int callingUid = Binder.getCallingUid(); 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() @@ -4217,7 +4327,7 @@ public final class ActivityManagerService extends ActivityManagerNative Slog.i(TAG_MU, "Getting intent sender for origCallingUid=" + Binder.getOrigCallingUid()); return getIntentSenderLocked(type, packageName, Binder.getOrigCallingUid(), - token, resultWho, requestCode, intents, resolvedTypes, flags); + token, resultWho, requestCode, intents, resolvedTypes, flags, options); } catch (RemoteException e) { throw new SecurityException(e); @@ -4227,11 +4337,12 @@ public final class ActivityManagerService extends ActivityManagerNative IIntentSender getIntentSenderLocked(int type, String packageName, int callingUid, IBinder token, String resultWho, - int requestCode, Intent[] intents, String[] resolvedTypes, int flags) { + int requestCode, Intent[] intents, String[] resolvedTypes, int flags, + Bundle options) { if (DEBUG_MU) Slog.v(TAG_MU, "getIntentSenderLocked(): uid=" + callingUid); ActivityRecord activity = null; - if (type == INTENT_SENDER_ACTIVITY_RESULT) { + if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) { activity = mMainStack.isInStackLocked(token); if (activity == null) { return null; @@ -4249,7 +4360,7 @@ public final class ActivityManagerService extends ActivityManagerNative PendingIntentRecord.Key key = new PendingIntentRecord.Key( type, packageName, activity, resultWho, - requestCode, intents, resolvedTypes, flags); + requestCode, intents, resolvedTypes, flags, options); WeakReference<PendingIntentRecord> ref; ref = mIntentSenderRecords.get(key); PendingIntentRecord rec = ref != null ? ref.get() : null; @@ -4278,7 +4389,7 @@ public final class ActivityManagerService extends ActivityManagerNative } rec = new PendingIntentRecord(this, key, callingUid); mIntentSenderRecords.put(key, rec.ref); - if (type == INTENT_SENDER_ACTIVITY_RESULT) { + if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) { if (activity.pendingResults == null) { activity.pendingResults = new HashSet<WeakReference<PendingIntentRecord>>(); @@ -4296,8 +4407,8 @@ public final class ActivityManagerService extends ActivityManagerNative PendingIntentRecord rec = (PendingIntentRecord)sender; try { int uid = AppGlobals.getPackageManager() - .getPackageUid(rec.key.packageName); - if (uid != Binder.getCallingUid()) { + .getPackageUid(rec.key.packageName, UserId.getCallingUserId()); + if (!UserId.isSameApp(uid, Binder.getCallingUid())) { String msg = "Permission Denial: cancelIntentSender() from pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() @@ -4333,6 +4444,17 @@ public final class ActivityManagerService extends ActivityManagerNative return null; } + public int getUidForIntentSender(IIntentSender sender) { + if (sender instanceof PendingIntentRecord) { + try { + PendingIntentRecord res = (PendingIntentRecord)sender; + return res.uid; + } catch (ClassCastException e) { + } + } + return -1; + } + public boolean isIntentSenderTargetedToPackage(IIntentSender pendingResult) { if (!(pendingResult instanceof PendingIntentRecord)) { return false; @@ -4543,76 +4665,91 @@ public final class ActivityManagerService extends ActivityManagerNative throw new SecurityException(msg); } - private final boolean checkHoldingPermissionsLocked(IPackageManager pm, - ProviderInfo pi, Uri uri, int uid, int modeFlags) { - boolean readPerm = (modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0; - boolean writePerm = (modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0; + /** + * Determine if UID is holding permissions required to access {@link Uri} in + * the given {@link ProviderInfo}. Final permission checking is always done + * in {@link ContentProvider}. + */ + private final boolean checkHoldingPermissionsLocked( + IPackageManager pm, ProviderInfo pi, Uri uri, int uid, int modeFlags) { if (DEBUG_URI_PERMISSION) Slog.v(TAG, "checkHoldingPermissionsLocked: uri=" + uri + " uid=" + uid); - try { - // Is the component private from the target uid? - final boolean prv = !pi.exported && pi.applicationInfo.uid != uid; - // Acceptable if the there is no read permission needed from the - // target or the target is holding the read permission. - if (!readPerm) { - if ((!prv && pi.readPermission == null) || - (pm.checkUidPermission(pi.readPermission, uid) - == PackageManager.PERMISSION_GRANTED)) { - readPerm = true; - } - } + if (pi.applicationInfo.uid == uid) { + return true; + } else if (!pi.exported) { + return false; + } - // Acceptable if the there is no write permission needed from the - // target or the target is holding the read permission. - if (!writePerm) { - if (!prv && (pi.writePermission == null) || - (pm.checkUidPermission(pi.writePermission, uid) - == PackageManager.PERMISSION_GRANTED)) { - writePerm = true; - } + boolean readMet = (modeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0; + boolean writeMet = (modeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0; + try { + // check if target holds top-level <provider> permissions + if (!readMet && pi.readPermission != null + && (pm.checkUidPermission(pi.readPermission, uid) == PERMISSION_GRANTED)) { + readMet = true; } + if (!writeMet && pi.writePermission != null + && (pm.checkUidPermission(pi.writePermission, uid) == PERMISSION_GRANTED)) { + writeMet = true; + } + + // track if unprotected read/write is allowed; any denied + // <path-permission> below removes this ability + boolean allowDefaultRead = pi.readPermission == null; + boolean allowDefaultWrite = pi.writePermission == null; - // Acceptable if there is a path permission matching the URI that - // the target holds the permission on. - PathPermission[] pps = pi.pathPermissions; - if (pps != null && (!readPerm || !writePerm)) { + // check if target holds any <path-permission> that match uri + final PathPermission[] pps = pi.pathPermissions; + if (pps != null) { final String path = uri.getPath(); int i = pps.length; - while (i > 0 && (!readPerm || !writePerm)) { + while (i > 0 && (!readMet || !writeMet)) { i--; PathPermission pp = pps[i]; - if (!readPerm) { - final String pprperm = pp.getReadPermission(); - if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Checking read perm for " - + pprperm + " for " + pp.getPath() - + ": match=" + pp.match(path) - + " check=" + pm.checkUidPermission(pprperm, uid)); - if (pprperm != null && pp.match(path) && - (pm.checkUidPermission(pprperm, uid) - == PackageManager.PERMISSION_GRANTED)) { - readPerm = true; + if (pp.match(path)) { + if (!readMet) { + final String pprperm = pp.getReadPermission(); + if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Checking read perm for " + + pprperm + " for " + pp.getPath() + + ": match=" + pp.match(path) + + " check=" + pm.checkUidPermission(pprperm, uid)); + if (pprperm != null) { + if (pm.checkUidPermission(pprperm, uid) == PERMISSION_GRANTED) { + readMet = true; + } else { + allowDefaultRead = false; + } + } } - } - if (!writePerm) { - final String ppwperm = pp.getWritePermission(); - if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Checking write perm " - + ppwperm + " for " + pp.getPath() - + ": match=" + pp.match(path) - + " check=" + pm.checkUidPermission(ppwperm, uid)); - if (ppwperm != null && pp.match(path) && - (pm.checkUidPermission(ppwperm, uid) - == PackageManager.PERMISSION_GRANTED)) { - writePerm = true; + if (!writeMet) { + final String ppwperm = pp.getWritePermission(); + if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Checking write perm " + + ppwperm + " for " + pp.getPath() + + ": match=" + pp.match(path) + + " check=" + pm.checkUidPermission(ppwperm, uid)); + if (ppwperm != null) { + if (pm.checkUidPermission(ppwperm, uid) == PERMISSION_GRANTED) { + writeMet = true; + } else { + allowDefaultWrite = false; + } + } } } } } + + // grant unprotected <provider> read/write, if not blocked by + // <path-permission> above + if (allowDefaultRead) readMet = true; + if (allowDefaultWrite) writeMet = true; + } catch (RemoteException e) { return false; } - return readPerm && writePerm; + return readMet && writeMet; } private final boolean checkUriPermissionLocked(Uri uri, int uid, @@ -4657,9 +4794,11 @@ public final class ActivityManagerService extends ActivityManagerNative * if callingUid is not allowed to do this. Returns the uid of the target * if the URI permission grant should be performed; returns -1 if it is not * needed (for example targetPkg already has permission to access the URI). + * If you already know the uid of the target, you can supply it in + * lastTargetUid else set that to -1. */ int checkGrantUriPermissionLocked(int callingUid, String targetPkg, - Uri uri, int modeFlags) { + Uri uri, int modeFlags, int lastTargetUid) { modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); if (modeFlags == 0) { @@ -4689,7 +4828,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) { } } @@ -4698,10 +4837,10 @@ public final class ActivityManagerService extends ActivityManagerNative return -1; } - int targetUid; - if (targetPkg != null) { + 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); @@ -4710,8 +4849,6 @@ public final class ActivityManagerService extends ActivityManagerNative } catch (RemoteException ex) { return -1; } - } else { - targetUid = -1; } if (targetUid >= 0) { @@ -4783,7 +4920,7 @@ public final class ActivityManagerService extends ActivityManagerNative Uri uri, int modeFlags) { enforceNotIsolatedCaller("checkGrantUriPermission"); synchronized(this) { - return checkGrantUriPermissionLocked(callingUid, targetPkg, uri, modeFlags); + return checkGrantUriPermissionLocked(callingUid, targetPkg, uri, modeFlags, -1); } } @@ -4830,13 +4967,13 @@ public final class ActivityManagerService extends ActivityManagerNative } } - void grantUriPermissionLocked(int callingUid, - String targetPkg, Uri uri, int modeFlags, UriPermissionOwner owner) { + void grantUriPermissionLocked(int callingUid, String targetPkg, Uri uri, + int modeFlags, UriPermissionOwner owner) { if (targetPkg == null) { throw new NullPointerException("targetPkg"); } - int targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, uri, modeFlags); + int targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, uri, modeFlags, -1); if (targetUid < 0) { return; } @@ -4844,13 +4981,26 @@ public final class ActivityManagerService extends ActivityManagerNative grantUriPermissionUncheckedLocked(targetUid, targetPkg, uri, modeFlags, owner); } + static class NeededUriGrants extends ArrayList<Uri> { + final String targetPkg; + final int targetUid; + final int flags; + + NeededUriGrants(String _targetPkg, int _targetUid, int _flags) { + targetPkg = _targetPkg; + targetUid = _targetUid; + flags = _flags; + } + } + /** * Like checkGrantUriPermissionLocked, but takes an Intent. */ - int checkGrantUriPermissionFromIntentLocked(int callingUid, - String targetPkg, Intent intent) { + NeededUriGrants checkGrantUriPermissionFromIntentLocked(int callingUid, + String targetPkg, Intent intent, int mode, NeededUriGrants needed) { if (DEBUG_URI_PERMISSION) Slog.v(TAG, - "Checking URI perm to " + (intent != null ? intent.getData() : null) + "Checking URI perm to data=" + (intent != null ? intent.getData() : null) + + " clip=" + (intent != null ? intent.getClipData() : null) + " from " + intent + "; flags=0x" + Integer.toHexString(intent != null ? intent.getFlags() : 0)); @@ -4859,33 +5009,74 @@ public final class ActivityManagerService extends ActivityManagerNative } if (intent == null) { - return -1; + return null; } Uri data = intent.getData(); - if (data == null) { - return -1; + ClipData clip = intent.getClipData(); + if (data == null && clip == null) { + return null; + } + if (data != null) { + int target = checkGrantUriPermissionLocked(callingUid, targetPkg, data, + mode, needed != null ? needed.targetUid : -1); + if (target > 0) { + if (needed == null) { + needed = new NeededUriGrants(targetPkg, target, mode); + } + needed.add(data); + } + } + if (clip != null) { + for (int i=0; i<clip.getItemCount(); i++) { + Uri uri = clip.getItemAt(i).getUri(); + if (uri != null) { + int target = -1; + target = checkGrantUriPermissionLocked(callingUid, targetPkg, uri, + mode, needed != null ? needed.targetUid : -1); + if (target > 0) { + if (needed == null) { + needed = new NeededUriGrants(targetPkg, target, mode); + } + needed.add(uri); + } + } else { + Intent clipIntent = clip.getItemAt(i).getIntent(); + if (clipIntent != null) { + NeededUriGrants newNeeded = checkGrantUriPermissionFromIntentLocked( + callingUid, targetPkg, clipIntent, mode, needed); + if (newNeeded != null) { + needed = newNeeded; + } + } + } + } } - return checkGrantUriPermissionLocked(callingUid, targetPkg, data, - intent.getFlags()); + + return needed; } /** * Like grantUriPermissionUncheckedLocked, but takes an Intent. */ - void grantUriPermissionUncheckedFromIntentLocked(int targetUid, - String targetPkg, Intent intent, UriPermissionOwner owner) { - grantUriPermissionUncheckedLocked(targetUid, targetPkg, intent.getData(), - intent.getFlags(), owner); + void grantUriPermissionUncheckedFromIntentLocked(NeededUriGrants needed, + UriPermissionOwner owner) { + if (needed != null) { + for (int i=0; i<needed.size(); i++) { + grantUriPermissionUncheckedLocked(needed.targetUid, needed.targetPkg, + needed.get(i), needed.flags, owner); + } + } } void grantUriPermissionFromIntentLocked(int callingUid, String targetPkg, Intent intent, UriPermissionOwner owner) { - int targetUid = checkGrantUriPermissionFromIntentLocked(callingUid, targetPkg, intent); - if (targetUid < 0) { + NeededUriGrants needed = checkGrantUriPermissionFromIntentLocked(callingUid, targetPkg, + intent, intent != null ? intent.getFlags() : 0, null); + if (needed == null) { return; } - grantUriPermissionUncheckedFromIntentLocked(targetUid, targetPkg, intent, owner); + grantUriPermissionUncheckedFromIntentLocked(needed, owner); } public void grantUriPermission(IApplicationThread caller, String targetPkg, @@ -4941,14 +5132,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) { } } @@ -5043,7 +5234,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) { } } @@ -5321,12 +5512,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; } } @@ -5372,15 +5564,16 @@ public final class ActivityManagerService extends ActivityManagerNative "removeSubTask()"); long ident = Binder.clearCallingIdentity(); try { - return mMainStack.removeTaskActivitiesLocked(taskId, subTaskIndex) != null; + return mMainStack.removeTaskActivitiesLocked(taskId, subTaskIndex, + true) != null; } finally { Binder.restoreCallingIdentity(ident); } } } - private void cleanUpRemovedTaskLocked(ActivityRecord root, boolean killProcesses) { - TaskRecord tr = root.task; + private void cleanUpRemovedTaskLocked(TaskRecord tr, int flags) { + final boolean killProcesses = (flags&ActivityManager.REMOVE_TASK_KILL_PROCESS) != 0; Intent baseIntent = new Intent( tr.intent != null ? tr.intent : tr.affinityIntent); ComponentName component = baseIntent.getComponent(); @@ -5391,7 +5584,7 @@ public final class ActivityManagerService extends ActivityManagerNative // Find any running services associated with this app. ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>(); - for (ServiceRecord sr : mServiceMap.getAllServices(root.userId)) { + for (ServiceRecord sr : mServiceMap.getAllServices(tr.userId)) { if (sr.packageName.equals(component.getPackageName())) { services.add(sr); } @@ -5406,7 +5599,7 @@ public final class ActivityManagerService extends ActivityManagerNative stopServiceLocked(sr); } else { sr.pendingStarts.add(new ServiceRecord.StartItem(sr, true, - sr.makeNextStartId(), baseIntent, -1)); + sr.makeNextStartId(), baseIntent, null)); if (sr.app != null && sr.app.thread != null) { sendServiceArgsLocked(sr, false); } @@ -5446,11 +5639,11 @@ public final class ActivityManagerService extends ActivityManagerNative "removeTask()"); long ident = Binder.clearCallingIdentity(); try { - ActivityRecord r = mMainStack.removeTaskActivitiesLocked(taskId, -1); + ActivityRecord r = mMainStack.removeTaskActivitiesLocked(taskId, -1, + false); if (r != null) { mRecentTasks.remove(r.task); - cleanUpRemovedTaskLocked(r, - (flags&ActivityManager.REMOVE_TASK_KILL_PROCESS) != 0); + cleanUpRemovedTaskLocked(r.task, flags); return true; } else { TaskRecord tr = null; @@ -5468,6 +5661,8 @@ public final class ActivityManagerService extends ActivityManagerNative // Caller is just removing a recent task that is // not actively running. That is easy! mRecentTasks.remove(i); + cleanUpRemovedTaskLocked(tr, flags); + return true; } else { Slog.w(TAG, "removeTask: task " + taskId + " does not have activities to remove, " @@ -5523,13 +5718,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(); @@ -5544,7 +5740,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--) { @@ -5558,13 +5754,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); } } @@ -5765,6 +5962,11 @@ public final class ActivityManagerService extends ActivityManagerNative return providers; } + /** + * Check if {@link ProcessRecord} has a possible chance at accessing the + * given {@link ProviderInfo}. Final permission checking is always done + * in {@link ContentProvider}. + */ private final String checkContentProviderPermissionLocked( ProviderInfo cpi, ProcessRecord r) { final int callingPid = (r != null) ? r.pid : Binder.getCallingPid(); @@ -5965,15 +6167,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) { @@ -5990,7 +6191,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 { @@ -5998,13 +6199,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. @@ -6045,7 +6246,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 " @@ -6379,7 +6580,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 " @@ -6611,12 +6812,25 @@ 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); } } } + void setOpenGlTraceApp(ApplicationInfo app, String processName) { + synchronized (this) { + boolean isDebuggable = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0")); + if (!isDebuggable) { + if ((app.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) { + throw new SecurityException("Process not debuggable: " + app.packageName); + } + } + + mOpenGlTraceApp = processName; + } + } + void setProfileApp(ApplicationInfo app, String processName, String profileFile, ParcelFileDescriptor profileFd, boolean autoStopProfiler) { synchronized (this) { @@ -6813,7 +7027,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) { @@ -6957,7 +7207,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) { @@ -7214,6 +7464,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; @@ -7261,7 +7515,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 " @@ -7623,7 +7877,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) { @@ -7952,6 +8206,22 @@ public final class ActivityManagerService extends ActivityManagerNative } } + private void fillInProcMemInfo(ProcessRecord app, + ActivityManager.RunningAppProcessInfo outInfo) { + outInfo.pid = app.pid; + outInfo.uid = app.info.uid; + if (mHeavyWeightProcess == app) { + outInfo.flags |= ActivityManager.RunningAppProcessInfo.FLAG_CANT_SAVE_STATE; + } + if (app.persistent) { + outInfo.flags |= ActivityManager.RunningAppProcessInfo.FLAG_PERSISTENT; + } + outInfo.lastTrimLevel = app.trimMemoryLevel; + int adj = app.curAdj; + outInfo.importance = oomAdjToImportance(adj, outInfo); + outInfo.importanceReasonCode = app.adjTypeCode; + } + public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() { enforceNotIsolatedCaller("getRunningAppProcesses"); // Lazy instantiation of list @@ -7965,16 +8235,7 @@ public final class ActivityManagerService extends ActivityManagerNative ActivityManager.RunningAppProcessInfo currApp = new ActivityManager.RunningAppProcessInfo(app.processName, app.pid, app.getPackageList()); - currApp.uid = app.info.uid; - if (mHeavyWeightProcess == app) { - currApp.flags |= ActivityManager.RunningAppProcessInfo.FLAG_CANT_SAVE_STATE; - } - if (app.persistent) { - currApp.flags |= ActivityManager.RunningAppProcessInfo.FLAG_PERSISTENT; - } - int adj = app.curAdj; - currApp.importance = oomAdjToImportance(adj, currApp); - currApp.importanceReasonCode = app.adjTypeCode; + fillInProcMemInfo(app, currApp); if (app.adjSource instanceof ProcessRecord) { currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid; currApp.importanceReasonImportance = oomAdjToImportance( @@ -8014,7 +8275,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); } @@ -8026,6 +8287,18 @@ public final class ActivityManagerService extends ActivityManagerNative } @Override + public void getMyMemoryState(ActivityManager.RunningAppProcessInfo outInfo) { + enforceNotIsolatedCaller("getMyMemoryState"); + synchronized (this) { + ProcessRecord proc; + synchronized (mPidsSelfLocked) { + proc = mPidsSelfLocked.get(Binder.getCallingPid()); + } + fillInProcMemInfo(proc, outInfo); + } + } + + @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (checkCallingPermission(android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) { @@ -8479,8 +8752,8 @@ public final class ActivityManagerService extends ActivityManagerNative pw.print(" Process "); pw.print(pname); pw.print(" uid "); pw.print(puid); pw.print(": last crashed "); - pw.print((now-uids.valueAt(i))); - pw.println(" ms ago"); + TimeUtils.formatDuration(now-uids.valueAt(i), pw); + pw.println(" ago"); } } } @@ -8552,6 +8825,9 @@ public final class ActivityManagerService extends ActivityManagerNative + " mDebugTransient=" + mDebugTransient + " mOrigWaitForDebugger=" + mOrigWaitForDebugger); } + if (mOpenGlTraceApp != null) { + pw.println(" mOpenGlTraceApp=" + mOpenGlTraceApp); + } if (mProfileApp != null || mProfileProc != null || mProfileFile != null || mProfileFd != null) { pw.println(" mProfileApp=" + mProfileApp + " mProfileProc=" + mProfileProc); @@ -9025,7 +9301,7 @@ public final class ActivityManagerService extends ActivityManagerNative for (int i=0; i<N; i++) { sb.setLength(0); sb.append(" Intent: "); - intents.get(i).toShortString(sb, false, true, false); + intents.get(i).toShortString(sb, false, true, false, false); pw.println(sb.toString()); Bundle bundle = intents.get(i).getExtras(); if (bundle != null) { @@ -9110,7 +9386,7 @@ public final class ActivityManagerService extends ActivityManagerNative ConnectionRecord conn = clist.get(i); pw.print(" "); pw.print(conn.binding.intent.intent.getIntent() - .toShortString(false, false, false)); + .toShortString(false, false, false, false)); pw.print(" -> "); ProcessRecord proc = conn.binding.client; pw.println(proc != null ? proc.toShortString() : "null"); @@ -9249,7 +9525,7 @@ public final class ActivityManagerService extends ActivityManagerNative boolean dumpProvidersLocked(FileDescriptor fd, PrintWriter pw, String[] args, int opti, boolean dumpAll, String dumpPackage) { - boolean needSep = false; + boolean needSep = true; ItemMatcher matcher = new ItemMatcher(); matcher.build(args, opti); @@ -9361,7 +9637,7 @@ public final class ActivityManagerService extends ActivityManagerNative // Complete + brief == give a summary. Isn't that obvious?!? if (lastTask.intent != null) { pw.print(prefix); pw.print(" "); - pw.println(lastTask.intent.toInsecureString()); + pw.println(lastTask.intent.toInsecureStringWithClip()); } } } @@ -9997,6 +10273,29 @@ public final class ActivityManagerService extends ActivityManagerNative } pw.println(); pw.print("Total PSS: "); pw.print(totalPss); pw.println(" kB"); + final int[] SINGLE_LONG_FORMAT = new int[] { + Process.PROC_SPACE_TERM|Process.PROC_OUT_LONG + }; + long[] longOut = new long[1]; + Process.readProcFile("/sys/kernel/mm/ksm/pages_shared", + SINGLE_LONG_FORMAT, null, longOut, null); + long shared = longOut[0] * ProcessList.PAGE_SIZE / 1024; + longOut[0] = 0; + Process.readProcFile("/sys/kernel/mm/ksm/pages_sharing", + SINGLE_LONG_FORMAT, null, longOut, null); + long sharing = longOut[0] * ProcessList.PAGE_SIZE / 1024; + longOut[0] = 0; + Process.readProcFile("/sys/kernel/mm/ksm/pages_unshared", + SINGLE_LONG_FORMAT, null, longOut, null); + long unshared = longOut[0] * ProcessList.PAGE_SIZE / 1024; + longOut[0] = 0; + Process.readProcFile("/sys/kernel/mm/ksm/pages_volatile", + SINGLE_LONG_FORMAT, null, longOut, null); + long voltile = longOut[0] * ProcessList.PAGE_SIZE / 1024; + pw.print(" KSM: "); pw.print(sharing); pw.print(" kB saved from shared "); + pw.print(shared); pw.println(" kB"); + pw.print(" "); pw.print(unshared); pw.print(" kB unshared; "); + pw.print(voltile); pw.println(" kB volatile"); } } @@ -10480,21 +10779,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) { @@ -10565,7 +10864,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) { @@ -10673,9 +10972,9 @@ public final class ActivityManagerService extends ActivityManagerNative si.deliveredTime = SystemClock.uptimeMillis(); r.deliveredStarts.add(si); si.deliveryCount++; - if (si.targetPermissionUid >= 0 && si.intent != null) { - grantUriPermissionUncheckedFromIntentLocked(si.targetPermissionUid, - r.packageName, si.intent, si.getUriPermissionsLocked()); + if (si.neededGrants != null) { + grantUriPermissionUncheckedFromIntentLocked(si.neededGrants, + si.getUriPermissionsLocked()); } bumpServiceExecutingLocked(r, "start"); if (!oomAdjusted) { @@ -10753,7 +11052,7 @@ public final class ActivityManagerService extends ActivityManagerNative boolean created = false; try { mStringBuilder.setLength(0); - r.intent.getIntent().toShortString(mStringBuilder, true, false, true); + r.intent.getIntent().toShortString(mStringBuilder, true, false, true, false); EventLog.writeEvent(EventLogTags.AM_CREATE_SERVICE, System.identityHashCode(r), r.shortName, mStringBuilder.toString(), r.app.pid); @@ -10779,7 +11078,7 @@ public final class ActivityManagerService extends ActivityManagerNative // be called. if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) { r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(), - null, -1)); + null, null)); } sendServiceArgsLocked(r, true); @@ -10930,7 +11229,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 " @@ -11151,15 +11450,15 @@ public final class ActivityManagerService extends ActivityManagerNative ? res.permission : "private to package"); } ServiceRecord r = res.record; - int targetPermissionUid = checkGrantUriPermissionFromIntentLocked( - callingUid, r.packageName, service); + NeededUriGrants neededGrants = checkGrantUriPermissionFromIntentLocked( + callingUid, r.packageName, service, service.getFlags(), null); if (unscheduleServiceRestartLocked(r)) { if (DEBUG_SERVICE) Slog.v(TAG, "START SERVICE WHILE RESTART PENDING: " + r); } r.startRequested = true; r.callStart = false; r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(), - service, targetPermissionUid)); + service, neededGrants)); r.lastActivity = SystemClock.uptimeMillis(); synchronized (r.stats.getBatteryStats()) { r.stats.startRunningLocked(); @@ -11235,7 +11534,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(); @@ -11263,7 +11563,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 @@ -11892,7 +12193,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 " @@ -12221,7 +12522,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!"); } @@ -12256,7 +12557,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); @@ -12267,7 +12568,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, @@ -12334,7 +12636,7 @@ public final class ActivityManagerService extends ActivityManagerNative } } catch (RemoteException e) { Slog.w(TAG, "Remote exception", e); - return BROADCAST_SUCCESS; + return ActivityManager.BROADCAST_SUCCESS; } } @@ -12352,7 +12654,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (requiredPermission != null) { Slog.w(TAG, "Can't broadcast sticky intent " + intent + " and enforce permission " + requiredPermission); - return BROADCAST_STICKY_CANT_HAVE_PERMISSION; + return ActivityManager.BROADCAST_STICKY_CANT_HAVE_PERMISSION; } if (intent.getComponent() != null) { throw new SecurityException( @@ -12384,7 +12686,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(); @@ -12392,15 +12694,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. @@ -12526,7 +12828,7 @@ public final class ActivityManagerService extends ActivityManagerNative } } - return BROADCAST_SUCCESS; + return ActivityManager.BROADCAST_SUCCESS; } final Intent verifyBroadcastLocked(Intent intent) { @@ -12691,7 +12993,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) { @@ -12719,9 +13021,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; @@ -12776,11 +13079,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"); @@ -13010,6 +13314,102 @@ public final class ActivityManagerService extends ActivityManagerNative } } + @Override + public boolean targetTaskAffinityMatchesActivity(IBinder token, String destAffinity) { + ActivityRecord srec = ActivityRecord.forToken(token); + return srec.task.affinity != null && srec.task.affinity.equals(destAffinity); + } + + public boolean navigateUpTo(IBinder token, Intent destIntent, int resultCode, + Intent resultData) { + ComponentName dest = destIntent.getComponent(); + + synchronized (this) { + ActivityRecord srec = ActivityRecord.forToken(token); + ArrayList<ActivityRecord> history = srec.stack.mHistory; + final int start = history.indexOf(srec); + if (start < 0) { + // Current activity is not in history stack; do nothing. + return false; + } + int finishTo = start - 1; + ActivityRecord parent = null; + boolean foundParentInTask = false; + if (dest != null) { + TaskRecord tr = srec.task; + for (int i = start - 1; i >= 0; i--) { + ActivityRecord r = history.get(i); + if (tr != r.task) { + // Couldn't find parent in the same task; stop at the one above this. + // (Root of current task; in-app "home" behavior) + // Always at least finish the current activity. + finishTo = Math.min(start - 1, i + 1); + parent = history.get(finishTo); + break; + } else if (r.info.packageName.equals(dest.getPackageName()) && + r.info.name.equals(dest.getClassName())) { + finishTo = i; + parent = r; + foundParentInTask = true; + break; + } + } + } + + if (mController != null) { + ActivityRecord next = mMainStack.topRunningActivityLocked(token, 0); + if (next != null) { + // ask watcher if this is allowed + boolean resumeOK = true; + try { + resumeOK = mController.activityResuming(next.packageName); + } catch (RemoteException e) { + mController = null; + } + + if (!resumeOK) { + return false; + } + } + } + final long origId = Binder.clearCallingIdentity(); + for (int i = start; i > finishTo; i--) { + ActivityRecord r = history.get(i); + mMainStack.requestFinishActivityLocked(r.appToken, resultCode, resultData, + "navigate-up"); + // Only return the supplied result for the first activity finished + resultCode = Activity.RESULT_CANCELED; + resultData = null; + } + + if (parent != null && foundParentInTask) { + final int parentLaunchMode = parent.info.launchMode; + final int destIntentFlags = destIntent.getFlags(); + if (parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE || + parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TASK || + parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TOP || + (destIntentFlags & Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) { + parent.deliverNewIntentLocked(srec.app.uid, destIntent); + } else { + try { + ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo( + destIntent.getComponent(), 0, UserId.getCallingUserId()); + int res = mMainStack.startActivityLocked(srec.app.thread, destIntent, + null, aInfo, parent.appToken, null, + 0, -1, parent.launchedFromUid, 0, null, true, null); + foundParentInTask = res == ActivityManager.START_SUCCESS; + } catch (RemoteException e) { + foundParentInTask = false; + } + mMainStack.requestFinishActivityLocked(parent.appToken, resultCode, + resultData, "navigate-up"); + } + } + Binder.restoreCallingIdentity(origId); + return foundParentInTask; + } + } + // ========================================================= // LIFETIME MANAGEMENT // ========================================================= @@ -13982,6 +14382,14 @@ public final class ActivityManagerService extends ActivityManagerNative if (mPreviousProcess != null) minFactor++; if (factor < minFactor) factor = minFactor; step = 0; + int fgTrimLevel; + if (numHidden <= (ProcessList.MAX_HIDDEN_APPS/5)) { + fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL; + } else if (numHidden <= (ProcessList.MAX_HIDDEN_APPS/3)) { + fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW; + } else { + fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE; + } int curLevel = ComponentCallbacks2.TRIM_MEMORY_COMPLETE; for (i=0; i<N; i++) { ProcessRecord app = mLruProcesses.get(i); @@ -14008,6 +14416,7 @@ public final class ActivityManagerService extends ActivityManagerNative app.trimMemoryLevel = curLevel; step++; if (step >= factor) { + step = 0; switch (curLevel) { case ComponentCallbacks2.TRIM_MEMORY_COMPLETE: curLevel = ComponentCallbacks2.TRIM_MEMORY_MODERATE; @@ -14027,20 +14436,28 @@ public final class ActivityManagerService extends ActivityManagerNative } } app.trimMemoryLevel = ComponentCallbacks2.TRIM_MEMORY_BACKGROUND; - } else if ((app.curAdj > ProcessList.VISIBLE_APP_ADJ || app.systemNoUi) - && app.pendingUiClean) { - if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN - && app.thread != null) { + } else { + if ((app.curAdj > ProcessList.VISIBLE_APP_ADJ || app.systemNoUi) + && app.pendingUiClean) { + // If this application is now in the background and it + // had done UI, then give it the special trim level to + // have it free UI resources. + final int level = ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN; + if (app.trimMemoryLevel < level && app.thread != null) { + try { + app.thread.scheduleTrimMemory(level); + } catch (RemoteException e) { + } + } + app.pendingUiClean = false; + } + if (app.trimMemoryLevel < fgTrimLevel && app.thread != null) { try { - app.thread.scheduleTrimMemory( - ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN); + app.thread.scheduleTrimMemory(fgTrimLevel); } catch (RemoteException e) { } } - app.trimMemoryLevel = ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN; - app.pendingUiClean = false; - } else { - app.trimMemoryLevel = 0; + app.trimMemoryLevel = fgTrimLevel; } } } else { @@ -14057,11 +14474,9 @@ public final class ActivityManagerService extends ActivityManagerNative } catch (RemoteException e) { } } - app.trimMemoryLevel = ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN; app.pendingUiClean = false; - } else { - app.trimMemoryLevel = 0; } + app.trimMemoryLevel = 0; } } @@ -14327,25 +14742,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(); @@ -14356,8 +14752,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. @@ -14374,23 +14768,54 @@ 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; + @Override + public UserInfo getCurrentUser() throws RemoteException { + final int callingUid = Binder.getCallingUid(); + if (callingUid != 0 && callingUid != Process.myUid()) { + Slog.e(TAG, "Trying to get user from unauthorized app"); + return null; + } + return AppGlobals.getPackageManager().getUser(mCurrentUserId); + } + + 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 cdab6c6..a098f18 100644 --- a/services/java/com/android/server/am/ActivityRecord.java +++ b/services/java/com/android/server/am/ActivityRecord.java @@ -16,16 +16,17 @@ package com.android.server.am; +import com.android.internal.app.ResolverActivity; import com.android.server.AttributeCache; import com.android.server.am.ActivityStack.ActivityState; import android.app.Activity; +import android.app.ActivityOptions; import android.content.ComponentName; 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; @@ -85,6 +86,8 @@ final class ActivityRecord { long startTime; // last time this activity was started long lastVisibleTime; // last time this activity became visible long cpuTimeAtResume; // the cpu time of host process at the time of resuming activity + long pauseTime; // last time we started pausing the activity + long launchTickTime; // base time for launch tick messages Configuration configuration; // configuration activity was last running in CompatibilityInfo compat;// last used compatibility mode ActivityRecord resultTo; // who started this entry, so will get our reply @@ -93,6 +96,7 @@ final class ActivityRecord { ArrayList results; // pending ActivityResult objs we have received HashSet<WeakReference<PendingIntentRecord>> pendingResults; // all pending intents for this act ArrayList newIntents; // any pending new intents for single-top mode + ActivityOptions pendingOptions; // most recently given options HashSet<ConnectionRecord> connections; // All ConnectionRecord we hold UriPermissionOwner uriPermissions; // current special URI access perms. ProcessRecord app; // if non-null, hosting application @@ -127,26 +131,27 @@ final class ActivityRecord { pw.print(prefix); pw.print("packageName="); pw.print(packageName); pw.print(" processName="); pw.println(processName); pw.print(prefix); pw.print("launchedFromUid="); pw.print(launchedFromUid); - pw.print(prefix); pw.print("userId="); pw.print(userId); - pw.print(" app="); pw.println(app); - pw.print(prefix); pw.println(intent.toInsecureString()); + pw.print(" userId="); pw.println(userId); + pw.print(prefix); pw.print("app="); pw.println(app); + pw.print(prefix); pw.println(intent.toInsecureStringWithClip()); pw.print(prefix); pw.print("frontOfTask="); pw.print(frontOfTask); pw.print(" task="); pw.println(task); pw.print(prefix); pw.print("taskAffinity="); pw.println(taskAffinity); pw.print(prefix); pw.print("realActivity="); pw.println(realActivity.flattenToShortString()); - pw.print(prefix); pw.print("base="); pw.print(baseDir); - if (!resDir.equals(baseDir)) pw.print(" res="); pw.print(resDir); - pw.print(" data="); pw.println(dataDir); - pw.print(prefix); pw.print("labelRes=0x"); - pw.print(Integer.toHexString(labelRes)); - pw.print(" icon=0x"); pw.print(Integer.toHexString(icon)); - pw.print(" theme=0x"); pw.println(Integer.toHexString(theme)); + pw.print(prefix); pw.print("baseDir="); pw.println(baseDir); + if (!resDir.equals(baseDir)) { + pw.print(prefix); pw.print("resDir="); pw.println(resDir); + } + pw.print(prefix); pw.print("dataDir="); pw.println(dataDir); pw.print(prefix); pw.print("stateNotNeeded="); pw.print(stateNotNeeded); pw.print(" componentSpecified="); pw.print(componentSpecified); pw.print(" isHomeActivity="); pw.println(isHomeActivity); + pw.print(prefix); pw.print("compat="); pw.print(compat); + pw.print(" labelRes=0x"); pw.print(Integer.toHexString(labelRes)); + pw.print(" icon=0x"); pw.print(Integer.toHexString(icon)); + pw.print(" theme=0x"); pw.println(Integer.toHexString(theme)); pw.print(prefix); pw.print("config="); pw.println(configuration); - pw.print(prefix); pw.print("compat="); pw.println(compat); if (resultTo != null || resultWho != null) { pw.print(prefix); pw.print("resultTo="); pw.print(resultTo); pw.print(" resultWho="); pw.print(resultWho); @@ -193,13 +198,11 @@ final class ActivityRecord { TimeUtils.formatDuration(launchTime, pw); pw.print(" startTime="); TimeUtils.formatDuration(startTime, pw); pw.println(""); } - if (lastVisibleTime != 0) { - pw.print(prefix); pw.print("lastVisibleTime="); - TimeUtils.formatDuration(lastVisibleTime, pw); pw.println(""); - } - if (waitingVisible || nowVisible) { + if (lastVisibleTime != 0 || waitingVisible || nowVisible) { pw.print(prefix); pw.print("waitingVisible="); pw.print(waitingVisible); - pw.print(" nowVisible="); pw.println(nowVisible); + pw.print(" nowVisible="); pw.print(nowVisible); + pw.print("lastVisibleTime="); + TimeUtils.formatDuration(lastVisibleTime, pw); pw.println(""); } if (configDestroy || configChangeFlags != 0) { pw.print(prefix); pw.print("configDestroy="); pw.print(configDestroy); @@ -380,7 +383,7 @@ final class ActivityRecord { _intent.getData() == null && _intent.getType() == null && (intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 && - !"android".equals(realActivity.getClassName())) { + !ResolverActivity.class.getName().equals(realActivity.getClassName())) { // This sure looks like a home activity! // Note the last check is so we don't count the resolver // activity as being home... really, we don't care about @@ -537,6 +540,42 @@ final class ActivityRecord { } } + void updateOptionsLocked(Bundle options) { + if (options != null) { + if (pendingOptions != null) { + pendingOptions.abort(); + } + pendingOptions = new ActivityOptions(options); + } + } + + void applyOptionsLocked() { + if (pendingOptions != null) { + 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() { + if (pendingOptions != null) { + pendingOptions.abort(); + pendingOptions = null; + } + } + void removeUriPermissionsLocked() { if (uriPermissions != null) { uriPermissions.removeUriPermissionsLocked(); @@ -577,6 +616,32 @@ final class ActivityRecord { } } + void startLaunchTickingLocked() { + if (ActivityManagerService.IS_USER_BUILD) { + return; + } + if (launchTickTime == 0) { + launchTickTime = SystemClock.uptimeMillis(); + continueLaunchTickingLocked(); + } + } + + boolean continueLaunchTickingLocked() { + if (launchTickTime != 0) { + Message msg = stack.mHandler.obtainMessage(ActivityStack.LAUNCH_TICK_MSG); + msg.obj = this; + stack.mHandler.removeMessages(ActivityStack.LAUNCH_TICK_MSG); + stack.mHandler.sendMessageDelayed(msg, ActivityStack.LAUNCH_TICK); + return true; + } + return false; + } + + void finishLaunchTickingLocked() { + launchTickTime = 0; + stack.mHandler.removeMessages(ActivityStack.LAUNCH_TICK_MSG); + } + // IApplicationToken public boolean mayFreezeScreenLocked(ProcessRecord app) { @@ -632,6 +697,7 @@ final class ActivityRecord { stack.mInitialStartTime = 0; } startTime = 0; + finishLaunchTickingLocked(); } } diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index f9641eb..a01ed25 100644 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -22,18 +22,10 @@ import com.android.server.am.ActivityManagerService.PendingActivityLaunch; import android.app.Activity; import android.app.ActivityManager; +import android.app.ActivityOptions; import android.app.AppGlobals; import android.app.IActivityManager; import android.app.IThumbnailRetriever; -import static android.app.IActivityManager.START_CLASS_NOT_FOUND; -import static android.app.IActivityManager.START_DELIVERED_TO_TOP; -import static android.app.IActivityManager.START_FORWARD_AND_REQUEST_CONFLICT; -import static android.app.IActivityManager.START_INTENT_NOT_RESOLVED; -import static android.app.IActivityManager.START_PERMISSION_DENIED; -import static android.app.IActivityManager.START_RETURN_INTENT_TO_CALLER; -import static android.app.IActivityManager.START_SUCCESS; -import static android.app.IActivityManager.START_SWITCHES_CANCELED; -import static android.app.IActivityManager.START_TASK_TO_FRONT; import android.app.IApplicationThread; import android.app.PendingIntent; import android.app.ResultInfo; @@ -96,7 +88,10 @@ final class ActivityStack { // How long we wait until giving up on the last activity telling us it // is idle. static final int IDLE_TIMEOUT = 10*1000; - + + // Ticks during which we check progress while waiting for an app to launch. + static final int LAUNCH_TICK = 500; + // How long we wait until giving up on the last activity to pause. This // is short because it directly impacts the responsiveness of starting the // next activity. @@ -284,6 +279,7 @@ final class ActivityStack { static final int LAUNCH_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 4; static final int DESTROY_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 5; static final int RESUME_TOP_ACTIVITY_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 6; + static final int LAUNCH_TICK_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 7; final Handler mHandler = new Handler() { //public Handler() { @@ -306,6 +302,13 @@ final class ActivityStack { // We don't at this point know if the activity is fullscreen, // so we need to be conservative and assume it isn't. Slog.w(TAG, "Activity pause timeout for " + r); + synchronized (mService) { + if (r.app != null) { + mService.logAppTooSlow(r.app, r.pauseTime, + "pausing " + r); + } + } + activityPaused(r != null ? r.appToken : null, true); } break; case IDLE_TIMEOUT_MSG: { @@ -322,6 +325,15 @@ final class ActivityStack { Slog.w(TAG, "Activity idle timeout for " + r); activityIdleInternal(r != null ? r.appToken : null, true, null); } break; + case LAUNCH_TICK_MSG: { + ActivityRecord r = (ActivityRecord)msg.obj; + synchronized (mService) { + if (r.continueLaunchTickingLocked()) { + mService.logAppTooSlow(r.app, r.launchTickTime, + "launching " + r); + } + } + } break; case DESTROY_TIMEOUT_MSG: { ActivityRecord r = (ActivityRecord)msg.obj; // We don't at this point know if the activity is fullscreen, @@ -563,6 +575,9 @@ final class ActivityStack { r.startFreezingScreenLocked(app, 0); mService.mWindowManager.setAppVisibility(r.appToken, true); + // schedule launch ticks to collect information about slow apps. + r.startLaunchTickingLocked(); + // Have the window manager re-evaluate the orientation of // the screen based on the new activity order. Note that // as a result of this, it can call back into the activity @@ -945,6 +960,7 @@ final class ActivityStack { // responsiveness seen by the user. Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG); msg.obj = prev; + prev.pauseTime = SystemClock.uptimeMillis(); mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT); if (DEBUG_PAUSE) Slog.v(TAG, "Waiting for pause to complete..."); } else { @@ -1429,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 " @@ -1441,6 +1456,7 @@ final class ActivityStack { // We are starting up the next activity, so tell the window manager // that the previous one will be hidden soon. This way it can know // to ignore it when computing the desired screen orientation. + boolean noAnim = false; if (prev != null) { if (prev.finishing) { if (DEBUG_TRANSITION) Slog.v(TAG, @@ -1459,6 +1475,7 @@ final class ActivityStack { if (DEBUG_TRANSITION) Slog.v(TAG, "Prepare open transition: prev=" + prev); if (mNoAnimActivities.contains(next)) { + noAnim = true; mService.mWindowManager.prepareAppTransition( WindowManagerPolicy.TRANSIT_NONE, false); } else { @@ -1475,6 +1492,7 @@ final class ActivityStack { if (DEBUG_TRANSITION) Slog.v(TAG, "Prepare open transition: no previous"); if (mNoAnimActivities.contains(next)) { + noAnim = true; mService.mWindowManager.prepareAppTransition( WindowManagerPolicy.TRANSIT_NONE, false); } else { @@ -1482,6 +1500,11 @@ final class ActivityStack { WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN, false); } } + if (!noAnim) { + next.applyOptionsLocked(); + } else { + next.clearOptionsLocked(); + } if (next.app != null && next.app.thread != null) { if (DEBUG_SWITCH) Slog.v(TAG, "Resume running: " + next); @@ -1489,6 +1512,9 @@ final class ActivityStack { // This activity is now becoming visible. mService.mWindowManager.setAppVisibility(next.appToken, true); + // schedule launch ticks to collect information about slow apps. + next.startLaunchTickingLocked(); + ActivityRecord lastResumedActivity = mResumedActivity; ActivityState lastState = next.state; @@ -1637,7 +1663,7 @@ final class ActivityStack { } private final void startActivityLocked(ActivityRecord r, boolean newTask, - boolean doResume, boolean keepCurTransition) { + boolean doResume, boolean keepCurTransition, Bundle options) { final int NH = mHistory.size(); int addPos = -1; @@ -1669,6 +1695,7 @@ final class ActivityStack { if (VALIDATE_TOKENS) { validateAppTokensLocked(); } + ActivityOptions.abort(options); return; } break; @@ -1730,6 +1757,7 @@ final class ActivityStack { : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN, keepCurTransition); mNoAnimActivities.remove(r); } + r.updateOptionsLocked(options); mService.mWindowManager.addAppToken( addPos, r.appToken, r.task.taskId, r.info.screenOrientation, r.fullscreen); boolean doShow = true; @@ -1770,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(); @@ -1821,6 +1850,10 @@ final class ActivityStack { if (below != null && below.finishing) { continue; } + // Don't check any lower in the stack if we're crossing a user boundary. + if (below != null && below.userId != taskTop.userId) { + break; + } if (target == null) { target = below; targetI = i; @@ -2266,14 +2299,12 @@ final class ActivityStack { } final int startActivityLocked(IApplicationThread caller, - Intent intent, String resolvedType, - Uri[] grantedUriPermissions, - int grantedMode, ActivityInfo aInfo, IBinder resultTo, + Intent intent, String resolvedType, ActivityInfo aInfo, IBinder resultTo, String resultWho, int requestCode, - int callingPid, int callingUid, boolean onlyIfNeeded, + int callingPid, int callingUid, int startFlags, Bundle options, boolean componentSpecified, ActivityRecord[] outActivity) { - int err = START_SUCCESS; + int err = ActivityManager.START_SUCCESS; ProcessRecord callerApp = null; if (caller != null) { @@ -2285,13 +2316,13 @@ final class ActivityStack { Slog.w(TAG, "Unable to find app for caller " + caller + " (pid=" + callingPid + ") when starting: " + intent.toString()); - err = START_PERMISSION_DENIED; + err = ActivityManager.START_PERMISSION_DENIED; } } - if (err == START_SUCCESS) { - Slog.i(TAG, "START {" + intent.toShortString(true, true, true) + "} from pid " - + (callerApp != null ? callerApp.pid : callingPid)); + if (err == ActivityManager.START_SUCCESS) { + Slog.i(TAG, "START {" + intent.toShortString(true, true, true, false) + + "} from pid " + (callerApp != null ? callerApp.pid : callingPid)); } ActivityRecord sourceRecord = null; @@ -2315,7 +2346,8 @@ final class ActivityStack { // Transfer the result target from the source activity to the new // one being started, including any failures. if (requestCode >= 0) { - return START_FORWARD_AND_REQUEST_CONFLICT; + ActivityOptions.abort(options); + return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT; } resultRecord = sourceRecord.resultTo; resultWho = sourceRecord.resultWho; @@ -2327,25 +2359,26 @@ final class ActivityStack { } } - if (err == START_SUCCESS && intent.getComponent() == null) { + if (err == ActivityManager.START_SUCCESS && intent.getComponent() == null) { // We couldn't find a class that can handle the given Intent. // That's the end of that! - err = START_INTENT_NOT_RESOLVED; + err = ActivityManager.START_INTENT_NOT_RESOLVED; } - if (err == START_SUCCESS && aInfo == null) { + if (err == ActivityManager.START_SUCCESS && aInfo == null) { // We couldn't find the specific class specified in the Intent. // Also the end of the line. - err = START_CLASS_NOT_FOUND; + err = ActivityManager.START_CLASS_NOT_FOUND; } - if (err != START_SUCCESS) { + if (err != ActivityManager.START_SUCCESS) { if (resultRecord != null) { sendActivityResultLocked(-1, resultRecord, resultWho, requestCode, Activity.RESULT_CANCELED, null); } mDismissKeyguardOnNextActivity = false; + ActivityOptions.abort(options); return err; } @@ -2396,7 +2429,8 @@ final class ActivityStack { // We pretend to the caller that it was really started, but // they will just get a cancel result. mDismissKeyguardOnNextActivity = false; - return START_SUCCESS; + ActivityOptions.abort(options); + return ActivityManager.START_SUCCESS; } } } @@ -2415,12 +2449,11 @@ final class ActivityStack { PendingActivityLaunch pal = new PendingActivityLaunch(); pal.r = r; pal.sourceRecord = sourceRecord; - pal.grantedUriPermissions = grantedUriPermissions; - pal.grantedMode = grantedMode; - pal.onlyIfNeeded = onlyIfNeeded; + pal.startFlags = startFlags; mService.mPendingActivityLaunches.add(pal); mDismissKeyguardOnNextActivity = false; - return START_SWITCHES_CANCELED; + ActivityOptions.abort(options); + return ActivityManager.START_SWITCHES_CANCELED; } } @@ -2439,7 +2472,7 @@ final class ActivityStack { } err = startActivityUncheckedLocked(r, sourceRecord, - grantedUriPermissions, grantedMode, onlyIfNeeded, true); + startFlags, true, options); if (mDismissKeyguardOnNextActivity && mPausingActivity == null) { // Someone asked to have the keyguard dismissed on the next // activity start, but we are not actually doing an activity @@ -2462,8 +2495,8 @@ final class ActivityStack { } final int startActivityUncheckedLocked(ActivityRecord r, - ActivityRecord sourceRecord, Uri[] grantedUriPermissions, - int grantedMode, boolean onlyIfNeeded, boolean doResume) { + ActivityRecord sourceRecord, int startFlags, boolean doResume, + Bundle options) { final Intent intent = r.intent; final int callingUid = r.launchedFromUid; final int userId = r.userId; @@ -2490,14 +2523,14 @@ final class ActivityStack { // being launched is the same as the one making the call... or, as // a special case, if we do not know the caller then we count the // current top activity as the caller. - if (onlyIfNeeded) { + if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) { ActivityRecord checkedCaller = sourceRecord; if (checkedCaller == null) { checkedCaller = topRunningNonDelayedActivityLocked(notTop); } if (!checkedCaller.realActivity.equals(r.realActivity)) { // Caller is not the same as launcher, so always needed. - onlyIfNeeded = false; + startFlags &= ~ActivityManager.START_FLAG_ONLY_IF_NEEDED; } } @@ -2574,7 +2607,7 @@ final class ActivityStack { // We really do want to push this one into the // user's face, right now. moveHomeToFrontFromLaunchLocked(launchFlags); - moveTaskToFrontLocked(taskTop.task, r); + moveTaskToFrontLocked(taskTop.task, r, options); } } // If the caller has requested that the target task be @@ -2582,7 +2615,7 @@ final class ActivityStack { if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) { taskTop = resetTaskIfNeededLocked(taskTop, r); } - if (onlyIfNeeded) { + 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 // is the case, so this is it! And for paranoia, make @@ -2590,7 +2623,8 @@ final class ActivityStack { if (doResume) { resumeTopActivityLocked(null); } - return START_RETURN_INTENT_TO_CALLER; + ActivityOptions.abort(options); + return ActivityManager.START_RETURN_INTENT_TO_CALLER; } if ((launchFlags & (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK)) @@ -2677,7 +2711,8 @@ final class ActivityStack { if (doResume) { resumeTopActivityLocked(null); } - return START_TASK_TO_FRONT; + ActivityOptions.abort(options); + return ActivityManager.START_TASK_TO_FRONT; } } } @@ -2706,14 +2741,15 @@ final class ActivityStack { if (doResume) { resumeTopActivityLocked(null); } - if (onlyIfNeeded) { + 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 // is the case, so this is it! - return START_RETURN_INTENT_TO_CALLER; + return ActivityManager.START_RETURN_INTENT_TO_CALLER; } top.deliverNewIntentLocked(callingUid, r.intent); - return START_DELIVERED_TO_TOP; + return ActivityManager.START_DELIVERED_TO_TOP; } } } @@ -2725,7 +2761,8 @@ final class ActivityStack { r.resultTo, r.resultWho, r.requestCode, Activity.RESULT_CANCELED, null); } - return START_CLASS_NOT_FOUND; + ActivityOptions.abort(options); + return ActivityManager.START_CLASS_NOT_FOUND; } boolean newTask = false; @@ -2766,7 +2803,8 @@ final class ActivityStack { if (doResume) { resumeTopActivityLocked(null); } - return START_DELIVERED_TO_TOP; + ActivityOptions.abort(options); + return ActivityManager.START_DELIVERED_TO_TOP; } } else if (!addingToTask && (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) { @@ -2777,11 +2815,12 @@ final class ActivityStack { if (where >= 0) { ActivityRecord top = moveActivityToFrontLocked(where); logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task); + top.updateOptionsLocked(options); top.deliverNewIntentLocked(callingUid, r.intent); if (doResume) { resumeTopActivityLocked(null); } - return START_DELIVERED_TO_TOP; + return ActivityManager.START_DELIVERED_TO_TOP; } } // An existing activity is starting this new activity, so we want @@ -2805,13 +2844,6 @@ final class ActivityStack { + " in new guessed " + r.task); } - if (grantedUriPermissions != null && callingUid > 0) { - for (int i=0; i<grantedUriPermissions.length; i++) { - mService.grantUriPermissionLocked(callingUid, r.packageName, - grantedUriPermissions[i], grantedMode, r.getUriPermissionsLocked()); - } - } - mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName, intent, r.getUriPermissionsLocked()); @@ -2819,12 +2851,12 @@ final class ActivityStack { EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.task.taskId); } logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task); - startActivityLocked(r, newTask, doResume, keepCurTransition); - return START_SUCCESS; + startActivityLocked(r, newTask, doResume, keepCurTransition, options); + return ActivityManager.START_SUCCESS; } - ActivityInfo resolveActivity(Intent intent, String resolvedType, boolean debug, - String profileFile, ParcelFileDescriptor profileFd, boolean autoStopProfiler) { + ActivityInfo resolveActivity(Intent intent, String resolvedType, int startFlags, + String profileFile, ParcelFileDescriptor profileFd, int userId) { // Collect information about the target of the Intent. ActivityInfo aInfo; try { @@ -2832,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; @@ -2847,16 +2879,23 @@ final class ActivityStack { aInfo.applicationInfo.packageName, aInfo.name)); // Don't debug things in the system process - if (debug) { + if ((startFlags&ActivityManager.START_FLAG_DEBUG) != 0) { if (!aInfo.processName.equals("system")) { mService.setDebugApp(aInfo.processName, true, false); } } + if ((startFlags&ActivityManager.START_FLAG_OPENGL_TRACES) != 0) { + if (!aInfo.processName.equals("system")) { + mService.setOpenGlTraceApp(aInfo.applicationInfo, aInfo.processName); + } + } + if (profileFile != null) { if (!aInfo.processName.equals("system")) { mService.setProfileApp(aInfo.applicationInfo, aInfo.processName, - profileFile, profileFd, autoStopProfiler); + profileFile, profileFd, + (startFlags&ActivityManager.START_FLAG_AUTO_STOP_PROFILER) != 0); } } } @@ -2864,12 +2903,10 @@ final class ActivityStack { } final int startActivityMayWait(IApplicationThread caller, int callingUid, - Intent intent, String resolvedType, Uri[] grantedUriPermissions, - int grantedMode, IBinder resultTo, - String resultWho, int requestCode, boolean onlyIfNeeded, - boolean debug, String profileFile, ParcelFileDescriptor profileFd, - boolean autoStopProfiler, - WaitResult outResult, Configuration config, int userId) { + Intent intent, String resolvedType, IBinder resultTo, + String resultWho, int requestCode, int startFlags, String profileFile, + ParcelFileDescriptor profileFd, WaitResult outResult, Configuration config, + Bundle options, int userId) { // Refuse possible leaked file descriptors if (intent != null && intent.hasFileDescriptors()) { throw new IllegalArgumentException("File descriptors passed in Intent"); @@ -2880,8 +2917,8 @@ final class ActivityStack { intent = new Intent(intent); // Collect information about the target of the Intent. - ActivityInfo aInfo = resolveActivity(intent, resolvedType, debug, - profileFile, profileFd, autoStopProfiler); + ActivityInfo aInfo = resolveActivity(intent, resolvedType, startFlags, + profileFile, profileFd, userId); aInfo = mService.getActivityInfoForUser(aInfo, userId); synchronized (mService) { @@ -2921,15 +2958,16 @@ final class ActivityStack { Slog.w(TAG, "Unable to find app for caller " + caller + " (pid=" + realCallingPid + ") when starting: " + intent.toString()); - return START_PERMISSION_DENIED; + ActivityOptions.abort(options); + return ActivityManager.START_PERMISSION_DENIED; } } IIntentSender target = mService.getIntentSenderLocked( - IActivityManager.INTENT_SENDER_ACTIVITY, "android", + ActivityManager.INTENT_SENDER_ACTIVITY, "android", realCallingUid, null, null, 0, new Intent[] { intent }, new String[] { resolvedType }, PendingIntent.FLAG_CANCEL_CURRENT - | PendingIntent.FLAG_ONE_SHOT); + | PendingIntent.FLAG_ONE_SHOT, null); Intent newIntent = new Intent(); if (requestCode >= 0) { @@ -2961,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) { @@ -2972,9 +3010,8 @@ final class ActivityStack { } int res = startActivityLocked(caller, intent, resolvedType, - grantedUriPermissions, grantedMode, aInfo, - resultTo, resultWho, requestCode, callingPid, callingUid, - onlyIfNeeded, componentSpecified, null); + aInfo, resultTo, resultWho, requestCode, callingPid, callingUid, + startFlags, options, componentSpecified, null); if (mConfigWillChange && mMainStack) { // If the caller also wants to switch to a new configuration, @@ -2993,7 +3030,7 @@ final class ActivityStack { if (outResult != null) { outResult.result = res; - if (res == IActivityManager.START_SUCCESS) { + if (res == ActivityManager.START_SUCCESS) { mWaitingActivityLaunched.add(outResult); do { try { @@ -3001,7 +3038,7 @@ final class ActivityStack { } catch (InterruptedException e) { } } while (!outResult.timeout && outResult.who == null); - } else if (res == IActivityManager.START_TASK_TO_FRONT) { + } else if (res == ActivityManager.START_TASK_TO_FRONT) { ActivityRecord r = this.topRunningActivityLocked(null); if (r.nowVisible) { outResult.timeout = false; @@ -3026,8 +3063,8 @@ final class ActivityStack { } final int startActivities(IApplicationThread caller, int callingUid, - Intent[] intents, - String[] resolvedTypes, IBinder resultTo, int userId) { + Intent[] intents, String[] resolvedTypes, IBinder resultTo, + Bundle options, int userId) { if (intents == null) { throw new NullPointerException("intents is null"); } @@ -3070,8 +3107,8 @@ final class ActivityStack { intent = new Intent(intent); // Collect information about the target of the Intent. - ActivityInfo aInfo = resolveActivity(intent, resolvedTypes[i], false, - null, null, false); + ActivityInfo aInfo = resolveActivity(intent, resolvedTypes[i], + 0, null, null, userId); // TODO: New, check if this is correct aInfo = mService.getActivityInfoForUser(aInfo, userId); @@ -3081,9 +3118,15 @@ final class ActivityStack { "FLAG_CANT_SAVE_STATE not supported here"); } + Bundle theseOptions; + if (options != null && i == intents.length-1) { + theseOptions = options; + } else { + theseOptions = null; + } int res = startActivityLocked(caller, intent, resolvedTypes[i], - null, 0, aInfo, resultTo, null, -1, callingPid, callingUid, - false, componentSpecified, outActivity); + aInfo, resultTo, null, -1, callingPid, callingUid, + 0, theseOptions, componentSpecified, outActivity); if (res < 0) { return res; } @@ -3095,7 +3138,7 @@ final class ActivityStack { Binder.restoreCallingIdentity(origId); } - return IActivityManager.START_SUCCESS; + return ActivityManager.START_SUCCESS; } void reportActivityLaunchedLocked(boolean timeout, ActivityRecord r, @@ -3270,6 +3313,7 @@ final class ActivityStack { ActivityRecord r = ActivityRecord.forToken(token); if (r != null) { mHandler.removeMessages(IDLE_TIMEOUT_MSG, r); + r.finishLaunchTickingLocked(); } // Get the activity record. @@ -3447,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; @@ -3488,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, @@ -3640,6 +3696,7 @@ final class ActivityStack { mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r); mHandler.removeMessages(IDLE_TIMEOUT_MSG, r); mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r); + r.finishLaunchTickingLocked(); } final void removeActivityFromHistoryLocked(ActivityRecord r) { @@ -3853,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; @@ -3866,6 +3923,7 @@ final class ActivityStack { if (top < 0 || (mHistory.get(top)).task.taskId == task) { // nothing to do! + ActivityOptions.abort(options); return; } @@ -3907,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); } @@ -4024,10 +4091,13 @@ final class ActivityStack { return info; } - public ActivityRecord removeTaskActivitiesLocked(int taskId, int subTaskIndex) { + public ActivityRecord removeTaskActivitiesLocked(int taskId, int subTaskIndex, + boolean taskRequired) { TaskAccessInfo info = getTaskAccessInfoLocked(taskId, false); if (info.root == null) { - Slog.w(TAG, "removeTaskLocked: unknown taskId " + taskId); + if (taskRequired) { + Slog.w(TAG, "removeTaskLocked: unknown taskId " + taskId); + } return null; } @@ -4038,7 +4108,9 @@ final class ActivityStack { } if (subTaskIndex >= info.subtasks.size()) { - Slog.w(TAG, "removeTaskLocked: unknown subTaskIndex " + subTaskIndex); + if (taskRequired) { + Slog.w(TAG, "removeTaskLocked: unknown subTaskIndex " + subTaskIndex); + } return null; } 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/am/ContentProviderRecord.java b/services/java/com/android/server/am/ContentProviderRecord.java index f338cfc..608b09a 100644 --- a/services/java/com/android/server/am/ContentProviderRecord.java +++ b/services/java/com/android/server/am/ContentProviderRecord.java @@ -157,7 +157,7 @@ class ContentProviderRecord extends ContentProviderHolder { sb.append("ContentProviderRecord{"); sb.append(Integer.toHexString(System.identityHashCode(this))); sb.append(' '); - sb.append(info.name); + sb.append(name.flattenToShortString()); sb.append('}'); return stringName = sb.toString(); } diff --git a/services/java/com/android/server/am/IntentBindRecord.java b/services/java/com/android/server/am/IntentBindRecord.java index 2618c77..c94f714 100644 --- a/services/java/com/android/server/am/IntentBindRecord.java +++ b/services/java/com/android/server/am/IntentBindRecord.java @@ -54,7 +54,7 @@ class IntentBindRecord { void dumpInService(PrintWriter pw, String prefix) { pw.print(prefix); pw.print("intent={"); - pw.print(intent.getIntent().toShortString(false, true, false)); + pw.print(intent.getIntent().toShortString(false, true, false, false)); pw.println('}'); pw.print(prefix); pw.print("binder="); pw.println(binder); pw.print(prefix); pw.print("requested="); pw.print(requested); @@ -89,7 +89,7 @@ class IntentBindRecord { sb.append(service.shortName); sb.append(':'); if (intent != null) { - intent.getIntent().toShortString(sb, false, false, false); + intent.getIntent().toShortString(sb, false, false, false, false); } sb.append('}'); return stringName = sb.toString(); diff --git a/services/java/com/android/server/am/PendingIntentRecord.java b/services/java/com/android/server/am/PendingIntentRecord.java index 3b6a97c..ad15da1 100644 --- a/services/java/com/android/server/am/PendingIntentRecord.java +++ b/services/java/com/android/server/am/PendingIntentRecord.java @@ -16,12 +16,13 @@ package com.android.server.am; -import android.app.IActivityManager; +import android.app.ActivityManager; import android.content.IIntentSender; import android.content.IIntentReceiver; import android.app.PendingIntent; import android.content.Intent; import android.os.Binder; +import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.os.UserId; @@ -48,6 +49,7 @@ class PendingIntentRecord extends IIntentSender.Stub { final int requestCode; final Intent requestIntent; final String requestResolvedType; + final Bundle options; Intent[] allIntents; String[] allResolvedTypes; final int flags; @@ -56,7 +58,7 @@ class PendingIntentRecord extends IIntentSender.Stub { private static final int ODD_PRIME_NUMBER = 37; Key(int _t, String _p, ActivityRecord _a, String _w, - int _r, Intent[] _i, String[] _it, int _f) { + int _r, Intent[] _i, String[] _it, int _f, Bundle _o) { type = _t; packageName = _p; activity = _a; @@ -67,6 +69,7 @@ class PendingIntentRecord extends IIntentSender.Stub { allIntents = _i; allResolvedTypes = _it; flags = _f; + options = _o; int hash = 23; hash = (ODD_PRIME_NUMBER*hash) + _f; @@ -152,19 +155,19 @@ class PendingIntentRecord extends IIntentSender.Stub { return "Key{" + typeName() + " pkg=" + packageName + " intent=" + (requestIntent != null - ? requestIntent.toShortString(false, true, false) : "<null>") + ? requestIntent.toShortString(false, true, false, false) : "<null>") + " flags=0x" + Integer.toHexString(flags) + "}"; } String typeName() { switch (type) { - case IActivityManager.INTENT_SENDER_ACTIVITY: + case ActivityManager.INTENT_SENDER_ACTIVITY: return "startActivity"; - case IActivityManager.INTENT_SENDER_BROADCAST: + case ActivityManager.INTENT_SENDER_BROADCAST: return "broadcastIntent"; - case IActivityManager.INTENT_SENDER_SERVICE: + case ActivityManager.INTENT_SENDER_SERVICE: return "startService"; - case IActivityManager.INTENT_SENDER_ACTIVITY_RESULT: + case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT: return "activityResult"; } return Integer.toString(type); @@ -181,13 +184,13 @@ class PendingIntentRecord extends IIntentSender.Stub { public int send(int code, Intent intent, String resolvedType, IIntentReceiver finishedReceiver, String requiredPermission) { return sendInner(code, intent, resolvedType, finishedReceiver, - requiredPermission, null, null, 0, 0, 0); + requiredPermission, null, null, 0, 0, 0, null); } int sendInner(int code, Intent intent, String resolvedType, IIntentReceiver finishedReceiver, String requiredPermission, IBinder resultTo, String resultWho, int requestCode, - int flagsMask, int flagsValues) { + int flagsMask, int flagsValues, Bundle options) { synchronized(owner) { if (!canceled) { sent = true; @@ -213,7 +216,14 @@ class PendingIntentRecord extends IIntentSender.Stub { boolean sendFinish = finishedReceiver != null; switch (key.type) { - case IActivityManager.INTENT_SENDER_ACTIVITY: + case ActivityManager.INTENT_SENDER_ACTIVITY: + if (options == null) { + options = key.options; + } else if (key.options != null) { + Bundle opts = new Bundle(key.options); + opts.putAll(options); + options = opts; + } try { if (key.allIntents != null && key.allIntents.length > 1) { Intent[] allIntents = new Intent[key.allIntents.length]; @@ -227,22 +237,22 @@ class PendingIntentRecord extends IIntentSender.Stub { allIntents[allIntents.length-1] = finalIntent; allResolvedTypes[allResolvedTypes.length-1] = resolvedType; owner.startActivitiesInPackage(uid, allIntents, - allResolvedTypes, resultTo); + allResolvedTypes, resultTo, options); } else { owner.startActivityInPackage(uid, finalIntent, resolvedType, - resultTo, resultWho, requestCode, false); + resultTo, resultWho, requestCode, 0, options); } } catch (RuntimeException e) { Slog.w(ActivityManagerService.TAG, "Unable to send startActivity intent", e); } break; - case IActivityManager.INTENT_SENDER_ACTIVITY_RESULT: + case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT: key.activity.stack.sendActivityResultLocked(-1, key.activity, key.who, key.requestCode, code, finalIntent); break; - case IActivityManager.INTENT_SENDER_BROADCAST: + case ActivityManager.INTENT_SENDER_BROADCAST: try { // If a completion callback has been requested, require // that the broadcast be delivered synchronously @@ -257,7 +267,7 @@ class PendingIntentRecord extends IIntentSender.Stub { "Unable to send startActivity intent", e); } break; - case IActivityManager.INTENT_SENDER_SERVICE: + case ActivityManager.INTENT_SENDER_SERVICE: try { owner.startServiceInPackage(uid, finalIntent, resolvedType); @@ -281,7 +291,7 @@ class PendingIntentRecord extends IIntentSender.Stub { return 0; } } - return IActivityManager.START_CANCELED; + return ActivityManager.START_CANCELED; } protected void finalize() throws Throwable { @@ -320,7 +330,7 @@ class PendingIntentRecord extends IIntentSender.Stub { } if (key.requestIntent != null) { pw.print(prefix); pw.print("requestIntent="); - pw.println(key.requestIntent.toShortString(false, true, true)); + pw.println(key.requestIntent.toShortString(false, true, true, true)); } if (sent || canceled) { pw.print(prefix); pw.print("sent="); pw.print(sent); diff --git a/services/java/com/android/server/am/ProviderMap.java b/services/java/com/android/server/am/ProviderMap.java index 2021e0d..ccc928f 100644 --- a/services/java/com/android/server/am/ProviderMap.java +++ b/services/java/com/android/server/am/ProviderMap.java @@ -183,16 +183,20 @@ public class ProviderMap { r.dump(pw, " "); } else { pw.print(" * "); - pw.print(r.name.toShortString()); - /* - if (r.app != null) { - pw.println(":"); - pw.print(" "); - pw.println(r.app); - } else { - pw.println(); + pw.println(r); + if (r.proc != null) { + pw.print(" proc="); + pw.println(r.proc); + } + if (r.launchingApp != null) { + pw.print(" launchingApp="); + pw.println(r.launchingApp); + } + if (r.clients.size() > 0 || r.externalProcessNoHandleCount > 0) { + pw.print(" "); pw.print(r.clients.size()); + pw.print(" clients, "); pw.print(r.externalProcessNoHandleCount); + pw.println(" external handles"); } - */ } } } @@ -217,7 +221,7 @@ public class ProviderMap { pw.println(" "); pw.println(" Published content providers (by class):"); dumpProvidersByClassLocked(pw, dumpAll, mGlobalByClass); - pw.println(" "); + pw.println(""); } if (mProvidersByClassPerUser.size() > 1) { diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java index daa3653..828eef7 100644 --- a/services/java/com/android/server/am/ServiceRecord.java +++ b/services/java/com/android/server/am/ServiceRecord.java @@ -106,7 +106,7 @@ class ServiceRecord extends Binder { final boolean taskRemoved; final int id; final Intent intent; - final int targetPermissionUid; + final ActivityManagerService.NeededUriGrants neededGrants; long deliveredTime; int deliveryCount; int doneExecutingCount; @@ -115,12 +115,12 @@ class ServiceRecord extends Binder { String stringName; // caching of toString StartItem(ServiceRecord _sr, boolean _taskRemoved, int _id, Intent _intent, - int _targetPermissionUid) { + ActivityManagerService.NeededUriGrants _neededGrants) { sr = _sr; taskRemoved = _taskRemoved; id = _id; intent = _intent; - targetPermissionUid = _targetPermissionUid; + neededGrants = _neededGrants; } UriPermissionOwner getUriPermissionsLocked() { @@ -177,9 +177,9 @@ class ServiceRecord extends Binder { pw.print(prefix); pw.print(" intent="); if (si.intent != null) pw.println(si.intent.toString()); else pw.println("null"); - if (si.targetPermissionUid >= 0) { - pw.print(prefix); pw.print(" targetPermissionUid="); - pw.println(si.targetPermissionUid); + if (si.neededGrants != null) { + pw.print(prefix); pw.print(" neededGrants="); + pw.println(si.neededGrants); } if (si.uriPermissions != null) { if (si.uriPermissions.readUriPermissions != null) { @@ -196,7 +196,7 @@ class ServiceRecord extends Binder { void dump(PrintWriter pw, String prefix) { pw.print(prefix); pw.print("intent={"); - pw.print(intent.getIntent().toShortString(false, true, false)); + pw.print(intent.getIntent().toShortString(false, true, false, true)); pw.println('}'); pw.print(prefix); pw.print("packageName="); pw.println(packageName); pw.print(prefix); pw.print("processName="); pw.println(processName); diff --git a/services/java/com/android/server/am/TaskRecord.java b/services/java/com/android/server/am/TaskRecord.java index 47ec218..e3ebcc6 100644 --- a/services/java/com/android/server/am/TaskRecord.java +++ b/services/java/com/android/server/am/TaskRecord.java @@ -39,7 +39,7 @@ class TaskRecord extends ThumbnailHolder { boolean askedCompatMode;// Have asked the user about compat mode for this task. String stringName; // caching of toString() result. - int userId; // user for which this task was created + int userId; // user for which this task was created TaskRecord(int _taskId, ActivityInfo info, Intent _intent) { taskId = _taskId; @@ -111,14 +111,14 @@ class TaskRecord extends ThumbnailHolder { if (intent != null) { StringBuilder sb = new StringBuilder(128); sb.append(prefix); sb.append("intent={"); - intent.toShortString(sb, false, true, false); + intent.toShortString(sb, false, true, false, true); sb.append('}'); pw.println(sb.toString()); } if (affinityIntent != null) { StringBuilder sb = new StringBuilder(128); sb.append(prefix); sb.append("affinityIntent={"); - affinityIntent.toShortString(sb, false, true, false); + affinityIntent.toShortString(sb, false, true, false, true); sb.append('}'); pw.println(sb.toString()); } diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java index 9573fda..88a0ccb 100644 --- a/services/java/com/android/server/connectivity/Tethering.java +++ b/services/java/com/android/server/connectivity/Tethering.java @@ -1215,6 +1215,8 @@ public class Tethering extends INetworkManagementEventObserver.Stub { return retValue; } protected boolean turnOffUpstreamMobileConnection() { + // ignore pending renewal requests + ++mCurrentConnectionSequence; if (mMobileApnReserved != ConnectivityManager.TYPE_NONE) { try { mConnService.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, @@ -1304,6 +1306,14 @@ public class Tethering extends INetworkManagementEventObserver.Stub { if (upType == ConnectivityManager.TYPE_MOBILE_DUN || upType == ConnectivityManager.TYPE_MOBILE_HIPRI) { turnOnUpstreamMobileConnection(upType); + } else if (upType != ConnectivityManager.TYPE_NONE) { + /* If we've found an active upstream connection that's not DUN/HIPRI + * we should stop any outstanding DUN/HIPRI start requests. + * + * If we found NONE we don't want to do this as we want any previous + * requests to keep trying to bring up something we can use. + */ + turnOffUpstreamMobileConnection(); } if (upType == ConnectivityManager.TYPE_NONE) { diff --git a/services/java/com/android/server/wm/InputApplicationHandle.java b/services/java/com/android/server/input/InputApplicationHandle.java index 1812f11..42c1052 100644 --- a/services/java/com/android/server/wm/InputApplicationHandle.java +++ b/services/java/com/android/server/input/InputApplicationHandle.java @@ -14,8 +14,7 @@ * limitations under the License. */ -package com.android.server.wm; - +package com.android.server.input; /** * Functions as a handle for an application that can receive input. @@ -30,7 +29,7 @@ public final class InputApplicationHandle { private int ptr; // The window manager's application window token. - public final AppWindowToken appWindowToken; + public final Object appWindowToken; // Application name. public String name; @@ -40,7 +39,7 @@ public final class InputApplicationHandle { private native void nativeDispose(); - public InputApplicationHandle(AppWindowToken appWindowToken) { + public InputApplicationHandle(Object appWindowToken) { this.appWindowToken = appWindowToken; } diff --git a/services/java/com/android/server/wm/InputFilter.java b/services/java/com/android/server/input/InputFilter.java index 8f0001a..2ce0a02 100644 --- a/services/java/com/android/server/wm/InputFilter.java +++ b/services/java/com/android/server/input/InputFilter.java @@ -14,7 +14,9 @@ * limitations under the License. */ -package com.android.server.wm; +package com.android.server.input; + +import com.android.server.wm.WindowManagerService; import android.os.Handler; import android.os.Looper; @@ -33,7 +35,7 @@ import android.view.WindowManagerPolicy; * system's behavior changes as follows: * <ul> * <li>Input events are first delivered to the {@link WindowManagerPolicy} - * interception methods before queueing as usual. This critical step takes care of managing + * interception methods before queuing as usual. This critical step takes care of managing * the power state of the device and handling wake keys.</li> * <li>Input events are then asynchronously delivered to the input filter's * {@link #onInputEvent(InputEvent)} method instead of being enqueued for dispatch to @@ -79,7 +81,7 @@ import android.view.WindowManagerPolicy; * {@link WindowManagerPolicy#FLAG_PASS_TO_USER} policy flag. The input filter may * sometimes receive events that do not have this flag set. It should take note of * the fact that the policy intends to drop the event, clean up its state, and - * then send appropriate cancelation events to the dispatcher if needed. + * then send appropriate cancellation events to the dispatcher if needed. * </p><p> * For example, suppose the input filter is processing a gesture and one of the touch events * it receives does not have the {@link WindowManagerPolicy#FLAG_PASS_TO_USER} flag set. @@ -89,8 +91,8 @@ import android.view.WindowManagerPolicy; * Corollary: Events that set sent to the dispatcher should usually include the * {@link WindowManagerPolicy#FLAG_PASS_TO_USER} flag. Otherwise, they will be dropped! * </p><p> - * It may be prudent to disable automatic key repeating for synthetically generated - * keys by setting the {@link WindowManagerPolicy#FLAG_DISABLE_KEY_REPEAT} policy flag. + * It may be prudent to disable automatic key repeating for synthetic key events + * by setting the {@link WindowManagerPolicy#FLAG_DISABLE_KEY_REPEAT} policy flag. * </p> */ public abstract class InputFilter { diff --git a/services/java/com/android/server/wm/InputManager.java b/services/java/com/android/server/input/InputManagerService.java index 56c3519..b8cc65e 100644 --- a/services/java/com/android/server/wm/InputManager.java +++ b/services/java/com/android/server/input/InputManagerService.java @@ -14,10 +14,12 @@ * limitations under the License. */ -package com.android.server.wm; +package com.android.server.input; import com.android.internal.util.XmlUtils; import com.android.server.Watchdog; +import com.android.server.input.InputFilter.Host; +import com.android.server.wm.WindowManagerService; import org.xmlpull.v1.XmlPullParser; @@ -25,9 +27,14 @@ import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.database.ContentObserver; +import android.hardware.input.IInputManager; +import android.hardware.input.InputManager; +import android.os.Binder; import android.os.Environment; +import android.os.Handler; import android.os.Looper; import android.os.MessageQueue; +import android.os.Process; import android.os.SystemProperties; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; @@ -44,6 +51,7 @@ import android.view.WindowManager; import android.view.WindowManagerPolicy; import java.io.File; +import java.io.FileDescriptor; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; @@ -53,62 +61,65 @@ import java.util.ArrayList; /* * Wraps the C++ InputManager and provides its callbacks. */ -public class InputManager implements Watchdog.Monitor { +public class InputManagerService extends IInputManager.Stub implements Watchdog.Monitor { static final String TAG = "InputManager"; - - private static final boolean DEBUG = false; + static final boolean DEBUG = false; + + private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml"; + + // Pointer to native input manager service object. + private final int mPtr; - private final Callbacks mCallbacks; private final Context mContext; - private final WindowManagerService mWindowManagerService; - - private static native void nativeInit(Context context, - Callbacks callbacks, MessageQueue messageQueue); - private static native void nativeStart(); - private static native void nativeSetDisplaySize(int displayId, int width, int height, - int externalWidth, int externalHeight); - private static native void nativeSetDisplayOrientation(int displayId, int rotation); + private final Callbacks mCallbacks; + private final Handler mHandler; + + private static native int nativeInit(InputManagerService service, + Context context, MessageQueue messageQueue); + private static native void nativeStart(int ptr); + private static native void nativeSetDisplaySize(int ptr, int displayId, + int width, int height, int externalWidth, int externalHeight); + private static native void nativeSetDisplayOrientation(int ptr, int displayId, int rotation); - private static native int nativeGetScanCodeState(int deviceId, int sourceMask, - int scanCode); - private static native int nativeGetKeyCodeState(int deviceId, int sourceMask, - int keyCode); - private static native int nativeGetSwitchState(int deviceId, int sourceMask, - int sw); - private static native boolean nativeHasKeys(int deviceId, int sourceMask, - int[] keyCodes, boolean[] keyExists); - private static native void nativeRegisterInputChannel(InputChannel inputChannel, + private static native int nativeGetScanCodeState(int ptr, + int deviceId, int sourceMask, int scanCode); + private static native int nativeGetKeyCodeState(int ptr, + int deviceId, int sourceMask, int keyCode); + private static native int nativeGetSwitchState(int ptr, + int deviceId, int sourceMask, int sw); + private static native boolean nativeHasKeys(int ptr, + int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists); + private static native void nativeRegisterInputChannel(int ptr, InputChannel inputChannel, InputWindowHandle inputWindowHandle, boolean monitor); - private static native void nativeUnregisterInputChannel(InputChannel inputChannel); - private static native void nativeSetInputFilterEnabled(boolean enable); - private static native int nativeInjectInputEvent(InputEvent event, + private static native void nativeUnregisterInputChannel(int ptr, InputChannel inputChannel); + private static native void nativeSetInputFilterEnabled(int ptr, boolean enable); + private static native int nativeInjectInputEvent(int ptr, InputEvent event, int injectorPid, int injectorUid, int syncMode, int timeoutMillis, int policyFlags); - private static native void nativeSetInputWindows(InputWindowHandle[] windowHandles); - private static native void nativeSetInputDispatchMode(boolean enabled, boolean frozen); - private static native void nativeSetSystemUiVisibility(int visibility); - private static native void nativeSetFocusedApplication(InputApplicationHandle application); - private static native InputDevice nativeGetInputDevice(int deviceId); - private static native void nativeGetInputConfiguration(Configuration configuration); - private static native int[] nativeGetInputDeviceIds(); - private static native boolean nativeTransferTouchFocus(InputChannel fromChannel, - InputChannel toChannel); - private static native void nativeSetPointerSpeed(int speed); - private static native void nativeSetShowTouches(boolean enabled); - private static native String nativeDump(); - private static native void nativeMonitor(); - + private static native void nativeSetInputWindows(int ptr, InputWindowHandle[] windowHandles); + private static native void nativeSetInputDispatchMode(int ptr, boolean enabled, boolean frozen); + private static native void nativeSetSystemUiVisibility(int ptr, int visibility); + private static native void nativeSetFocusedApplication(int ptr, + InputApplicationHandle application); + private static native InputDevice nativeGetInputDevice(int ptr, int deviceId); + private static native void nativeGetInputConfiguration(int ptr, Configuration configuration); + private static native int[] nativeGetInputDeviceIds(int ptr); + private static native boolean nativeTransferTouchFocus(int ptr, + InputChannel fromChannel, InputChannel toChannel); + private static native void nativeSetPointerSpeed(int ptr, int speed); + private static native void nativeSetShowTouches(int ptr, boolean enabled); + private static native String nativeDump(int ptr); + private static native void nativeMonitor(int ptr); + // Input event injection constants defined in InputDispatcher.h. - static final int INPUT_EVENT_INJECTION_SUCCEEDED = 0; - static final int INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1; - static final int INPUT_EVENT_INJECTION_FAILED = 2; - static final int INPUT_EVENT_INJECTION_TIMED_OUT = 3; - - // Input event injection synchronization modes defined in InputDispatcher.h - static final int INPUT_EVENT_INJECTION_SYNC_NONE = 0; - static final int INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT = 1; - static final int INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISH = 2; - + private static final int INPUT_EVENT_INJECTION_SUCCEEDED = 0; + private static final int INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1; + private static final int INPUT_EVENT_INJECTION_FAILED = 2; + private static final int INPUT_EVENT_INJECTION_TIMED_OUT = 3; + + // Maximum number of milliseconds to wait for input event injection. + private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000; + // Key states (may be returned by queries about the current state of a // particular key code, scan code or switch). @@ -129,23 +140,21 @@ public class InputManager implements Watchdog.Monitor { InputFilter mInputFilter; InputFilterHost mInputFilterHost; - public InputManager(Context context, WindowManagerService windowManagerService) { + public InputManagerService(Context context, Callbacks callbacks) { this.mContext = context; - this.mWindowManagerService = windowManagerService; - this.mCallbacks = new Callbacks(); - - Looper looper = windowManagerService.mH.getLooper(); + this.mCallbacks = callbacks; + this.mHandler = new Handler(); Slog.i(TAG, "Initializing input manager"); - nativeInit(mContext, mCallbacks, looper.getQueue()); - - // Add ourself to the Watchdog monitors. - Watchdog.getInstance().addMonitor(this); + mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue()); } public void start() { Slog.i(TAG, "Starting input manager"); - nativeStart(); + nativeStart(mPtr); + + // Add ourself to the Watchdog monitors. + Watchdog.getInstance().addMonitor(this); registerPointerSpeedSettingObserver(); registerShowTouchesSettingObserver(); @@ -164,7 +173,7 @@ public class InputManager implements Watchdog.Monitor { Slog.d(TAG, "Setting display #" + displayId + " size to " + width + "x" + height + " external size " + externalWidth + "x" + externalHeight); } - nativeSetDisplaySize(displayId, width, height, externalWidth, externalHeight); + nativeSetDisplaySize(mPtr, displayId, width, height, externalWidth, externalHeight); } public void setDisplayOrientation(int displayId, int rotation) { @@ -175,7 +184,7 @@ public class InputManager implements Watchdog.Monitor { if (DEBUG) { Slog.d(TAG, "Setting display #" + displayId + " orientation to " + rotation); } - nativeSetDisplayOrientation(displayId, rotation); + nativeSetDisplayOrientation(mPtr, displayId, rotation); } public void getInputConfiguration(Configuration config) { @@ -183,9 +192,9 @@ public class InputManager implements Watchdog.Monitor { throw new IllegalArgumentException("config must not be null."); } - nativeGetInputConfiguration(config); + nativeGetInputConfiguration(mPtr, config); } - + /** * Gets the current state of a key or button by key code. * @param deviceId The input device id, or -1 to consult all devices. @@ -196,7 +205,7 @@ public class InputManager implements Watchdog.Monitor { * @return The key state. */ public int getKeyCodeState(int deviceId, int sourceMask, int keyCode) { - return nativeGetKeyCodeState(deviceId, sourceMask, keyCode); + return nativeGetKeyCodeState(mPtr, deviceId, sourceMask, keyCode); } /** @@ -209,7 +218,7 @@ public class InputManager implements Watchdog.Monitor { * @return The key state. */ public int getScanCodeState(int deviceId, int sourceMask, int scanCode) { - return nativeGetScanCodeState(deviceId, sourceMask, scanCode); + return nativeGetScanCodeState(mPtr, deviceId, sourceMask, scanCode); } /** @@ -222,7 +231,7 @@ public class InputManager implements Watchdog.Monitor { * @return The switch state. */ public int getSwitchState(int deviceId, int sourceMask, int switchCode) { - return nativeGetSwitchState(deviceId, sourceMask, switchCode); + return nativeGetSwitchState(mPtr, deviceId, sourceMask, switchCode); } /** @@ -237,6 +246,7 @@ public class InputManager implements Watchdog.Monitor { * key codes. * @return True if the lookup was successful, false otherwise. */ + @Override public boolean hasKeys(int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists) { if (keyCodes == null) { throw new IllegalArgumentException("keyCodes must not be null."); @@ -246,7 +256,7 @@ public class InputManager implements Watchdog.Monitor { + "least as large as keyCodes."); } - return nativeHasKeys(deviceId, sourceMask, keyCodes, keyExists); + return nativeHasKeys(mPtr, deviceId, sourceMask, keyCodes, keyExists); } /** @@ -260,7 +270,7 @@ public class InputManager implements Watchdog.Monitor { } InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName); - nativeRegisterInputChannel(inputChannels[0], null, true); + nativeRegisterInputChannel(mPtr, inputChannels[0], null, true); inputChannels[0].dispose(); // don't need to retain the Java object reference return inputChannels[1]; } @@ -277,7 +287,7 @@ public class InputManager implements Watchdog.Monitor { throw new IllegalArgumentException("inputChannel must not be null."); } - nativeRegisterInputChannel(inputChannel, inputWindowHandle, false); + nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false); } /** @@ -289,7 +299,7 @@ public class InputManager implements Watchdog.Monitor { throw new IllegalArgumentException("inputChannel must not be null."); } - nativeUnregisterInputChannel(inputChannel); + nativeUnregisterInputChannel(mPtr, inputChannel); } /** @@ -323,47 +333,46 @@ public class InputManager implements Watchdog.Monitor { filter.install(mInputFilterHost); } - nativeSetInputFilterEnabled(filter != null); + nativeSetInputFilterEnabled(mPtr, filter != null); } } - /** - * Injects an input event into the event system on behalf of an application. - * The synchronization mode determines whether the method blocks while waiting for - * input injection to proceed. - * - * {@link #INPUT_EVENT_INJECTION_SYNC_NONE} never blocks. Injection is asynchronous and - * is assumed always to be successful. - * - * {@link #INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT} waits for previous events to be - * dispatched so that the input dispatcher can determine whether input event injection will - * be permitted based on the current input focus. Does not wait for the input event to - * finish processing. - * - * {@link #INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISH} waits for the input event to - * be completely processed. - * - * @param event The event to inject. - * @param injectorPid The pid of the injecting application. - * @param injectorUid The uid of the injecting application. - * @param syncMode The synchronization mode. - * @param timeoutMillis The injection timeout in milliseconds. - * @return One of the INPUT_EVENT_INJECTION_XXX constants. - */ - public int injectInputEvent(InputEvent event, int injectorPid, int injectorUid, - int syncMode, int timeoutMillis) { + @Override + public boolean injectInputEvent(InputEvent event, int mode) { if (event == null) { throw new IllegalArgumentException("event must not be null"); } - if (injectorPid < 0 || injectorUid < 0) { - throw new IllegalArgumentException("injectorPid and injectorUid must not be negative."); - } - if (timeoutMillis <= 0) { - throw new IllegalArgumentException("timeoutMillis must be positive"); + if (mode != InputManager.INJECT_INPUT_EVENT_MODE_ASYNC + && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH + && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT) { + throw new IllegalArgumentException("mode is invalid"); } - return nativeInjectInputEvent(event, injectorPid, injectorUid, syncMode, timeoutMillis, - WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT); + final int pid = Binder.getCallingPid(); + final int uid = Binder.getCallingUid(); + final long ident = Binder.clearCallingIdentity(); + final int result; + try { + result = nativeInjectInputEvent(mPtr, event, pid, uid, mode, + INJECTION_TIMEOUT_MILLIS, WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT); + } finally { + Binder.restoreCallingIdentity(ident); + } + switch (result) { + case INPUT_EVENT_INJECTION_PERMISSION_DENIED: + Slog.w(TAG, "Input event injection from pid " + pid + " permission denied."); + throw new SecurityException( + "Injecting to another application requires INJECT_EVENTS permission"); + case INPUT_EVENT_INJECTION_SUCCEEDED: + return true; + case INPUT_EVENT_INJECTION_TIMED_OUT: + Slog.w(TAG, "Input event injection from pid " + pid + " timed out."); + return false; + case INPUT_EVENT_INJECTION_FAILED: + default: + Slog.w(TAG, "Input event injection from pid " + pid + " failed."); + return false; + } } /** @@ -371,32 +380,34 @@ public class InputManager implements Watchdog.Monitor { * @param id The device id. * @return The input device or null if not found. */ + @Override public InputDevice getInputDevice(int deviceId) { - return nativeGetInputDevice(deviceId); + return nativeGetInputDevice(mPtr, deviceId); } /** * Gets the ids of all input devices in the system. * @return The input device ids. */ + @Override public int[] getInputDeviceIds() { - return nativeGetInputDeviceIds(); + return nativeGetInputDeviceIds(mPtr); } public void setInputWindows(InputWindowHandle[] windowHandles) { - nativeSetInputWindows(windowHandles); + nativeSetInputWindows(mPtr, windowHandles); } public void setFocusedApplication(InputApplicationHandle application) { - nativeSetFocusedApplication(application); + nativeSetFocusedApplication(mPtr, application); } public void setInputDispatchMode(boolean enabled, boolean frozen) { - nativeSetInputDispatchMode(enabled, frozen); + nativeSetInputDispatchMode(mPtr, enabled, frozen); } public void setSystemUiVisibility(int visibility) { - nativeSetSystemUiVisibility(visibility); + nativeSetSystemUiVisibility(mPtr, visibility); } /** @@ -419,7 +430,7 @@ public class InputManager implements Watchdog.Monitor { if (toChannel == null) { throw new IllegalArgumentException("toChannel must not be null."); } - return nativeTransferTouchFocus(fromChannel, toChannel); + return nativeTransferTouchFocus(mPtr, fromChannel, toChannel); } /** @@ -427,20 +438,31 @@ public class InputManager implements Watchdog.Monitor { * @param speed The pointer speed as a value between -7 (slowest) and 7 (fastest) * where 0 is the default speed. */ - public void setPointerSpeed(int speed) { - speed = Math.min(Math.max(speed, -7), 7); - nativeSetPointerSpeed(speed); + @Override + public void tryPointerSpeed(int speed) { + if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED, + "tryPointerSpeed()")) { + throw new SecurityException("Requires SET_POINTER_SPEED permission"); + } + + setPointerSpeedUnchecked(speed); } public void updatePointerSpeedFromSettings() { - int speed = getPointerSpeedSetting(0); - setPointerSpeed(speed); + int speed = getPointerSpeedSetting(); + setPointerSpeedUnchecked(speed); + } + + private void setPointerSpeedUnchecked(int speed) { + speed = Math.min(Math.max(speed, InputManager.MIN_POINTER_SPEED), + InputManager.MAX_POINTER_SPEED); + nativeSetPointerSpeed(mPtr, speed); } private void registerPointerSpeedSettingObserver() { mContext.getContentResolver().registerContentObserver( Settings.System.getUriFor(Settings.System.POINTER_SPEED), true, - new ContentObserver(mWindowManagerService.mH) { + new ContentObserver(mHandler) { @Override public void onChange(boolean selfChange) { updatePointerSpeedFromSettings(); @@ -448,8 +470,8 @@ public class InputManager implements Watchdog.Monitor { }); } - private int getPointerSpeedSetting(int defaultValue) { - int speed = defaultValue; + private int getPointerSpeedSetting() { + int speed = InputManager.DEFAULT_POINTER_SPEED; try { speed = Settings.System.getInt(mContext.getContentResolver(), Settings.System.POINTER_SPEED); @@ -460,13 +482,13 @@ public class InputManager implements Watchdog.Monitor { public void updateShowTouchesFromSettings() { int setting = getShowTouchesSetting(0); - nativeSetShowTouches(setting != 0); + nativeSetShowTouches(mPtr, setting != 0); } private void registerShowTouchesSettingObserver() { mContext.getContentResolver().registerContentObserver( Settings.System.getUriFor(Settings.System.SHOW_TOUCHES), true, - new ContentObserver(mWindowManagerService.mH) { + new ContentObserver(mHandler) { @Override public void onChange(boolean selfChange) { updateShowTouchesFromSettings(); @@ -484,200 +506,238 @@ public class InputManager implements Watchdog.Monitor { return result; } - public void dump(PrintWriter pw) { - String dumpStr = nativeDump(); + @Override + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (mContext.checkCallingOrSelfPermission("android.permission.DUMP") + != PackageManager.PERMISSION_GRANTED) { + pw.println("Permission Denial: can't dump InputManager from from pid=" + + Binder.getCallingPid() + + ", uid=" + Binder.getCallingUid()); + return; + } + + pw.println("INPUT MANAGER (dumpsys input)\n"); + String dumpStr = nativeDump(mPtr); if (dumpStr != null) { pw.println(dumpStr); } } - // Called by the heartbeat to ensure locks are not held indefnitely (for deadlock detection). + private boolean checkCallingPermission(String permission, String func) { + // Quick check: if the calling permission is me, it's all okay. + if (Binder.getCallingPid() == Process.myPid()) { + return true; + } + + if (mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED) { + return true; + } + String msg = "Permission Denial: " + func + " from pid=" + + Binder.getCallingPid() + + ", uid=" + Binder.getCallingUid() + + " requires " + permission; + Slog.w(TAG, msg); + return false; + } + + // Called by the heartbeat to ensure locks are not held indefinitely (for deadlock detection). public void monitor() { synchronized (mInputFilterLock) { } - nativeMonitor(); + nativeMonitor(mPtr); } - private final class InputFilterHost implements InputFilter.Host { - private boolean mDisconnected; + // Native callback. + private void notifyConfigurationChanged(long whenNanos) { + mCallbacks.notifyConfigurationChanged(); + } - public void disconnectLocked() { - mDisconnected = true; - } + // Native callback. + private void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) { + mCallbacks.notifyLidSwitchChanged(whenNanos, lidOpen); + } - public void sendInputEvent(InputEvent event, int policyFlags) { - if (event == null) { - throw new IllegalArgumentException("event must not be null"); - } + // Native callback. + private void notifyInputChannelBroken(InputWindowHandle inputWindowHandle) { + mCallbacks.notifyInputChannelBroken(inputWindowHandle); + } - synchronized (mInputFilterLock) { - if (!mDisconnected) { - nativeInjectInputEvent(event, 0, 0, INPUT_EVENT_INJECTION_SYNC_NONE, 0, - policyFlags | WindowManagerPolicy.FLAG_FILTERED); - } + // Native callback. + private long notifyANR(InputApplicationHandle inputApplicationHandle, + InputWindowHandle inputWindowHandle) { + return mCallbacks.notifyANR(inputApplicationHandle, inputWindowHandle); + } + + // Native callback. + final boolean filterInputEvent(InputEvent event, int policyFlags) { + synchronized (mInputFilterLock) { + if (mInputFilter != null) { + mInputFilter.filterInputEvent(event, policyFlags); + return false; } } + event.recycle(); + return true; } - /* - * Callbacks from native. - */ - private final class Callbacks { - static final String TAG = "InputManager-Callbacks"; - - private static final boolean DEBUG_VIRTUAL_KEYS = false; - private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml"; - private static final String CALIBRATION_DIR_PATH = "usr/idc/"; - - @SuppressWarnings("unused") - public void notifyConfigurationChanged(long whenNanos) { - mWindowManagerService.mInputMonitor.notifyConfigurationChanged(); - } - - @SuppressWarnings("unused") - public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) { - mWindowManagerService.mInputMonitor.notifyLidSwitchChanged(whenNanos, lidOpen); - } - - @SuppressWarnings("unused") - public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle) { - mWindowManagerService.mInputMonitor.notifyInputChannelBroken(inputWindowHandle); - } - - @SuppressWarnings("unused") - public long notifyANR(InputApplicationHandle inputApplicationHandle, - InputWindowHandle inputWindowHandle) { - return mWindowManagerService.mInputMonitor.notifyANR( - inputApplicationHandle, inputWindowHandle); - } + // Native callback. + private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) { + return mCallbacks.interceptKeyBeforeQueueing( + event, policyFlags, isScreenOn); + } - @SuppressWarnings("unused") - final boolean filterInputEvent(InputEvent event, int policyFlags) { - synchronized (mInputFilterLock) { - if (mInputFilter != null) { - mInputFilter.filterInputEvent(event, policyFlags); - return false; - } - } - event.recycle(); - return true; - } + // Native callback. + private int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) { + return mCallbacks.interceptMotionBeforeQueueingWhenScreenOff(policyFlags); + } - @SuppressWarnings("unused") - public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) { - return mWindowManagerService.mInputMonitor.interceptKeyBeforeQueueing( - event, policyFlags, isScreenOn); - } + // Native callback. + private long interceptKeyBeforeDispatching(InputWindowHandle focus, + KeyEvent event, int policyFlags) { + return mCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags); + } - @SuppressWarnings("unused") - public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) { - return mWindowManagerService.mInputMonitor.interceptMotionBeforeQueueingWhenScreenOff( - policyFlags); - } + // Native callback. + private KeyEvent dispatchUnhandledKey(InputWindowHandle focus, + KeyEvent event, int policyFlags) { + return mCallbacks.dispatchUnhandledKey(focus, event, policyFlags); + } - @SuppressWarnings("unused") - public long interceptKeyBeforeDispatching(InputWindowHandle focus, - KeyEvent event, int policyFlags) { - return mWindowManagerService.mInputMonitor.interceptKeyBeforeDispatching( - focus, event, policyFlags); - } - - @SuppressWarnings("unused") - public KeyEvent dispatchUnhandledKey(InputWindowHandle focus, - KeyEvent event, int policyFlags) { - return mWindowManagerService.mInputMonitor.dispatchUnhandledKey( - focus, event, policyFlags); - } - - @SuppressWarnings("unused") - public boolean checkInjectEventsPermission(int injectorPid, int injectorUid) { - return mContext.checkPermission( - android.Manifest.permission.INJECT_EVENTS, injectorPid, injectorUid) - == PackageManager.PERMISSION_GRANTED; - } + // Native callback. + private boolean checkInjectEventsPermission(int injectorPid, int injectorUid) { + return mContext.checkPermission(android.Manifest.permission.INJECT_EVENTS, + injectorPid, injectorUid) == PackageManager.PERMISSION_GRANTED; + } - @SuppressWarnings("unused") - public int getVirtualKeyQuietTimeMillis() { - return mContext.getResources().getInteger( - com.android.internal.R.integer.config_virtualKeyQuietTimeMillis); - } + // Native callback. + private int getVirtualKeyQuietTimeMillis() { + return mContext.getResources().getInteger( + com.android.internal.R.integer.config_virtualKeyQuietTimeMillis); + } - @SuppressWarnings("unused") - public String[] getExcludedDeviceNames() { - ArrayList<String> names = new ArrayList<String>(); - - // Read partner-provided list of excluded input devices - XmlPullParser parser = null; - // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system". - File confFile = new File(Environment.getRootDirectory(), EXCLUDED_DEVICES_PATH); - FileReader confreader = null; - try { - confreader = new FileReader(confFile); - parser = Xml.newPullParser(); - parser.setInput(confreader); - XmlUtils.beginDocument(parser, "devices"); - - while (true) { - XmlUtils.nextElement(parser); - if (!"device".equals(parser.getName())) { - break; - } - String name = parser.getAttributeValue(null, "name"); - if (name != null) { - names.add(name); - } + // Native callback. + private String[] getExcludedDeviceNames() { + ArrayList<String> names = new ArrayList<String>(); + + // Read partner-provided list of excluded input devices + XmlPullParser parser = null; + // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system". + File confFile = new File(Environment.getRootDirectory(), EXCLUDED_DEVICES_PATH); + FileReader confreader = null; + try { + confreader = new FileReader(confFile); + parser = Xml.newPullParser(); + parser.setInput(confreader); + XmlUtils.beginDocument(parser, "devices"); + + while (true) { + XmlUtils.nextElement(parser); + if (!"device".equals(parser.getName())) { + break; + } + String name = parser.getAttributeValue(null, "name"); + if (name != null) { + names.add(name); } - } catch (FileNotFoundException e) { - // It's ok if the file does not exist. - } catch (Exception e) { - Slog.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e); - } finally { - try { if (confreader != null) confreader.close(); } catch (IOException e) { } } - - return names.toArray(new String[names.size()]); + } catch (FileNotFoundException e) { + // It's ok if the file does not exist. + } catch (Exception e) { + Slog.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e); + } finally { + try { if (confreader != null) confreader.close(); } catch (IOException e) { } } - @SuppressWarnings("unused") - public int getKeyRepeatTimeout() { - return ViewConfiguration.getKeyRepeatTimeout(); - } + return names.toArray(new String[names.size()]); + } - @SuppressWarnings("unused") - public int getKeyRepeatDelay() { - return ViewConfiguration.getKeyRepeatDelay(); - } + // Native callback. + private int getKeyRepeatTimeout() { + return ViewConfiguration.getKeyRepeatTimeout(); + } - @SuppressWarnings("unused") - public int getHoverTapTimeout() { - return ViewConfiguration.getHoverTapTimeout(); - } + // Native callback. + private int getKeyRepeatDelay() { + return ViewConfiguration.getKeyRepeatDelay(); + } - @SuppressWarnings("unused") - public int getHoverTapSlop() { - return ViewConfiguration.getHoverTapSlop(); - } + // Native callback. + private int getHoverTapTimeout() { + return ViewConfiguration.getHoverTapTimeout(); + } - @SuppressWarnings("unused") - public int getDoubleTapTimeout() { - return ViewConfiguration.getDoubleTapTimeout(); - } + // Native callback. + private int getHoverTapSlop() { + return ViewConfiguration.getHoverTapSlop(); + } - @SuppressWarnings("unused") - public int getLongPressTimeout() { - return ViewConfiguration.getLongPressTimeout(); - } + // Native callback. + private int getDoubleTapTimeout() { + return ViewConfiguration.getDoubleTapTimeout(); + } + + // Native callback. + private int getLongPressTimeout() { + return ViewConfiguration.getLongPressTimeout(); + } - @SuppressWarnings("unused") - public int getPointerLayer() { - return mWindowManagerService.mPolicy.windowTypeToLayerLw( - WindowManager.LayoutParams.TYPE_POINTER) - * WindowManagerService.TYPE_LAYER_MULTIPLIER - + WindowManagerService.TYPE_LAYER_OFFSET; + // Native callback. + private int getPointerLayer() { + return mCallbacks.getPointerLayer(); + } + + // Native callback. + private PointerIcon getPointerIcon() { + return PointerIcon.getDefaultIcon(mContext); + } + + /** + * Callback interface implemented by the Window Manager. + */ + public interface Callbacks { + public void notifyConfigurationChanged(); + + public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen); + + public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle); + + public long notifyANR(InputApplicationHandle inputApplicationHandle, + InputWindowHandle inputWindowHandle); + + public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn); + + public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags); + + public long interceptKeyBeforeDispatching(InputWindowHandle focus, + KeyEvent event, int policyFlags); + + public KeyEvent dispatchUnhandledKey(InputWindowHandle focus, + KeyEvent event, int policyFlags); + + public int getPointerLayer(); + } + + /** + * Hosting interface for input filters to call back into the input manager. + */ + private final class InputFilterHost implements InputFilter.Host { + private boolean mDisconnected; + + public void disconnectLocked() { + mDisconnected = true; } - @SuppressWarnings("unused") - public PointerIcon getPointerIcon() { - return PointerIcon.getDefaultIcon(mContext); + public void sendInputEvent(InputEvent event, int policyFlags) { + if (event == null) { + throw new IllegalArgumentException("event must not be null"); + } + + synchronized (mInputFilterLock) { + if (!mDisconnected) { + nativeInjectInputEvent(mPtr, event, 0, 0, + InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, 0, + policyFlags | WindowManagerPolicy.FLAG_FILTERED); + } + } } } } diff --git a/services/java/com/android/server/wm/InputWindowHandle.java b/services/java/com/android/server/input/InputWindowHandle.java index 264877c..03d66af 100644 --- a/services/java/com/android/server/wm/InputWindowHandle.java +++ b/services/java/com/android/server/input/InputWindowHandle.java @@ -14,11 +14,10 @@ * limitations under the License. */ -package com.android.server.wm; +package com.android.server.input; import android.graphics.Region; import android.view.InputChannel; -import android.view.WindowManagerPolicy; /** * Functions as a handle for a window that can receive input. @@ -35,7 +34,7 @@ public final class InputWindowHandle { public final InputApplicationHandle inputApplicationHandle; // The window manager's window state. - public final WindowManagerPolicy.WindowState windowState; + public final Object windowState; // The input channel associated with the window. public InputChannel inputChannel; @@ -91,7 +90,7 @@ public final class InputWindowHandle { private native void nativeDispose(); public InputWindowHandle(InputApplicationHandle inputApplicationHandle, - WindowManagerPolicy.WindowState windowState) { + Object windowState) { this.inputApplicationHandle = inputApplicationHandle; this.windowState = windowState; } diff --git a/services/java/com/android/server/location/ComprehensiveCountryDetector.java b/services/java/com/android/server/location/ComprehensiveCountryDetector.java index 2d6a148..1026a0d 100755 --- a/services/java/com/android/server/location/ComprehensiveCountryDetector.java +++ b/services/java/com/android/server/location/ComprehensiveCountryDetector.java @@ -202,7 +202,7 @@ public class ComprehensiveCountryDetector extends CountryDetectorBase { if (mDebugLogs.size() >= MAX_LENGTH_DEBUG_LOGS) { mDebugLogs.poll(); } - if (Log.isLoggable(TAG, Log.DEBUG)) { + if (DEBUG) { Slog.d(TAG, country.toString()); } mDebugLogs.add(country); @@ -394,7 +394,7 @@ public class ComprehensiveCountryDetector extends CountryDetectorBase { private void notifyIfCountryChanged(final Country country, final Country detectedCountry) { if (detectedCountry != null && mListener != null && (country == null || !country.equals(detectedCountry))) { - if (Log.isLoggable(TAG, Log.DEBUG)) { + if (DEBUG) { Slog.d(TAG, "" + country + " --> " + detectedCountry); } notifyListener(detectedCountry); diff --git a/services/java/com/android/server/net/NetworkIdentitySet.java b/services/java/com/android/server/net/NetworkIdentitySet.java index af03fb3..397f9f4 100644 --- a/services/java/com/android/server/net/NetworkIdentitySet.java +++ b/services/java/com/android/server/net/NetworkIdentitySet.java @@ -21,7 +21,6 @@ import android.net.NetworkIdentity; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; -import java.net.ProtocolException; import java.util.HashSet; /** @@ -33,48 +32,46 @@ import java.util.HashSet; public class NetworkIdentitySet extends HashSet<NetworkIdentity> { private static final int VERSION_INIT = 1; private static final int VERSION_ADD_ROAMING = 2; + private static final int VERSION_ADD_NETWORK_ID = 3; public NetworkIdentitySet() { } public NetworkIdentitySet(DataInputStream in) throws IOException { final int version = in.readInt(); - switch (version) { - case VERSION_INIT: { - final int size = in.readInt(); - for (int i = 0; i < size; i++) { - final int ignoredVersion = in.readInt(); - final int type = in.readInt(); - final int subType = in.readInt(); - final String subscriberId = readOptionalString(in); - add(new NetworkIdentity(type, subType, subscriberId, false)); - } - break; + final int size = in.readInt(); + for (int i = 0; i < size; i++) { + if (version <= VERSION_INIT) { + final int ignored = in.readInt(); } - case VERSION_ADD_ROAMING: { - final int size = in.readInt(); - for (int i = 0; i < size; i++) { - final int type = in.readInt(); - final int subType = in.readInt(); - final String subscriberId = readOptionalString(in); - final boolean roaming = in.readBoolean(); - add(new NetworkIdentity(type, subType, subscriberId, roaming)); - } - break; + final int type = in.readInt(); + final int subType = in.readInt(); + final String subscriberId = readOptionalString(in); + final String networkId; + if (version >= VERSION_ADD_NETWORK_ID) { + networkId = readOptionalString(in); + } else { + networkId = null; } - default: { - throw new ProtocolException("unexpected version: " + version); + final boolean roaming; + if (version >= VERSION_ADD_ROAMING) { + roaming = in.readBoolean(); + } else { + roaming = false; } + + add(new NetworkIdentity(type, subType, subscriberId, networkId, false)); } } public void writeToStream(DataOutputStream out) throws IOException { - out.writeInt(VERSION_ADD_ROAMING); + out.writeInt(VERSION_ADD_NETWORK_ID); out.writeInt(size()); for (NetworkIdentity ident : this) { out.writeInt(ident.getType()); out.writeInt(ident.getSubType()); writeOptionalString(out, ident.getSubscriberId()); + writeOptionalString(out, ident.getNetworkId()); out.writeBoolean(ident.getRoaming()); } } diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java index a890068..77addd6 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; @@ -49,6 +48,7 @@ import static android.net.NetworkTemplate.MATCH_MOBILE_ALL; import static android.net.NetworkTemplate.MATCH_WIFI; import static android.net.NetworkTemplate.buildTemplateMobileAll; import static android.net.TrafficStats.MB_IN_BYTES; +import static android.telephony.TelephonyManager.SIM_STATE_READY; import static android.text.format.DateUtils.DAY_IN_MILLIS; import static com.android.internal.util.Preconditions.checkNotNull; import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT; @@ -74,6 +74,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 +97,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; @@ -112,6 +114,7 @@ import android.util.Xml; import com.android.internal.R; import com.android.internal.os.AtomicFile; import com.android.internal.util.FastXmlSerializer; +import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Objects; import com.google.android.collect.Lists; import com.google.android.collect.Maps; @@ -156,6 +159,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private static final int VERSION_ADDED_RESTRICT_BACKGROUND = 3; 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; + private static final int VERSION_ADDED_NETWORK_ID = 9; + private static final int VERSION_LATEST = VERSION_ADDED_NETWORK_ID; // @VisibleForTesting public static final int TYPE_WARNING = 0x1; @@ -165,19 +173,24 @@ 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"; private static final String ATTR_NETWORK_TEMPLATE = "networkTemplate"; private static final String ATTR_SUBSCRIBER_ID = "subscriberId"; + private static final String ATTR_NETWORK_ID = "networkId"; private static final String ATTR_CYCLE_DAY = "cycleDay"; + private static final String ATTR_CYCLE_TIMEZONE = "cycleTimezone"; private static final String ATTR_WARNING_BYTES = "warningBytes"; private static final String ATTR_LIMIT_BYTES = "limitBytes"; private static final String ATTR_LAST_SNOOZE = "lastSnooze"; 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"; @@ -219,8 +232,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(); @@ -375,18 +388,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(); } } @@ -475,6 +496,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { for (NetworkPolicy policy : mNetworkPolicy.values()) { // ignore policies that aren't relevant to user if (!isTemplateRelevant(policy.template)) continue; + if (!policy.hasCycle()) continue; final long start = computeLastCycleBoundary(currentTime, policy); final long end = currentTime; @@ -512,16 +534,24 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { /** * Test if given {@link NetworkTemplate} is relevant to user based on - * current device state, such as when {@link #getActiveSubscriberId()} - * matches. This is regardless of data connection status. + * current device state, such as when + * {@link TelephonyManager#getSubscriberId()} matches. This is regardless of + * data connection status. */ private boolean isTemplateRelevant(NetworkTemplate template) { + final TelephonyManager tele = TelephonyManager.from(mContext); + switch (template.getMatchRule()) { case MATCH_MOBILE_3G_LOWER: case MATCH_MOBILE_4G: case MATCH_MOBILE_ALL: - // mobile templates are relevant when subscriberid is active - return Objects.equal(getActiveSubscriberId(), template.getSubscriberId()); + // mobile templates are relevant when SIM is ready and + // subscriberId matches. + if (tele.getSimState() == SIM_STATE_READY) { + return Objects.equal(tele.getSubscriberId(), template.getSubscriberId()); + } else { + return false; + } } return true; } @@ -740,7 +770,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final long currentTime = currentTimeMillis(); for (NetworkPolicy policy : mNetworkPolicy.values()) { // shortcut when policy has no limit - if (policy.limitBytes == LIMIT_DISABLED) { + if (policy.limitBytes == LIMIT_DISABLED || !policy.hasCycle()) { setNetworkTemplateEnabled(policy.template, true); continue; } @@ -763,13 +793,16 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * for the given {@link NetworkTemplate}. */ private void setNetworkTemplateEnabled(NetworkTemplate template, boolean enabled) { + final TelephonyManager tele = TelephonyManager.from(mContext); + switch (template.getMatchRule()) { case MATCH_MOBILE_3G_LOWER: case MATCH_MOBILE_4G: case MATCH_MOBILE_ALL: // TODO: offer more granular control over radio states once // 4965893 is available. - if (Objects.equal(getActiveSubscriberId(), template.getSubscriberId())) { + if (tele.getSimState() == SIM_STATE_READY + && Objects.equal(tele.getSubscriberId(), template.getSubscriberId())) { setPolicyDataEnable(TYPE_MOBILE, enabled); setPolicyDataEnable(TYPE_WIMAX, enabled); } @@ -842,9 +875,15 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { for (NetworkPolicy policy : mNetworkRules.keySet()) { final String[] ifaces = mNetworkRules.get(policy); - final long start = computeLastCycleBoundary(currentTime, policy); - final long end = currentTime; - final long totalBytes = getTotalBytes(policy.template, start, end); + final long start; + final long totalBytes; + if (policy.hasCycle()) { + start = computeLastCycleBoundary(currentTime, policy); + totalBytes = getTotalBytes(policy.template, start, currentTime); + } else { + start = Long.MAX_VALUE; + totalBytes = 0; + } if (LOGD) { Slog.d(TAG, "applying policy " + policy.toString() + " to ifaces " @@ -902,9 +941,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { if (LOGV) Slog.v(TAG, "ensureActiveMobilePolicyLocked()"); if (mSuppressDefaultPolicy) return; - final String subscriberId = getActiveSubscriberId(); + final TelephonyManager tele = TelephonyManager.from(mContext); + + // avoid creating policy when SIM isn't ready + if (tele.getSimState() != SIM_STATE_READY) return; + + final String subscriberId = tele.getSubscriberId(); final NetworkIdentity probeIdent = new NetworkIdentity( - TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, false); + TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false); // examine to see if any policy is defined for active mobile boolean mobileDefined = false; @@ -922,13 +966,15 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { com.android.internal.R.integer.config_networkPolicyDefaultWarning) * MB_IN_BYTES; - final Time time = new Time(Time.TIMEZONE_UTC); + final Time time = new Time(); time.setToNow(); + final int cycleDay = time.monthDay; + final String cycleTimezone = time.timezone; final NetworkTemplate template = buildTemplateMobileAll(subscriberId); - mNetworkPolicy.put(template, new NetworkPolicy(template, cycleDay, warningBytes, - LIMIT_DISABLED, SNOOZE_NEVER, SNOOZE_NEVER, true)); + mNetworkPolicy.put(template, new NetworkPolicy(template, cycleDay, cycleTimezone, + warningBytes, LIMIT_DISABLED, SNOOZE_NEVER, SNOOZE_NEVER, true, true)); writePolicyLocked(); } } @@ -938,7 +984,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 { @@ -963,7 +1009,19 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } else if (TAG_NETWORK_POLICY.equals(tag)) { final int networkTemplate = readIntAttribute(in, ATTR_NETWORK_TEMPLATE); final String subscriberId = in.getAttributeValue(null, ATTR_SUBSCRIBER_ID); + final String networkId; + if (version >= VERSION_ADDED_NETWORK_ID) { + networkId = in.getAttributeValue(null, ATTR_NETWORK_ID); + } else { + networkId = null; + } final int cycleDay = readIntAttribute(in, ATTR_CYCLE_DAY); + final String cycleTimezone; + if (version >= VERSION_ADDED_TIMEZONE) { + cycleTimezone = in.getAttributeValue(null, ATTR_CYCLE_TIMEZONE); + } else { + cycleTimezone = Time.TIMEZONE_UTC; + } final long warningBytes = readLongAttribute(in, ATTR_WARNING_BYTES); final long limitBytes = readLongAttribute(in, ATTR_LIMIT_BYTES); final long lastLimitSnooze; @@ -994,22 +1052,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); + networkTemplate, subscriberId, networkId); mNetworkPolicy.put(template, new NetworkPolicy(template, cycleDay, - warningBytes, limitBytes, lastWarningSnooze, lastLimitSnooze, - metered)); + cycleTimezone, warningBytes, limitBytes, lastWarningSnooze, + lastLimitSnooze, metered, inferred)); - } else if (TAG_UID_POLICY.equals(tag)) { + } else if (TAG_UID_POLICY.equals(tag) && version < VERSION_SWITCH_APP_ID) { 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) && version >= VERSION_SWITCH_APP_ID) { + 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"); + } } } } @@ -1054,7 +1128,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { out.startDocument(null, true); out.startTag(null, TAG_POLICY_LIST); - writeIntAttribute(out, ATTR_VERSION, VERSION_SPLIT_SNOOZE); + writeIntAttribute(out, ATTR_VERSION, VERSION_LATEST); writeBooleanAttribute(out, ATTR_RESTRICT_BACKGROUND, mRestrictBackground); // write all known network policies @@ -1067,27 +1141,33 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { if (subscriberId != null) { out.attribute(null, ATTR_SUBSCRIBER_ID, subscriberId); } + final String networkId = template.getNetworkId(); + if (networkId != null) { + out.attribute(null, ATTR_NETWORK_ID, networkId); + } writeIntAttribute(out, ATTR_CYCLE_DAY, policy.cycleDay); + out.attribute(null, ATTR_CYCLE_TIMEZONE, policy.cycleTimezone); writeLongAttribute(out, ATTR_WARNING_BYTES, policy.warningBytes); writeLongAttribute(out, ATTR_LIMIT_BYTES, policy.limitBytes); 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); @@ -1102,24 +1182,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(); } @@ -1127,11 +1207,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); } } @@ -1271,7 +1351,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { policy = findPolicyForNetworkLocked(ident); } - if (policy == null) { + if (policy == null || !policy.hasCycle()) { // missing policy means we can't derive useful quota info return null; } @@ -1293,9 +1373,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } @Override - protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) { + protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { mContext.enforceCallingOrSelfPermission(DUMP, TAG); + final IndentingPrintWriter fout = new IndentingPrintWriter(writer, " "); + final HashSet<String> argSet = new HashSet<String>(); for (String arg : args) { argSet.add(arg); @@ -1318,31 +1400,38 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { fout.print("Restrict background: "); fout.println(mRestrictBackground); fout.println("Network policies:"); + fout.increaseIndent(); for (NetworkPolicy policy : mNetworkPolicy.values()) { - fout.print(" "); fout.println(policy.toString()); + fout.println(policy.toString()); } + fout.decreaseIndent(); - fout.println("Policy status for known UIDs:"); + fout.println("Policy for apps:"); + fout.increaseIndent(); + 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(); + } + fout.decreaseIndent(); 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:"); + fout.increaseIndent(); + size = knownUids.size(); for (int i = 0; i < size; i++) { final int uid = knownUids.keyAt(i); - fout.print(" UID="); + 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) { @@ -1361,6 +1450,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { fout.println(); } + fout.decreaseIndent(); } } @@ -1432,7 +1522,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 @@ -1451,13 +1542,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; } @@ -1639,15 +1738,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } - private String getActiveSubscriberId() { - final TelephonyManager telephony = (TelephonyManager) mContext.getSystemService( - Context.TELEPHONY_SERVICE); - return telephony.getSubscriberId(); - } - private long getTotalBytes(NetworkTemplate template, long start, long end) { try { - return mNetworkStats.getSummaryForNetwork(template, start, end).getTotalBytes(); + return mNetworkStats.getNetworkTotalBytes(template, start, end); } catch (RuntimeException e) { Slog.w(TAG, "problem reading network stats: " + e); return 0; @@ -1703,6 +1796,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/net/NetworkStatsRecorder.java b/services/java/com/android/server/net/NetworkStatsRecorder.java index 290bd2c..540f606 100644 --- a/services/java/com/android/server/net/NetworkStatsRecorder.java +++ b/services/java/com/android/server/net/NetworkStatsRecorder.java @@ -221,6 +221,11 @@ public class NetworkStatsRecorder { if (mLastSnapshot != null) { mLastSnapshot = mLastSnapshot.withoutUid(uid); } + + final NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null; + if (complete != null) { + complete.removeUid(uid); + } } /** diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 13c0640..f7ba329 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -26,6 +26,7 @@ import static android.content.Intent.ACTION_UID_REMOVED; import static android.content.Intent.EXTRA_UID; import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE; +import static android.net.NetworkIdentity.COMBINE_SUBTYPE_ENABLED; import static android.net.NetworkStats.IFACE_ALL; import static android.net.NetworkStats.SET_ALL; import static android.net.NetworkStats.SET_DEFAULT; @@ -33,7 +34,7 @@ import static android.net.NetworkStats.SET_FOREGROUND; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static android.net.NetworkTemplate.buildTemplateMobileAll; -import static android.net.NetworkTemplate.buildTemplateWifi; +import static android.net.NetworkTemplate.buildTemplateWifiWildcard; import static android.net.TrafficStats.MB_IN_BYTES; import static android.provider.Settings.Secure.NETSTATS_DEV_BUCKET_DURATION; import static android.provider.Settings.Secure.NETSTATS_DEV_DELETE_AGE; @@ -69,6 +70,7 @@ import android.content.IntentFilter; import android.net.IConnectivityManager; import android.net.INetworkManagementEventObserver; import android.net.INetworkStatsService; +import android.net.INetworkStatsSession; import android.net.LinkProperties; import android.net.NetworkIdentity; import android.net.NetworkInfo; @@ -212,6 +214,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final HandlerThread mHandlerThread; private final Handler mHandler; + private boolean mSystemReady; + public NetworkStatsService( Context context, INetworkManagementService networkManager, IAlarmManager alarmManager) { this(context, networkManager, alarmManager, NtpTrustedTime.getInstance(context), @@ -250,6 +254,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } public void systemReady() { + mSystemReady = true; + if (!isBandwidthControlEnabled()) { Slog.w(TAG, "bandwidth controls disabled, unable to track stats"); return; @@ -300,7 +306,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // watch for networkType changes that aren't broadcast through // CONNECTIVITY_ACTION_IMMEDIATE above. - mTeleManager.listen(mPhoneListener, LISTEN_DATA_CONNECTION_STATE); + if (!COMBINE_SUBTYPE_ENABLED) { + mTeleManager.listen(mPhoneListener, LISTEN_DATA_CONNECTION_STATE); + } registerPollAlarmLocked(); registerGlobalAlert(); @@ -321,7 +329,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContext.unregisterReceiver(mRemovedReceiver); mContext.unregisterReceiver(mShutdownReceiver); - mTeleManager.listen(mPhoneListener, LISTEN_NONE); + if (!COMBINE_SUBTYPE_ENABLED) { + mTeleManager.listen(mPhoneListener, LISTEN_NONE); + } final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis(); @@ -336,6 +346,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mUidTagRecorder = null; mDevStatsCached = null; + + mSystemReady = false; } private void maybeUpgradeLegacyStatsLocked() { @@ -401,40 +413,75 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) { - return mDevStatsCached.getHistory(template, UID_ALL, SET_ALL, TAG_NONE, fields); - } + public INetworkStatsSession openSession() { + mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); - @Override - public NetworkStats getSummaryForNetwork(NetworkTemplate template, long start, long end) { - return mDevStatsCached.getSummary(template, start, end); - } + // return an IBinder which holds strong references to any loaded stats + // for its lifetime; when caller closes only weak references remain. - @Override - public NetworkStatsHistory getHistoryForUid( - NetworkTemplate template, int uid, int set, int tag, int fields) { - // TODO: transition to stats sessions to avoid WeakReferences - if (tag == TAG_NONE) { - return mUidRecorder.getOrLoadCompleteLocked().getHistory( - template, uid, set, tag, fields); - } else { - return mUidTagRecorder.getOrLoadCompleteLocked().getHistory( - template, uid, set, tag, fields); - } + return new INetworkStatsSession.Stub() { + private NetworkStatsCollection mUidComplete; + private NetworkStatsCollection mUidTagComplete; + + private NetworkStatsCollection getUidComplete() { + if (mUidComplete == null) { + mUidComplete = mUidRecorder.getOrLoadCompleteLocked(); + } + return mUidComplete; + } + + private NetworkStatsCollection getUidTagComplete() { + if (mUidTagComplete == null) { + mUidTagComplete = mUidTagRecorder.getOrLoadCompleteLocked(); + } + return mUidTagComplete; + } + + @Override + public NetworkStats getSummaryForNetwork( + NetworkTemplate template, long start, long end) { + return mDevStatsCached.getSummary(template, start, end); + } + + @Override + public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) { + return mDevStatsCached.getHistory(template, UID_ALL, SET_ALL, TAG_NONE, fields); + } + + @Override + public NetworkStats getSummaryForAllUid( + NetworkTemplate template, long start, long end, boolean includeTags) { + final NetworkStats stats = getUidComplete().getSummary(template, start, end); + if (includeTags) { + final NetworkStats tagStats = getUidTagComplete() + .getSummary(template, start, end); + stats.combineAllValues(tagStats); + } + return stats; + } + + @Override + public NetworkStatsHistory getHistoryForUid( + NetworkTemplate template, int uid, int set, int tag, int fields) { + if (tag == TAG_NONE) { + return getUidComplete().getHistory(template, uid, set, tag, fields); + } else { + return getUidTagComplete().getHistory(template, uid, set, tag, fields); + } + } + + @Override + public void close() { + mUidComplete = null; + mUidTagComplete = null; + } + }; } @Override - public NetworkStats getSummaryForAllUid( - NetworkTemplate template, long start, long end, boolean includeTags) { - // TODO: transition to stats sessions to avoid WeakReferences - final NetworkStats stats = mUidRecorder.getOrLoadCompleteLocked().getSummary( - template, start, end); - if (includeTags) { - final NetworkStats tagStats = mUidTagRecorder.getOrLoadCompleteLocked().getSummary( - template, start, end); - stats.combineAllValues(tagStats); - } - return stats; + public long getNetworkTotalBytes(NetworkTemplate template, long start, long end) { + mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); + return mDevStatsCached.getSummary(template, start, end).getTotalBytes(); } @Override @@ -649,6 +696,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * {@link NetworkIdentitySet}. */ private void updateIfacesLocked() { + if (!mSystemReady) return; if (LOGV) Slog.v(TAG, "updateIfacesLocked()"); // take one last stats snapshot before updating iface mapping. this @@ -737,7 +785,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * {@link NetworkStatsHistory}. */ private void performPollLocked(int flags) { + if (!mSystemReady) return; if (LOGV) Slog.v(TAG, "performPollLocked(flags=0x" + Integer.toHexString(flags) + ")"); + final long startRealtime = SystemClock.elapsedRealtime(); final boolean persistNetwork = (flags & FLAG_PERSIST_NETWORK) != 0; @@ -822,7 +872,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { trustedTime); // collect wifi sample - template = buildTemplateWifi(); + template = buildTemplateWifiWildcard(); devTotal = mDevRecorder.getTotalSinceBootLocked(template); xtTotal = new NetworkStats.Entry(); uidTotal = mUidRecorder.getTotalSinceBootLocked(template); diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java index e471a3f..1593707 100644 --- a/services/java/com/android/server/pm/PackageManagerService.java +++ b/services/java/com/android/server/pm/PackageManagerService.java @@ -20,6 +20,10 @@ 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_DISABLED_USER; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; +import static android.content.pm.PackageManager.ENFORCEMENT_DEFAULT; +import static android.content.pm.PackageManager.ENFORCEMENT_YES; +import static android.Manifest.permission.READ_EXTERNAL_STORAGE; +import static android.Manifest.permission.GRANT_REVOKE_PERMISSIONS; import static libcore.io.OsConstants.S_ISLNK; import com.android.internal.app.IMediaContainerService; @@ -130,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; @@ -391,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; @@ -400,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(); @@ -625,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; @@ -669,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 @@ -731,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; @@ -807,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); } } @@ -908,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, @@ -1074,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); } } } @@ -1132,6 +1147,27 @@ public class PackageManagerService extends IPackageManager.Stub { ? (UPDATE_PERMISSIONS_REPLACE_PKG|UPDATE_PERMISSIONS_REPLACE_ALL) : 0)); + // Verify that all of the preferred activity components actually + // exist. It is possible for applications to be updated and at + // that point remove a previously declared activity component that + // had been set as a preferred activity. We try to clean this up + // the next time we encounter that preferred activity, but it is + // possible for the user flow to never be able to return to that + // situation so here we do a sanity check to make sure we haven't + // left any junk around. + ArrayList<PreferredActivity> removed = new ArrayList<PreferredActivity>(); + for (PreferredActivity pa : mSettings.mPreferredActivities.filterSet()) { + if (mActivities.mActivities.get(pa.mPref.mComponent) == null) { + removed.add(pa); + } + } + for (int i=0; i<removed.size(); i++) { + PreferredActivity pa = removed.get(i); + Slog.w(TAG, "Removing dangling preferred activity: " + + pa.mPref.mComponent); + mSettings.mPreferredActivities.removeFilter(pa); + } + // can downgrade to reader mSettings.writeLPr(); @@ -1155,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; @@ -1209,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()) { @@ -1473,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; @@ -1526,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; } } @@ -1552,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. @@ -1627,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; @@ -1654,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); @@ -1670,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; @@ -1733,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; @@ -1752,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; @@ -1838,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); @@ -1851,6 +1932,9 @@ public class PackageManagerService extends IPackageManager.Stub { return PackageManager.PERMISSION_GRANTED; } } + if (!isPermissionEnforcedLocked(permName)) { + return PackageManager.PERMISSION_GRANTED; + } } return PackageManager.PERMISSION_DENIED; } @@ -1869,6 +1953,9 @@ public class PackageManagerService extends IPackageManager.Stub { return PackageManager.PERMISSION_GRANTED; } } + if (!isPermissionEnforcedLocked(permName)) { + return PackageManager.PERMISSION_GRANTED; + } } return PackageManager.PERMISSION_DENIED; } @@ -1966,7 +2053,7 @@ public class PackageManagerService extends IPackageManager.Stub { if (!async) { mSettings.writeLPr(); } else { - scheduleWriteSettingsLocked(); + scheduleWriteSettingsLocked(); } } return added; @@ -2201,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) { @@ -2232,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; } @@ -2243,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) { @@ -2252,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 @@ -2286,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) { @@ -2295,31 +2385,40 @@ public class PackageManagerService extends IPackageManager.Stub { Log.v(TAG, " null"); } } - if (ai != null) { - for (int j=0; j<N; j++) { - final ResolveInfo ri = query.get(j); - if (!ri.activityInfo.applicationInfo.packageName - .equals(ai.applicationInfo.packageName)) { - continue; - } - if (!ri.activityInfo.name.equals(ai.name)) { - continue; - } - - // Okay we found a previously set preferred app. - // If the result set is different from when this - // was created, we need to clear it and re-ask the - // user their preference. - if (!pa.mPref.sameSet(query, priority)) { - Slog.i(TAG, "Result set changed, dropping preferred activity for " - + intent + " type " + resolvedType); - mSettings.mPreferredActivities.removeFilter(pa); - return null; - } + if (ai == null) { + // This previously registered preferred activity + // component is no longer known. Most likely an update + // to the app was installed and in the new version this + // component no longer exists. Clean it up by removing + // it from the preferred activities list, and skip it. + Slog.w(TAG, "Removing dangling preferred activity: " + + pa.mPref.mComponent); + mSettings.mPreferredActivities.removeFilter(pa); + continue; + } + for (int j=0; j<N; j++) { + final ResolveInfo ri = query.get(j); + if (!ri.activityInfo.applicationInfo.packageName + .equals(ai.applicationInfo.packageName)) { + continue; + } + if (!ri.activityInfo.name.equals(ai.name)) { + continue; + } - // Yay! - return ri; + // Okay we found a previously set preferred app. + // If the result set is different from when this + // was created, we need to clear it and re-ask the + // user their preference. + if (!pa.mPref.sameSet(query, priority)) { + Slog.i(TAG, "Result set changed, dropping preferred activity for " + + intent + " type " + resolvedType); + mSettings.mPreferredActivities.removeFilter(pa); + return null; } + + // Yay! + return ri; } } } @@ -2327,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) { @@ -2339,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; @@ -2352,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); @@ -2412,7 +2515,7 @@ public class PackageManagerService extends IPackageManager.Stub { ri = resolveIntent( sintent, specificTypes != null ? specificTypes[i] : null, - flags); + flags, userId); if (ri == null) { continue; } @@ -2423,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; } @@ -2532,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) { @@ -2542,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; @@ -2555,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, @@ -2577,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) { @@ -2587,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; @@ -2600,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; } @@ -2629,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) { @@ -2649,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); } } @@ -2671,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; @@ -2688,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); } } @@ -2725,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)); } } } @@ -2739,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; } } @@ -2762,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)); } } } @@ -2784,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)); } } } @@ -3442,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)) { @@ -3549,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: " @@ -3570,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) { @@ -3612,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(); @@ -4036,8 +4171,6 @@ public class PackageManagerService extends IPackageManager.Stub { // writer synchronized (mPackages) { - clearPackagePreferredActivitiesLPw(pkg.packageName); - mPackages.remove(pkg.applicationInfo.packageName); if (pkg.mPath != null) { mAppDirs.remove(pkg.mPath); @@ -4442,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; } @@ -4471,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) { @@ -4536,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; @@ -4544,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; @@ -4557,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; @@ -4567,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; } @@ -4622,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; } @@ -4651,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) { @@ -4711,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; @@ -4719,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; @@ -4732,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; @@ -4743,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; } @@ -4835,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) { } } @@ -4994,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); } } @@ -5597,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 " @@ -7024,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. @@ -7061,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)); } } } @@ -7100,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); } @@ -7118,16 +7279,7 @@ public class PackageManagerService extends IPackageManager.Stub { mSettings.updateSharedUserPermsLPw(deletedPs, mGlobalGids); } } - } - // remove from preferred activities. - ArrayList<PreferredActivity> removed = new ArrayList<PreferredActivity>(); - for (PreferredActivity pa : mSettings.mPreferredActivities.filterSet()) { - if (pa.mPref.mComponent.getPackageName().equals(deletedPs.name)) { - removed.add(pa); - } - } - for (PreferredActivity pa : removed) { - mSettings.mPreferredActivities.removeFilter(pa); + clearPackagePreferredActivitiesLPw(deletedPs.name); } } // can downgrade to reader @@ -7287,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 @@ -7318,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; @@ -7350,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); @@ -7364,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 { @@ -7382,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; @@ -7400,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: " @@ -7569,17 +7725,27 @@ public class PackageManagerService extends IPackageManager.Stub { android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null); } + ArrayList<PreferredActivity> removed = null; Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator(); String action = filter.getAction(0); String category = filter.getCategory(0); while (it.hasNext()) { PreferredActivity pa = it.next(); if (pa.getAction(0).equals(action) && pa.getCategory(0).equals(category)) { - it.remove(); - Log.i(TAG, "Removed preferred activity " + pa.mPref.mComponent + ":"); + if (removed == null) { + removed = new ArrayList<PreferredActivity>(); + } + removed.add(pa); + Log.i(TAG, "Removing preferred activity " + pa.mPref.mComponent + ":"); filter.dump(new LogPrinter(Log.INFO, TAG), " "); } } + if (removed != null) { + for (int i=0; i<removed.size(); i++) { + PreferredActivity pa = removed.get(i); + mSettings.mPreferredActivities.removeFilter(pa); + } + } addPreferredActivity(filter, match, set, activity); } } @@ -7611,16 +7777,25 @@ public class PackageManagerService extends IPackageManager.Stub { } boolean clearPackagePreferredActivitiesLPw(String packageName) { - boolean changed = false; + ArrayList<PreferredActivity> removed = null; Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator(); while (it.hasNext()) { PreferredActivity pa = it.next(); if (pa.mPref.mComponent.getPackageName().equals(packageName)) { - it.remove(); - changed = true; + if (removed == null) { + removed = new ArrayList<PreferredActivity>(); + } + removed.add(pa); } } - return changed; + if (removed != null) { + for (int i=0; i<removed.size(); i++) { + PreferredActivity pa = removed.get(i); + mSettings.mPreferredActivities.removeFilter(pa); + } + return true; + } + return false; } public int getPreferredActivities(List<IntentFilter> outFilters, @@ -7647,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 @@ -7671,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); @@ -7690,35 +7870,47 @@ 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. + PackageParser.Package pkg = pkgSetting.pkg; + if (pkg == null || !pkg.hasComponentClassName(className)) { + if (pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN) { + throw new IllegalArgumentException("Component class " + className + + " does not exist in " + packageName); + } else { + Slog.w(TAG, "Failed setComponentEnabledSetting: component class " + + className + " does not exist in " + packageName); + } + } 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; @@ -7727,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) { @@ -7776,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); } } } @@ -7800,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); } } @@ -8014,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(")"); } @@ -8279,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; } @@ -8332,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); } } @@ -8756,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; } @@ -8765,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( @@ -8783,7 +9011,74 @@ 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 + public void setPermissionEnforcement(String permission, int enforcement) { + mContext.enforceCallingOrSelfPermission(GRANT_REVOKE_PERMISSIONS, null); + if (READ_EXTERNAL_STORAGE.equals(permission)) { + synchronized (mPackages) { + 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 { + throw new IllegalArgumentException("No selective enforcement for " + permission); + } + } + + @Override + public int getPermissionEnforcement(String permission) { + mContext.enforceCallingOrSelfPermission(GRANT_REVOKE_PERMISSIONS, null); + if (READ_EXTERNAL_STORAGE.equals(permission)) { + synchronized (mPackages) { + return mSettings.mReadExternalStorageEnforcement; + } + } else { + throw new IllegalArgumentException("No selective enforcement for " + permission); + } + } + + private boolean isPermissionEnforcedLocked(String permission) { + if (READ_EXTERNAL_STORAGE.equals(permission)) { + switch (mSettings.mReadExternalStorageEnforcement) { + case ENFORCEMENT_DEFAULT: + return false; + case ENFORCEMENT_YES: + return true; + } + } + + return true; } } 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 5da6ac9..bb7f4fc 100644 --- a/services/java/com/android/server/pm/Settings.java +++ b/services/java/com/android/server/pm/Settings.java @@ -20,6 +20,7 @@ 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_DISABLED_USER; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; +import static android.content.pm.PackageManager.ENFORCEMENT_DEFAULT; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.JournaledFile; @@ -31,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; @@ -39,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; @@ -62,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; @@ -74,6 +80,20 @@ final class Settings { private static final boolean DEBUG_STOPPED = false; + 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; @@ -91,6 +111,8 @@ final class Settings { int mInternalSdkPlatform; int mExternalSdkPlatform; + int mReadExternalStorageEnforcement = ENFORCEMENT_DEFAULT; + /** Device identity for the purpose of package verification. */ private VerifierDeviceIdentity mVerifierDeviceIdentity; @@ -147,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, @@ -248,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; } @@ -257,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, @@ -266,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; @@ -317,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) { @@ -329,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 @@ -372,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; @@ -398,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); @@ -414,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; @@ -444,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 @@ -469,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); } @@ -496,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!"); @@ -506,7 +549,7 @@ final class Settings { sharedUser.packages.add(p); p.sharedUser = sharedUser; - p.userId = sharedUser.userId; + p.appId = sharedUser.userId; } } @@ -571,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; @@ -585,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); @@ -652,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(); @@ -705,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); @@ -714,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 @@ -751,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; } @@ -790,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 { @@ -811,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); @@ -864,13 +1132,20 @@ final class Settings { serializer.attribute(null, "internal", Integer.toString(mInternalSdkPlatform)); serializer.attribute(null, "external", Integer.toString(mExternalSdkPlatform)); serializer.endTag(null, "last-platform-version"); - + if (mVerifierDeviceIdentity != null) { serializer.startTag(null, "verifier"); serializer.attribute(null, "device", mVerifierDeviceIdentity.toString()); serializer.endTag(null, "verifier"); } + if (mReadExternalStorageEnforcement != ENFORCEMENT_DEFAULT) { + serializer.startTag(null, TAG_READ_EXTERNAL_STORAGE); + serializer.attribute( + null, ATTR_ENFORCEMENT, Integer.toString(mReadExternalStorageEnforcement)); + serializer.endTag(null, TAG_READ_EXTERNAL_STORAGE); + } + serializer.startTag(null, "permission-trees"); for (BasePermission bp : mPermissionTrees.values()) { writePermissionLPr(serializer, bp); @@ -893,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"); @@ -918,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"); } } @@ -1003,8 +1278,7 @@ final class Settings { |FileUtils.S_IRGRP|FileUtils.S_IWGRP, -1, -1); - writeStoppedLPr(); - + writeAllUsersPackageRestrictionsLPr(); return; } catch(XmlPullParserException e) { @@ -1017,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(); @@ -1026,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); } @@ -1042,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) { @@ -1059,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); } } } @@ -1072,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); } @@ -1089,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"); } @@ -1114,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"); } @@ -1146,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)); @@ -1167,7 +1421,7 @@ final class Settings { } } } - serializer.endTag(null, "item"); + serializer.endTag(null, TAG_ITEM); } } @@ -1185,7 +1439,7 @@ final class Settings { return ret; } - boolean readLPw() { + boolean readLPw(List<UserInfo> users) { FileInputStream str = null; if (mBackupSettingsFilename.exists()) { try { @@ -1260,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); } @@ -1291,6 +1545,12 @@ final class Settings { Slog.w(PackageManagerService.TAG, "Discard invalid verifier device id: " + e.getMessage()); } + } else if (TAG_READ_EXTERNAL_STORAGE.equals(tagName)) { + final String enforcement = parser.getAttributeValue(null, ATTR_ENFORCEMENT); + try { + mReadExternalStorageEnforcement = Integer.parseInt(enforcement); + } catch (NumberFormatException e) { + } } else { Slog.w(PackageManagerService.TAG, "Unknown element under <packages>: " + parser.getName()); @@ -1347,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"); @@ -1388,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) { @@ -1425,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"); @@ -1478,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; @@ -1522,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"); @@ -1653,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 @@ -1672,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")) { @@ -1692,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")) { @@ -1712,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 @@ -1723,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" @@ -1740,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 @@ -1751,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" @@ -1768,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"))) { @@ -1840,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 { @@ -1868,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); @@ -1886,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... @@ -1921,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; @@ -1960,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) { @@ -1997,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) { @@ -2077,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); @@ -2150,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) { @@ -2215,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="); @@ -2225,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..1bd15f6 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; @@ -59,6 +60,7 @@ import java.util.LinkedList; import java.util.List; import java.util.HashMap; import java.util.Map; +import java.util.Scanner; /** * UsbDeviceManager manages USB state in device mode. @@ -80,6 +82,8 @@ public class UsbDeviceManager { "/sys/class/android_usb/android0/f_mass_storage/lun/file"; private static final String RNDIS_ETH_ADDR_PATH = "/sys/class/android_usb/android0/f_rndis/ethaddr"; + private static final String AUDIO_SOURCE_PCM_PATH = + "/sys/class/android_usb/android0/f_audio_source/pcm"; private static final int MSG_UPDATE_STATE = 0; private static final int MSG_ENABLE_ADB = 1; @@ -104,6 +108,7 @@ public class UsbDeviceManager { private final boolean mHasUsbAccessory; private boolean mUseUsbNotification; private boolean mAdbEnabled; + private boolean mAudioSourceEnabled; private Map<String, List<Pair<String, String>>> mOemModeMap; private class AdbSettingsObserver extends ContentObserver { @@ -206,6 +211,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 +230,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]; @@ -284,6 +295,8 @@ public class UsbDeviceManager { String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim(); updateState(state); mAdbEnabled = containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ADB); + mAudioSourceEnabled = containsFunction(mCurrentFunctions, + UsbManager.USB_FUNCTION_AUDIO_SOURCE); // Upgrade step for previous versions that used persist.service.adb.enable String value = SystemProperties.get("persist.service.adb.enable", ""); @@ -365,11 +378,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; @@ -501,6 +510,28 @@ public class UsbDeviceManager { mContext.sendStickyBroadcast(intent); } + private void updateAudioSourceFunction(boolean enabled) { + // send a sticky broadcast containing current USB state + Intent intent = new Intent(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG); + intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + intent.putExtra("state", (enabled ? 1 : 0)); + if (enabled) { + try { + Scanner scanner = new Scanner(new File(AUDIO_SOURCE_PCM_PATH)); + int card = scanner.nextInt(); + int device = scanner.nextInt(); + intent.putExtra("card", card); + intent.putExtra("device", device); + } catch (FileNotFoundException e) { + Slog.e(TAG, "could not open audio source PCM file", e); + } + } + + mContext.sendStickyBroadcast(intent); + mAudioSourceEnabled = enabled; + } + @Override public void handleMessage(Message msg) { switch (msg.what) { @@ -520,6 +551,11 @@ public class UsbDeviceManager { } if (mBootCompleted) { updateUsbState(); + boolean audioSourceEnabled = containsFunction(mCurrentFunctions, + UsbManager.USB_FUNCTION_AUDIO_SOURCE); + if (audioSourceEnabled != mAudioSourceEnabled) { + updateAudioSourceFunction(audioSourceEnabled); + } } break; case MSG_ENABLE_ADB: @@ -540,6 +576,7 @@ public class UsbDeviceManager { if (mCurrentAccessory != null) { mSettingsManager.accessoryAttached(mCurrentAccessory); } + updateAudioSourceFunction(mAudioSourceEnabled); break; } } @@ -588,6 +625,7 @@ public class UsbDeviceManager { notification.defaults = 0; // please be quiet notification.sound = null; notification.vibrate = null; + notification.priority = Notification.PRIORITY_MIN; Intent intent = Intent.makeRestartActivityTask( new ComponentName("com.android.settings", @@ -621,6 +659,7 @@ public class UsbDeviceManager { notification.defaults = 0; // please be quiet notification.sound = null; notification.vibrate = null; + notification.priority = Notification.PRIORITY_MIN; Intent intent = Intent.makeRestartActivityTask( new ComponentName("com.android.settings", diff --git a/services/java/com/android/server/wm/AppWindowAnimator.java b/services/java/com/android/server/wm/AppWindowAnimator.java new file mode 100644 index 0000000..c3b5465 --- /dev/null +++ b/services/java/com/android/server/wm/AppWindowAnimator.java @@ -0,0 +1,301 @@ +// Copyright 2012 Google Inc. All Rights Reserved. + +package com.android.server.wm; + +import android.graphics.Matrix; +import android.util.Slog; +import android.view.Surface; +import android.view.WindowManagerPolicy; +import android.view.animation.Animation; +import android.view.animation.Transformation; + +import java.io.PrintWriter; + +/** + * + */ +public class AppWindowAnimator { + + final AppWindowToken mAppToken; + final WindowManagerService mService; + final WindowAnimator mAnimator; + + boolean animating; + Animation animation; + boolean animInitialized; + boolean hasTransformation; + final Transformation transformation = new Transformation(); + + // Have we been asked to have this token keep the screen frozen? + // Protect with mAnimator. + boolean freezingScreen; + + // Offset to the window of all layers in the token, for use by + // AppWindowToken animations. + int animLayerAdjustment; + + // Special surface for thumbnail animation. + Surface thumbnail; + int thumbnailTransactionSeq; + int thumbnailX; + int thumbnailY; + int thumbnailLayer; + Animation thumbnailAnimation; + final Transformation thumbnailTransformation = new Transformation(); + + public AppWindowAnimator(final WindowManagerService service, final AppWindowToken atoken) { + mService = service; + mAppToken = atoken; + mAnimator = service.mAnimator; + } + + 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(mService.mTransitionAnimationScale); + int zorder = anim.getZAdjustment(); + int adj = 0; + if (zorder == Animation.ZORDER_TOP) { + adj = WindowManagerService.TYPE_LAYER_OFFSET; + } else if (zorder == Animation.ZORDER_BOTTOM) { + adj = -WindowManagerService.TYPE_LAYER_OFFSET; + } + + if (animLayerAdjustment != adj) { + animLayerAdjustment = adj; + updateLayers(); + } + // Start out animation gone if window is gone, or visible if window is visible. + transformation.clear(); + transformation.setAlpha(mAppToken.reportedVisible ? 1 : 0); + hasTransformation = true; + } + + public void setDummyAnimation() { + if (animation == null) { + if (WindowManagerService.localLOGV) Slog.v( + WindowManagerService.TAG, "Setting dummy animation in " + this); + animation = WindowManagerService.sDummyAnimation; + animInitialized = false; + } + } + + public void clearAnimation() { + 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 = mAppToken.allAppWindows.size(); + final int adj = animLayerAdjustment; + thumbnailLayer = -1; + for (int i=0; i<N; i++) { + final WindowState w = mAppToken.allAppWindows.get(i); + final WindowStateAnimator winAnimator = w.mWinAnimator; + winAnimator.mAnimLayer = w.mLayer + adj; + if (winAnimator.mAnimLayer > thumbnailLayer) { + thumbnailLayer = winAnimator.mAnimLayer; + } + if (WindowManagerService.DEBUG_LAYERS) Slog.v(WindowManagerService.TAG, "Updating layer " + w + ": " + + winAnimator.mAnimLayer); + if (w == mService.mInputMethodTarget && !mService.mInputMethodTargetWaitingAnim) { + mService.setInputMethodAnimLayerAdjustment(adj); + } + if (w == mService.mWallpaperTarget && mService.mLowerWallpaperTarget == null) { + mService.setWallpaperAnimLayerAdjustmentLocked(adj); + } + } + } + + private void stepThumbnailAnimation(long currentTime) { + thumbnailTransformation.clear(); + thumbnailAnimation.getTransformation(currentTime, thumbnailTransformation); + thumbnailTransformation.getMatrix().preTranslate(thumbnailX, thumbnailY); + final boolean screenAnimation = mAnimator.mScreenRotationAnimation != null + && mAnimator.mScreenRotationAnimation.isAnimating(); + if (screenAnimation) { + thumbnailTransformation.postCompose( + mAnimator.mScreenRotationAnimation.getEnterTransformation()); + } + // cache often used attributes locally + final float tmpFloats[] = mService.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) { + return false; + } + transformation.clear(); + final boolean more = animation.getTransformation(currentTime, transformation); + if (WindowManagerService.DEBUG_ANIM) Slog.v( + WindowManagerService.TAG, "Stepped animation in " + this + + ": more=" + more + ", xform=" + transformation); + if (!more) { + animation = null; + clearThumbnail(); + if (WindowManagerService.DEBUG_ANIM) Slog.v( + WindowManagerService.TAG, "Finished animation in " + this + + " @ " + currentTime); + } + hasTransformation = more; + return more; + } + + // This must be called while inside a transaction. + boolean stepAnimationLocked(long currentTime, int dw, int dh) { + if (mService.okToDisplay()) { + // We will run animations as long as the display isn't frozen. + + if (animation == WindowManagerService.sDummyAnimation) { + // This guy is going to animate, but not yet. For now count + // it as not animating for purposes of scheduling transactions; + // when it is really time to animate, this will be set to + // a real animation and the next call will execute normally. + return false; + } + + if ((mAppToken.allDrawn || animating || mAppToken.startingDisplayed) + && animation != null) { + if (!animating) { + if (WindowManagerService.DEBUG_ANIM) Slog.v( + WindowManagerService.TAG, "Starting animation in " + this + + " @ " + currentTime + ": dw=" + dw + " dh=" + dh + + " scale=" + mService.mTransitionAnimationScale + + " allDrawn=" + mAppToken.allDrawn + " animating=" + animating); + if (!animInitialized) { + animation.initialize(dw, dh, dw, dh); + } + animation.setStartTime(currentTime); + animating = true; + if (thumbnail != null) { + thumbnail.show(); + thumbnailAnimation.setStartTime(currentTime); + } + } + if (stepAnimation(currentTime)) { + // animation isn't over, step any thumbnail and that's + // it for now. + if (thumbnail != null) { + stepThumbnailAnimation(currentTime); + } + return true; + } + } + } else if (animation != null) { + // If the display is frozen, and there is a pending animation, + // clear it and make sure we run the cleanup code. + animating = true; + animation = null; + } + + hasTransformation = false; + + if (!animating && animation == null) { + return false; + } + + mAnimator.mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM; + if (WindowManagerService.DEBUG_LAYOUT_REPEATS) { + mService.debugLayoutRepeats("AppWindowToken", mAnimator.mPendingLayoutChanges); + } + + clearAnimation(); + animating = false; + if (animLayerAdjustment != 0) { + animLayerAdjustment = 0; + updateLayers(); + } + if (mService.mInputMethodTarget != null + && mService.mInputMethodTarget.mAppToken == mAppToken) { + mService.moveInputMethodWindowsIfNeededLocked(true); + } + + if (WindowManagerService.DEBUG_ANIM) Slog.v( + WindowManagerService.TAG, "Animation done in " + this + + ": reportedVisible=" + mAppToken.reportedVisible); + + transformation.clear(); + + final int N = mAppToken.windows.size(); + for (int i=0; i<N; i++) { + mAppToken.windows.get(i).mWinAnimator.finishExit(); + } + mAppToken.updateReportedVisibilityLocked(); + + return false; + } + + boolean showAllWindowsLocked() { + boolean isAnimating = false; + final int NW = mAppToken.allAppWindows.size(); + for (int i=0; i<NW; i++) { + WindowStateAnimator winAnimator = mAppToken.allAppWindows.get(i).mWinAnimator; + if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, + "performing show on: " + winAnimator); + winAnimator.performShowLocked(); + isAnimating |= winAnimator.isAnimating(); + } + return isAnimating; + } + + void dump(PrintWriter pw, String prefix) { + if (freezingScreen) { + pw.print(prefix); pw.print(" freezingScreen="); pw.println(freezingScreen); + } + if (animating || animation != null) { + pw.print(prefix); pw.print("animating="); pw.print(animating); + pw.print(" animation="); pw.println(animation); + } + if (hasTransformation) { + pw.print(prefix); pw.print("XForm: "); + transformation.printShortString(pw); + pw.println(); + } + if (animLayerAdjustment != 0) { + pw.print(prefix); pw.print("animLayerAdjustment="); pw.println(animLayerAdjustment); + } + 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()); + } + } +} diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/java/com/android/server/wm/AppWindowToken.java index 0e3d20a..bf35154 100644 --- a/services/java/com/android/server/wm/AppWindowToken.java +++ b/services/java/com/android/server/wm/AppWindowToken.java @@ -18,6 +18,7 @@ package com.android.server.wm; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; +import com.android.server.input.InputApplicationHandle; import com.android.server.wm.WindowManagerService.H; import android.content.pm.ActivityInfo; @@ -27,8 +28,6 @@ import android.util.Slog; import android.view.IApplicationToken; import android.view.View; import android.view.WindowManager; -import android.view.animation.Animation; -import android.view.animation.Transformation; import java.io.PrintWriter; import java.util.ArrayList; @@ -44,18 +43,22 @@ class AppWindowToken extends WindowToken { // All of the windows and child windows that are included in this // application token. Note this list is NOT sorted! final ArrayList<WindowState> allAppWindows = new ArrayList<WindowState>(); + final AppWindowAnimator mAppAnimator; + + final WindowAnimator mAnimator; 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; @@ -83,18 +86,6 @@ class AppWindowToken extends WindowToken { // Set to true when the token has been removed from the window mgr. boolean removed; - // Have we been asked to have this token keep the screen frozen? - boolean freezingScreen; - - boolean animating; - Animation animation; - boolean hasTransformation; - final Transformation transformation = new Transformation(); - - // Offset to the window of all layers in the token, for use by - // AppWindowToken animations. - int animLayerAdjustment; - // Information about an application starting window if displayed. StartingData startingData; WindowState startingWindow; @@ -112,60 +103,8 @@ class AppWindowToken extends WindowToken { appWindowToken = this; appToken = _token; mInputApplicationHandle = new InputApplicationHandle(this); - lastTransactionSequence = service.mTransactionSequence-1; - } - - public void setAnimation(Animation anim) { - if (WindowManagerService.localLOGV) Slog.v( - WindowManagerService.TAG, "Setting animation in " + this + ": " + anim); - animation = anim; - animating = false; - anim.restrictDuration(WindowManagerService.MAX_ANIMATION_DURATION); - anim.scaleCurrentDuration(service.mTransitionAnimationScale); - int zorder = anim.getZAdjustment(); - int adj = 0; - if (zorder == Animation.ZORDER_TOP) { - adj = WindowManagerService.TYPE_LAYER_OFFSET; - } else if (zorder == Animation.ZORDER_BOTTOM) { - adj = -WindowManagerService.TYPE_LAYER_OFFSET; - } - - if (animLayerAdjustment != adj) { - animLayerAdjustment = adj; - updateLayers(); - } - } - - public void setDummyAnimation() { - if (animation == null) { - if (WindowManagerService.localLOGV) Slog.v( - WindowManagerService.TAG, "Setting dummy animation in " + this); - animation = WindowManagerService.sDummyAnimation; - } - } - - public void clearAnimation() { - if (animation != null) { - animation = null; - animating = true; - } - } - - void updateLayers() { - final int N = allAppWindows.size(); - final int adj = animLayerAdjustment; - for (int i=0; i<N; i++) { - WindowState w = allAppWindows.get(i); - w.mAnimLayer = w.mLayer + adj; - if (WindowManagerService.DEBUG_LAYERS) Slog.v(WindowManagerService.TAG, "Updating layer " + w + ": " - + w.mAnimLayer); - if (w == service.mInputMethodTarget && !service.mInputMethodTargetWaitingAnim) { - service.setInputMethodAnimLayerAdjustment(adj); - } - if (w == service.mWallpaperTarget && service.mLowerWallpaperTarget == null) { - service.setWallpaperAnimLayerAdjustmentLocked(adj); - } - } + mAnimator = service.mAnimator; + mAppAnimator = new AppWindowAnimator(_service, this); } void sendAppVisibilityToClients() { @@ -185,94 +124,6 @@ class AppWindowToken extends WindowToken { } } - void showAllWindowsLocked() { - 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(); - } - } - - // This must be called while inside a transaction. - boolean stepAnimationLocked(long currentTime, int dw, int dh) { - if (!service.mDisplayFrozen && service.mPolicy.isScreenOnFully()) { - // We will run animations as long as the display isn't frozen. - - if (animation == WindowManagerService.sDummyAnimation) { - // This guy is going to animate, but not yet. For now count - // it as not animating for purposes of scheduling transactions; - // when it is really time to animate, this will be set to - // a real animation and the next call will execute normally. - return false; - } - - if ((allDrawn || animating || startingDisplayed) && animation != null) { - if (!animating) { - if (WindowManagerService.DEBUG_ANIM) Slog.v( - WindowManagerService.TAG, "Starting animation in " + this + - " @ " + currentTime + ": dw=" + dw + " dh=" + dh - + " scale=" + service.mTransitionAnimationScale - + " allDrawn=" + allDrawn + " animating=" + animating); - animation.initialize(dw, dh, dw, dh); - animation.setStartTime(currentTime); - animating = true; - } - transformation.clear(); - final boolean more = animation.getTransformation( - currentTime, transformation); - if (WindowManagerService.DEBUG_ANIM) Slog.v( - WindowManagerService.TAG, "Stepped animation in " + this + - ": more=" + more + ", xform=" + transformation); - if (more) { - // we're done! - hasTransformation = true; - return true; - } - if (WindowManagerService.DEBUG_ANIM) Slog.v( - WindowManagerService.TAG, "Finished animation in " + this + - " @ " + currentTime); - animation = null; - } - } else if (animation != null) { - // If the display is frozen, and there is a pending animation, - // clear it and make sure we run the cleanup code. - animating = true; - animation = null; - } - - hasTransformation = false; - - if (!animating) { - return false; - } - - clearAnimation(); - animating = false; - if (animLayerAdjustment != 0) { - animLayerAdjustment = 0; - updateLayers(); - } - if (service.mInputMethodTarget != null && service.mInputMethodTarget.mAppToken == this) { - service.moveInputMethodWindowsIfNeededLocked(true); - } - - if (WindowManagerService.DEBUG_ANIM) Slog.v( - WindowManagerService.TAG, "Animation done in " + this - + ": reportedVisible=" + reportedVisible); - - transformation.clear(); - - final int N = windows.size(); - for (int i=0; i<N; i++) { - windows.get(i).finishExit(); - } - updateReportedVisibilityLocked(); - - return false; - } - void updateReportedVisibilityLocked() { if (appToken == null) { return; @@ -283,7 +134,8 @@ class AppWindowToken extends WindowToken { int numDrawn = 0; boolean nowGone = true; - if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "Update reported visibility: " + this); + if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, + "Update reported visibility: " + this); final int N = allAppWindows.size(); for (int i=0; i<N; i++) { WindowState win = allAppWindows.get(i); @@ -296,27 +148,26 @@ 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 + Slog.v(WindowManagerService.TAG, "Not displayed: s=" + win.mWinAnimator.mSurface + " pv=" + win.mPolicyVisibility - + " dp=" + win.mDrawPending - + " cdp=" + win.mCommitDrawPending + + " mDrawState=" + win.mWinAnimator.mDrawState + " ah=" + win.mAttachedHidden + " 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; } } @@ -369,6 +220,7 @@ class AppWindowToken extends WindowToken { return null; } + @Override void dump(PrintWriter pw, String prefix) { super.dump(pw, prefix); if (appToken != null) { @@ -385,9 +237,8 @@ class AppWindowToken extends WindowToken { pw.print(" willBeHidden="); pw.print(willBeHidden); pw.print(" reportedDrawn="); pw.print(reportedDrawn); pw.print(" reportedVisible="); pw.println(reportedVisible); - if (paused || freezingScreen) { - pw.print(prefix); pw.print("paused="); pw.print(paused); - pw.print(" freezingScreen="); pw.println(freezingScreen); + if (paused) { + pw.print(prefix); pw.print("paused="); pw.println(paused); } if (numInterestingWindows != 0 || numDrawnWindows != 0 || inPendingTransaction || allDrawn) { @@ -397,18 +248,6 @@ class AppWindowToken extends WindowToken { pw.print(" inPendingTransaction="); pw.print(inPendingTransaction); pw.print(" allDrawn="); pw.println(allDrawn); } - if (animating || animation != null) { - pw.print(prefix); pw.print("animating="); pw.print(animating); - pw.print(" animation="); pw.println(animation); - } - if (hasTransformation) { - pw.print(prefix); pw.print("XForm: "); - transformation.printShortString(pw); - pw.println(); - } - if (animLayerAdjustment != 0) { - pw.print(prefix); pw.print("animLayerAdjustment="); pw.println(animLayerAdjustment); - } if (startingData != null || removed || firstWindowDrawn) { pw.print(prefix); pw.print("startingData="); pw.print(startingData); pw.print(" removed="); pw.print(removed); @@ -434,4 +273,4 @@ class AppWindowToken extends WindowToken { } return stringName; } -}
\ No newline at end of file +} diff --git a/services/java/com/android/server/wm/BlackFrame.java b/services/java/com/android/server/wm/BlackFrame.java index 10e294b..c915932 100644 --- a/services/java/com/android/server/wm/BlackFrame.java +++ b/services/java/com/android/server/wm/BlackFrame.java @@ -16,6 +16,8 @@ package com.android.server.wm; +import java.io.PrintWriter; + import android.graphics.Matrix; import android.graphics.PixelFormat; import android.graphics.Rect; @@ -30,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", @@ -43,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) { @@ -56,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] + "," @@ -72,14 +76,31 @@ public class BlackFrame { } } + final Rect mOuterRect; + final Rect mInnerRect; final Matrix mTmpMatrix = new Matrix(); final float[] mTmpFloats = new float[9]; final BlackSurface[] mBlackSurfaces = new BlackSurface[4]; + public void printTo(String prefix, PrintWriter pw) { + pw.print(prefix); pw.print("Outer: "); mOuterRect.printShortString(pw); + pw.print(" / Inner: "); mInnerRect.printShortString(pw); + pw.println(); + for (int i=0; i<mBlackSurfaces.length; i++) { + BlackSurface bs = mBlackSurfaces[i]; + pw.print(prefix); pw.print("#"); pw.print(i); + pw.print(": "); pw.print(bs.surface); + pw.print(" left="); pw.print(bs.left); + pw.print(" top="); pw.println(bs.top); + } + } + public BlackFrame(SurfaceSession session, Rect outer, Rect inner, int layer) throws Surface.OutOfResourcesException { boolean success = false; + mOuterRect = new Rect(outer); + mInnerRect = new Rect(inner); try { if (outer.top < inner.top) { mBlackSurfaces[0] = new BlackSurface(session, layer, @@ -138,6 +159,14 @@ public class BlackFrame { } } + public void setAlpha(float alpha) { + for (int i=0; i<mBlackSurfaces.length; i++) { + if (mBlackSurfaces[i] != null) { + mBlackSurfaces[i].surface.setAlpha(alpha); + } + } + } + public void clearMatrix() { for (int i=0; i<mBlackSurfaces.length; i++) { if (mBlackSurfaces[i] != null) { diff --git a/services/java/com/android/server/wm/DimAnimator.java b/services/java/com/android/server/wm/DimAnimator.java index a9d4e01..b08c864 100644 --- a/services/java/com/android/server/wm/DimAnimator.java +++ b/services/java/com/android/server/wm/DimAnimator.java @@ -41,14 +41,14 @@ class DimAnimator { DimAnimator (SurfaceSession session) { if (mDimSurface == null) { - if (WindowManagerService.SHOW_TRANSACTIONS || - WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG, - " DIM " + mDimSurface + ": CREATE"); try { mDimSurface = new Surface(session, 0, "DimAnimator", -1, 16, 16, PixelFormat.OPAQUE, Surface.FX_SURFACE_DIM); + if (WindowManagerService.SHOW_TRANSACTIONS || + WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG, + " DIM " + mDimSurface + ": CREATE"); mDimSurface.setAlpha(0.0f); } catch (Exception e) { Slog.e(WindowManagerService.TAG, "Exception creating Dim surface", e); @@ -57,12 +57,17 @@ class DimAnimator { } /** - * Show the dim surface. + * Set's the dim surface's layer and update dim parameters that will be used in + * {@link #updateSurface} after all windows are examined. */ - void show(int dw, int dh) { + void updateParameters(final Resources res, final Parameters params, final long currentTime) { + final int dw = params.mDimWidth; + final int dh = params.mDimHeight; + final WindowStateAnimator winAnimator = params.mDimWinAnimator; + final float target = params.mDimTarget; if (!mDimShown) { - if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, " DIM " + mDimSurface + ": SHOW pos=(0,0) (" + - dw + "x" + dh + ")"); + if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, + " DIM " + mDimSurface + ": SHOW pos=(0,0) (" + dw + "x" + dh + ")"); mDimShown = true; try { mLastDimWidth = dw; @@ -78,31 +83,24 @@ class DimAnimator { mLastDimHeight = dh; mDimSurface.setSize(dw, dh); } - } - /** - * Set's the dim surface's layer and update dim parameters that will be used in - * {@link updateSurface} after all windows are examined. - */ - void updateParameters(Resources res, WindowState w, long currentTime) { - mDimSurface.setLayer(w.mAnimLayer - WindowManagerService.LAYER_OFFSET_DIM); + mDimSurface.setLayer(winAnimator.mAnimLayer - WindowManagerService.LAYER_OFFSET_DIM); - final float target = w.mExiting ? 0 : w.mAttrs.dimAmount; - if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, " DIM " + mDimSurface - + ": layer=" + (w.mAnimLayer-1) + " target=" + target); + if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, " DIM " + + mDimSurface + ": layer=" + (winAnimator.mAnimLayer-1) + " target=" + target); if (mDimTargetAlpha != target) { // 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 = (winAnimator.mAnimating && winAnimator.mAnimation != null) + ? winAnimator.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 +128,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; @@ -190,4 +186,18 @@ class DimAnimator { pw.print(" delta="); pw.print(mDimDeltaPerMs); pw.print(" lastAnimTime="); pw.println(mLastDimAnimTime); } + + static class Parameters { + final WindowStateAnimator mDimWinAnimator; + final int mDimWidth; + final int mDimHeight; + final float mDimTarget; + Parameters(final WindowStateAnimator dimWinAnimator, final int dimWidth, + final int dimHeight, final float dimTarget) { + mDimWinAnimator = dimWinAnimator; + mDimWidth = dimWidth; + mDimHeight = dimHeight; + mDimTarget = dimTarget; + } + } }
\ No newline at end of file diff --git a/services/java/com/android/server/wm/DimSurface.java b/services/java/com/android/server/wm/DimSurface.java index dc6cc0d..c1dbb36 100644 --- a/services/java/com/android/server/wm/DimSurface.java +++ b/services/java/com/android/server/wm/DimSurface.java @@ -32,14 +32,14 @@ class DimSurface { DimSurface(SurfaceSession session) { if (mDimSurface == null) { - if (WindowManagerService.SHOW_TRANSACTIONS || - WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG, - " DIM " + mDimSurface + ": CREATE"); try { mDimSurface = new Surface(session, 0, "DimSurface", -1, 16, 16, PixelFormat.OPAQUE, Surface.FX_SURFACE_DIM); + if (WindowManagerService.SHOW_TRANSACTIONS || + WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG, + " DIM " + mDimSurface + ": CREATE"); mDimSurface.setAlpha(0.0f); } catch (Exception e) { Slog.e(WindowManagerService.TAG, "Exception creating Dim surface", e); diff --git a/services/java/com/android/server/wm/DragState.java b/services/java/com/android/server/wm/DragState.java index a19035a..b2cf3e0 100644 --- a/services/java/com/android/server/wm/DragState.java +++ b/services/java/com/android/server/wm/DragState.java @@ -16,6 +16,8 @@ package com.android.server.wm; +import com.android.server.input.InputApplicationHandle; +import com.android.server.input.InputWindowHandle; import com.android.server.wm.WindowManagerService.DragInputEventReceiver; import com.android.server.wm.WindowManagerService.H; diff --git a/services/java/com/android/server/wm/FakeWindowImpl.java b/services/java/com/android/server/wm/FakeWindowImpl.java index 121ce18..2527f46 100644 --- a/services/java/com/android/server/wm/FakeWindowImpl.java +++ b/services/java/com/android/server/wm/FakeWindowImpl.java @@ -16,6 +16,9 @@ package com.android.server.wm; +import com.android.server.input.InputApplicationHandle; +import com.android.server.input.InputWindowHandle; + import android.os.Looper; import android.os.Process; import android.util.Slog; diff --git a/services/java/com/android/server/wm/InputMonitor.java b/services/java/com/android/server/wm/InputMonitor.java index fb74d27..c28cfa2 100644 --- a/services/java/com/android/server/wm/InputMonitor.java +++ b/services/java/com/android/server/wm/InputMonitor.java @@ -16,6 +16,10 @@ package com.android.server.wm; +import com.android.server.input.InputManagerService; +import com.android.server.input.InputApplicationHandle; +import com.android.server.input.InputWindowHandle; + import android.graphics.Rect; import android.os.RemoteException; import android.util.Log; @@ -27,7 +31,7 @@ import android.view.WindowManager; import java.util.ArrayList; import java.util.Arrays; -final class InputMonitor { +final class InputMonitor implements InputManagerService.Callbacks { private final WindowManagerService mService; // Current window with input focus for keys and other non-touch events. May be null. @@ -93,7 +97,7 @@ final class InputMonitor { } if (appWindowToken == null && inputApplicationHandle != null) { - appWindowToken = inputApplicationHandle.appWindowToken; + appWindowToken = (AppWindowToken)inputApplicationHandle.appWindowToken; if (appWindowToken != null) { Slog.i(WindowManagerService.TAG, "Input event dispatching timed out sending to application " @@ -301,7 +305,14 @@ final class InputMonitor { WindowState windowState = focus != null ? (WindowState) focus.windowState : null; return mService.mPolicy.dispatchUnhandledKey(windowState, event, policyFlags); } - + + /* Callback to get pointer layer. */ + public int getPointerLayer() { + return mService.mPolicy.windowTypeToLayerLw(WindowManager.LayoutParams.TYPE_POINTER) + * WindowManagerService.TYPE_LAYER_MULTIPLIER + + WindowManagerService.TYPE_LAYER_OFFSET; + } + /* Called when the current input focus changes. * Layer assignment is assumed to be complete by the time this is called. */ diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/java/com/android/server/wm/ScreenRotationAnimation.java index 04a039f..e460f7f 100644 --- a/services/java/com/android/server/wm/ScreenRotationAnimation.java +++ b/services/java/com/android/server/wm/ScreenRotationAnimation.java @@ -33,15 +33,17 @@ class ScreenRotationAnimation { static final String TAG = "ScreenRotationAnimation"; static final boolean DEBUG_STATE = false; static final boolean DEBUG_TRANSFORMS = false; + static final boolean USE_CUSTOM_BLACK_FRAME = false; static final int FREEZE_LAYER = WindowManagerService.TYPE_LAYER_MULTIPLIER * 200; final Context mContext; Surface mSurface; - BlackFrame mBlackFrame; + BlackFrame mCustomBlackFrame; + BlackFrame mExitingBlackFrame; + BlackFrame mEnteringBlackFrame; int mWidth, mHeight; - int mSnapshotRotation; int mSnapshotDeltaRotation; int mOriginalRotation; int mOriginalWidth, mOriginalHeight; @@ -59,6 +61,8 @@ class ScreenRotationAnimation { final Transformation mStartExitTransformation = new Transformation(); Animation mStartEnterAnimation; final Transformation mStartEnterTransformation = new Transformation(); + Animation mStartFrameAnimation; + final Transformation mStartFrameTransformation = new Transformation(); // The finishing animation for the exiting and entering elements. This // animation needs to undo the transformation of the starting animation. @@ -68,6 +72,8 @@ class ScreenRotationAnimation { final Transformation mFinishExitTransformation = new Transformation(); Animation mFinishEnterAnimation; final Transformation mFinishEnterTransformation = new Transformation(); + Animation mFinishFrameAnimation; + final Transformation mFinishFrameTransformation = new Transformation(); // The current active animation to move from the old to the new rotated // state. Which animation is run here will depend on the old and new @@ -76,6 +82,8 @@ class ScreenRotationAnimation { final Transformation mRotateExitTransformation = new Transformation(); Animation mRotateEnterAnimation; final Transformation mRotateEnterTransformation = new Transformation(); + Animation mRotateFrameAnimation; + final Transformation mRotateFrameTransformation = new Transformation(); // A previously running rotate animation. This will be used if we need // to switch to a new rotation before finishing the previous one. @@ -83,28 +91,54 @@ class ScreenRotationAnimation { final Transformation mLastRotateExitTransformation = new Transformation(); Animation mLastRotateEnterAnimation; final Transformation mLastRotateEnterTransformation = new Transformation(); + Animation mLastRotateFrameAnimation; + final Transformation mLastRotateFrameTransformation = new Transformation(); // Complete transformations being applied. final Transformation mExitTransformation = new Transformation(); final Transformation mEnterTransformation = new Transformation(); + final Transformation mFrameTransformation = new Transformation(); boolean mStarted; boolean mAnimRunning; boolean mFinishAnimReady; long mFinishAnimStartTime; + final Matrix mFrameInitialMatrix = new Matrix(); final Matrix mSnapshotInitialMatrix = new Matrix(); final Matrix mSnapshotFinalMatrix = new Matrix(); + final Matrix mExitFrameFinalMatrix = new Matrix(); final Matrix mTmpMatrix = new Matrix(); final float[] mTmpFloats = new float[9]; + private boolean mMoreRotateEnter; + private boolean mMoreRotateExit; + private boolean mMoreRotateFrame; + private boolean mMoreFinishEnter; + private boolean mMoreFinishExit; + private boolean mMoreFinishFrame; + private boolean mMoreStartEnter; + private boolean mMoreStartExit; + private boolean mMoreStartFrame; public void printTo(String prefix, PrintWriter pw) { pw.print(prefix); pw.print("mSurface="); pw.print(mSurface); pw.print(" mWidth="); pw.print(mWidth); pw.print(" mHeight="); pw.println(mHeight); - pw.print(prefix); pw.print("mBlackFrame="); pw.println(mBlackFrame); - pw.print(prefix); pw.print("mSnapshotRotation="); pw.print(mSnapshotRotation); - pw.print(" mSnapshotDeltaRotation="); pw.print(mSnapshotDeltaRotation); + if (USE_CUSTOM_BLACK_FRAME) { + pw.print(prefix); pw.print("mCustomBlackFrame="); pw.println(mCustomBlackFrame); + if (mCustomBlackFrame != null) { + mCustomBlackFrame.printTo(prefix + " ", pw); + } + } + pw.print(prefix); pw.print("mExitingBlackFrame="); pw.println(mExitingBlackFrame); + if (mExitingBlackFrame != null) { + mExitingBlackFrame.printTo(prefix + " ", pw); + } + pw.print(prefix); pw.print("mEnteringBlackFrame="); pw.println(mEnteringBlackFrame); + if (mEnteringBlackFrame != null) { + mEnteringBlackFrame.printTo(prefix + " ", pw); + } + pw.print(prefix); pw.print(" mSnapshotDeltaRotation="); pw.print(mSnapshotDeltaRotation); pw.print(" mCurRotation="); pw.println(mCurRotation); pw.print(prefix); pw.print("mOriginalRotation="); pw.print(mOriginalRotation); pw.print(" mOriginalWidth="); pw.print(mOriginalWidth); @@ -117,25 +151,36 @@ class ScreenRotationAnimation { pw.print(" "); mStartExitTransformation.printShortString(pw); pw.println(); pw.print(prefix); pw.print("mStartEnterAnimation="); pw.print(mStartEnterAnimation); pw.print(" "); mStartEnterTransformation.printShortString(pw); pw.println(); + pw.print(prefix); pw.print("mStartFrameAnimation="); pw.print(mStartFrameAnimation); + pw.print(" "); mStartFrameTransformation.printShortString(pw); pw.println(); pw.print(prefix); pw.print("mFinishExitAnimation="); pw.print(mFinishExitAnimation); pw.print(" "); mFinishExitTransformation.printShortString(pw); pw.println(); pw.print(prefix); pw.print("mFinishEnterAnimation="); pw.print(mFinishEnterAnimation); pw.print(" "); mFinishEnterTransformation.printShortString(pw); pw.println(); + pw.print(prefix); pw.print("mFinishFrameAnimation="); pw.print(mFinishFrameAnimation); + pw.print(" "); mFinishFrameTransformation.printShortString(pw); pw.println(); pw.print(prefix); pw.print("mRotateExitAnimation="); pw.print(mRotateExitAnimation); pw.print(" "); mRotateExitTransformation.printShortString(pw); pw.println(); pw.print(prefix); pw.print("mRotateEnterAnimation="); pw.print(mRotateEnterAnimation); pw.print(" "); mRotateEnterTransformation.printShortString(pw); pw.println(); - pw.print(prefix); pw.print("mLastRotateExitAnimation="); - pw.print(mLastRotateExitAnimation); - pw.print(" "); mLastRotateExitTransformation.printShortString(pw); pw.println(); + pw.print(prefix); pw.print("mRotateFrameAnimation="); pw.print(mRotateFrameAnimation); + pw.print(" "); mRotateFrameTransformation.printShortString(pw); pw.println(); pw.print(prefix); pw.print("mExitTransformation="); mExitTransformation.printShortString(pw); pw.println(); pw.print(prefix); pw.print("mEnterTransformation="); mEnterTransformation.printShortString(pw); pw.println(); + pw.print(prefix); pw.print("mFrameTransformation="); + mEnterTransformation.printShortString(pw); pw.println(); + pw.print(prefix); pw.print("mFrameInitialMatrix="); + mFrameInitialMatrix.printShortString(pw); + pw.println(); pw.print(prefix); pw.print("mSnapshotInitialMatrix="); mSnapshotInitialMatrix.printShortString(pw); pw.print(" mSnapshotFinalMatrix="); mSnapshotFinalMatrix.printShortString(pw); pw.println(); + pw.print(prefix); pw.print("mExitFrameFinalMatrix="); + mExitFrameFinalMatrix.printShortString(pw); + pw.println(); } public ScreenRotationAnimation(Context context, SurfaceSession session, @@ -143,7 +188,6 @@ class ScreenRotationAnimation { mContext = context; // Screenshot does NOT include rotation! - mSnapshotRotation = 0; if (originalRotation == Surface.ROTATION_90 || originalRotation == Surface.ROTATION_270) { mWidth = originalHeight; @@ -167,7 +211,7 @@ class ScreenRotationAnimation { try { mSurface = new Surface(session, 0, "FreezeSurface", -1, mWidth, mHeight, PixelFormat.OPAQUE, Surface.FX_SURFACE_SCREENSHOT | Surface.HIDDEN); - if (mSurface == null || !mSurface.isValid()) { + if (!mSurface.isValid()) { // Screenshot failed, punt. mSurface = null; return; @@ -251,7 +295,7 @@ class ScreenRotationAnimation { // Compute the transformation matrix that must be applied // to the snapshot to make it stay in the same original position // with the current screen rotation. - int delta = deltaRotation(rotation, mSnapshotRotation); + int delta = deltaRotation(rotation, Surface.ROTATION_0); createRotationMatrix(delta, mWidth, mHeight, mSnapshotInitialMatrix); if (DEBUG_STATE) Slog.v(TAG, "**** ROTATION: " + delta); @@ -293,10 +337,18 @@ class ScreenRotationAnimation { com.android.internal.R.anim.screen_rotate_start_exit); mStartEnterAnimation = AnimationUtils.loadAnimation(mContext, com.android.internal.R.anim.screen_rotate_start_enter); + if (USE_CUSTOM_BLACK_FRAME) { + mStartFrameAnimation = AnimationUtils.loadAnimation(mContext, + com.android.internal.R.anim.screen_rotate_start_frame); + } mFinishExitAnimation = AnimationUtils.loadAnimation(mContext, com.android.internal.R.anim.screen_rotate_finish_exit); mFinishEnterAnimation = AnimationUtils.loadAnimation(mContext, com.android.internal.R.anim.screen_rotate_finish_enter); + if (USE_CUSTOM_BLACK_FRAME) { + mFinishFrameAnimation = AnimationUtils.loadAnimation(mContext, + com.android.internal.R.anim.screen_rotate_finish_frame); + } } if (DEBUG_STATE) Slog.v(TAG, "Rotation delta: " + delta + " finalWidth=" @@ -309,27 +361,47 @@ class ScreenRotationAnimation { com.android.internal.R.anim.screen_rotate_0_exit); mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext, com.android.internal.R.anim.screen_rotate_0_enter); + if (USE_CUSTOM_BLACK_FRAME) { + mRotateFrameAnimation = AnimationUtils.loadAnimation(mContext, + com.android.internal.R.anim.screen_rotate_0_frame); + } break; case Surface.ROTATION_90: mRotateExitAnimation = AnimationUtils.loadAnimation(mContext, com.android.internal.R.anim.screen_rotate_plus_90_exit); mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext, com.android.internal.R.anim.screen_rotate_plus_90_enter); + if (USE_CUSTOM_BLACK_FRAME) { + mRotateFrameAnimation = AnimationUtils.loadAnimation(mContext, + com.android.internal.R.anim.screen_rotate_plus_90_frame); + } break; case Surface.ROTATION_180: mRotateExitAnimation = AnimationUtils.loadAnimation(mContext, com.android.internal.R.anim.screen_rotate_180_exit); mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext, com.android.internal.R.anim.screen_rotate_180_enter); + mRotateFrameAnimation = AnimationUtils.loadAnimation(mContext, + com.android.internal.R.anim.screen_rotate_180_frame); break; case Surface.ROTATION_270: mRotateExitAnimation = AnimationUtils.loadAnimation(mContext, com.android.internal.R.anim.screen_rotate_minus_90_exit); mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext, com.android.internal.R.anim.screen_rotate_minus_90_enter); + if (USE_CUSTOM_BLACK_FRAME) { + mRotateFrameAnimation = AnimationUtils.loadAnimation(mContext, + com.android.internal.R.anim.screen_rotate_minus_90_frame); + } break; } + // Compute partial steps between original and final sizes. These + // are used for the dimensions of the exiting and entering elements, + // so they are never stretched too significantly. + final int halfWidth = (finalWidth + mOriginalWidth) / 2; + final int halfHeight = (finalHeight + mOriginalHeight) / 2; + // Initialize the animations. This is a hack, redefining what "parent" // means to allow supplying the last and next size. In this definition // "%p" is the original (let's call it "previous") size, and "%" is the @@ -337,16 +409,26 @@ class ScreenRotationAnimation { if (firstStart) { if (DEBUG_STATE) Slog.v(TAG, "Initializing start and finish animations"); mStartEnterAnimation.initialize(finalWidth, finalHeight, - mOriginalWidth, mOriginalHeight); - mStartExitAnimation.initialize(finalWidth, finalHeight, + halfWidth, halfHeight); + mStartExitAnimation.initialize(halfWidth, halfHeight, mOriginalWidth, mOriginalHeight); mFinishEnterAnimation.initialize(finalWidth, finalHeight, + halfWidth, halfHeight); + mFinishExitAnimation.initialize(halfWidth, halfHeight, mOriginalWidth, mOriginalHeight); - mFinishExitAnimation.initialize(finalWidth, finalHeight, - mOriginalWidth, mOriginalHeight); + if (USE_CUSTOM_BLACK_FRAME) { + mStartFrameAnimation.initialize(finalWidth, finalHeight, + mOriginalWidth, mOriginalHeight); + mFinishFrameAnimation.initialize(finalWidth, finalHeight, + mOriginalWidth, mOriginalHeight); + } } mRotateEnterAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight); mRotateExitAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight); + if (USE_CUSTOM_BLACK_FRAME) { + mRotateFrameAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, + mOriginalHeight); + } mAnimRunning = false; mFinishAnimReady = false; mFinishAnimStartTime = -1; @@ -360,22 +442,93 @@ class ScreenRotationAnimation { mFinishExitAnimation.scaleCurrentDuration(animationScale); mFinishEnterAnimation.restrictDuration(maxAnimationDuration); mFinishEnterAnimation.scaleCurrentDuration(animationScale); + if (USE_CUSTOM_BLACK_FRAME) { + mStartFrameAnimation.restrictDuration(maxAnimationDuration); + mStartFrameAnimation.scaleCurrentDuration(animationScale); + mFinishFrameAnimation.restrictDuration(maxAnimationDuration); + mFinishFrameAnimation.scaleCurrentDuration(animationScale); + } } mRotateExitAnimation.restrictDuration(maxAnimationDuration); mRotateExitAnimation.scaleCurrentDuration(animationScale); mRotateEnterAnimation.restrictDuration(maxAnimationDuration); mRotateEnterAnimation.scaleCurrentDuration(animationScale); + if (USE_CUSTOM_BLACK_FRAME) { + mRotateFrameAnimation.restrictDuration(maxAnimationDuration); + mRotateFrameAnimation.scaleCurrentDuration(animationScale); + } + + if (USE_CUSTOM_BLACK_FRAME && mCustomBlackFrame == null) { + if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i( + WindowManagerService.TAG, + ">>> OPEN TRANSACTION ScreenRotationAnimation.startAnimation"); + Surface.openTransaction(); + + // Compute the transformation matrix that must be applied + // the the black frame to make it stay in the initial position + // before the new screen rotation. This is different than the + // snapshot transformation because the snapshot is always based + // of the native orientation of the screen, not the orientation + // we were last in. + createRotationMatrix(delta, mOriginalWidth, mOriginalHeight, mFrameInitialMatrix); + + try { + Rect outer = new Rect(-mOriginalWidth*1, -mOriginalHeight*1, + mOriginalWidth*2, mOriginalHeight*2); + Rect inner = new Rect(0, 0, mOriginalWidth, mOriginalHeight); + mCustomBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER + 3); + mCustomBlackFrame.setMatrix(mFrameInitialMatrix); + } catch (Surface.OutOfResourcesException e) { + Slog.w(TAG, "Unable to allocate black surface", e); + } finally { + Surface.closeTransaction(); + if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i( + WindowManagerService.TAG, + "<<< CLOSE TRANSACTION ScreenRotationAnimation.startAnimation"); + } + } + + if (mExitingBlackFrame == null) { + if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i( + WindowManagerService.TAG, + ">>> OPEN TRANSACTION ScreenRotationAnimation.startAnimation"); + Surface.openTransaction(); + + // Compute the transformation matrix that must be applied + // the the black frame to make it stay in the initial position + // before the new screen rotation. This is different than the + // snapshot transformation because the snapshot is always based + // of the native orientation of the screen, not the orientation + // we were last in. + createRotationMatrix(delta, mOriginalWidth, mOriginalHeight, mFrameInitialMatrix); + + try { + Rect outer = new Rect(-mOriginalWidth*1, -mOriginalHeight*1, + mOriginalWidth*2, mOriginalHeight*2); + Rect inner = new Rect(0, 0, mOriginalWidth, mOriginalHeight); + mExitingBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER + 2); + mExitingBlackFrame.setMatrix(mFrameInitialMatrix); + } catch (Surface.OutOfResourcesException e) { + Slog.w(TAG, "Unable to allocate black surface", e); + } finally { + Surface.closeTransaction(); + if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i( + WindowManagerService.TAG, + "<<< CLOSE TRANSACTION ScreenRotationAnimation.startAnimation"); + } + } - if (mBlackFrame == null) { + if (false && mEnteringBlackFrame == null) { if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i( WindowManagerService.TAG, ">>> OPEN TRANSACTION ScreenRotationAnimation.startAnimation"); Surface.openTransaction(); try { - Rect outer = new Rect(-finalWidth*1, -finalHeight*1, finalWidth*2, finalHeight*2); + Rect outer = new Rect(-finalWidth*1, -finalHeight*1, + finalWidth*2, finalHeight*2); Rect inner = new Rect(0, 0, finalWidth, finalHeight); - mBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER); + mEnteringBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER); } catch (Surface.OutOfResourcesException e) { Slog.w(TAG, "Unable to allocate black surface", e); } finally { @@ -420,9 +573,17 @@ class ScreenRotationAnimation { mSurface.destroy(); mSurface = null; } - if (mBlackFrame != null) { - mBlackFrame.kill(); - mBlackFrame = null; + if (mCustomBlackFrame != null) { + mCustomBlackFrame.kill(); + mCustomBlackFrame = null; + } + if (mExitingBlackFrame != null) { + mExitingBlackFrame.kill(); + mExitingBlackFrame = null; + } + if (mEnteringBlackFrame != null) { + mEnteringBlackFrame.kill(); + mEnteringBlackFrame = null; } if (mStartExitAnimation != null) { mStartExitAnimation.cancel(); @@ -432,13 +593,21 @@ class ScreenRotationAnimation { mStartEnterAnimation.cancel(); mStartEnterAnimation = null; } + if (mStartFrameAnimation != null) { + mStartFrameAnimation.cancel(); + mStartFrameAnimation = null; + } if (mFinishExitAnimation != null) { mFinishExitAnimation.cancel(); mFinishExitAnimation = null; } - if (mStartEnterAnimation != null) { - mStartEnterAnimation.cancel(); - mStartEnterAnimation = null; + if (mFinishEnterAnimation != null) { + mFinishEnterAnimation.cancel(); + mFinishEnterAnimation = null; + } + if (mFinishFrameAnimation != null) { + mFinishFrameAnimation.cancel(); + mFinishFrameAnimation = null; } if (mRotateExitAnimation != null) { mRotateExitAnimation.cancel(); @@ -448,132 +617,146 @@ class ScreenRotationAnimation { mRotateEnterAnimation.cancel(); mRotateEnterAnimation = null; } + if (mRotateFrameAnimation != null) { + mRotateFrameAnimation.cancel(); + mRotateFrameAnimation = null; + } } public boolean isAnimating() { return mStartEnterAnimation != null || mStartExitAnimation != null - && mFinishEnterAnimation != null || mFinishExitAnimation != null - && mRotateEnterAnimation != null || mRotateExitAnimation != null; + || mStartFrameAnimation != null + || mFinishEnterAnimation != null || mFinishExitAnimation != null + || mFinishFrameAnimation != null + || mRotateEnterAnimation != null || mRotateExitAnimation != null + || mRotateFrameAnimation != null; } - public boolean stepAnimation(long now) { - if (!isAnimating()) { - if (DEBUG_STATE) Slog.v(TAG, "Step: no animations running"); - return false; - } - - if (!mAnimRunning) { - if (DEBUG_STATE) Slog.v(TAG, "Step: starting start, finish, rotate"); - if (mStartEnterAnimation != null) { - mStartEnterAnimation.setStartTime(now); - } - if (mStartExitAnimation != null) { - mStartExitAnimation.setStartTime(now); - } - if (mFinishEnterAnimation != null) { - mFinishEnterAnimation.setStartTime(0); - } - if (mFinishExitAnimation != null) { - mFinishExitAnimation.setStartTime(0); - } - if (mRotateEnterAnimation != null) { - mRotateEnterAnimation.setStartTime(now); - } - if (mRotateExitAnimation != null) { - mRotateExitAnimation.setStartTime(now); - } - mAnimRunning = true; - } + private boolean stepAnimation(long now) { if (mFinishAnimReady && mFinishAnimStartTime < 0) { if (DEBUG_STATE) Slog.v(TAG, "Step: finish anim now ready"); mFinishAnimStartTime = now; } - // If the start animation is no longer running, we want to keep its - // transformation intact until the finish animation also completes. - - boolean moreStartExit = false; + mMoreStartExit = false; if (mStartExitAnimation != null) { - mStartExitTransformation.clear(); - moreStartExit = mStartExitAnimation.getTransformation(now, mStartExitTransformation); + mMoreStartExit = mStartExitAnimation.getTransformation(now, mStartExitTransformation); if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start exit: " + mStartExitTransformation); - if (!moreStartExit) { - if (DEBUG_STATE) Slog.v(TAG, "Start exit animation done!"); - mStartExitAnimation.cancel(); - mStartExitAnimation = null; - } } - boolean moreStartEnter = false; + mMoreStartEnter = false; if (mStartEnterAnimation != null) { - mStartEnterTransformation.clear(); - moreStartEnter = mStartEnterAnimation.getTransformation(now, mStartEnterTransformation); + mMoreStartEnter = mStartEnterAnimation.getTransformation(now, mStartEnterTransformation); if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start enter: " + mStartEnterTransformation); - if (!moreStartEnter) { - if (DEBUG_STATE) Slog.v(TAG, "Start enter animation done!"); - mStartEnterAnimation.cancel(); - mStartEnterAnimation = null; - } + } + + mMoreStartFrame = false; + if (mStartFrameAnimation != null) { + mMoreStartFrame = mStartFrameAnimation.getTransformation(now, mStartFrameTransformation); + if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start frame: " + mStartFrameTransformation); } long finishNow = mFinishAnimReady ? (now - mFinishAnimStartTime) : 0; if (DEBUG_STATE) Slog.v(TAG, "Step: finishNow=" + finishNow); - mFinishExitTransformation.clear(); - boolean moreFinishExit = false; + mMoreFinishExit = false; if (mFinishExitAnimation != null) { - moreFinishExit = mFinishExitAnimation.getTransformation(finishNow, mFinishExitTransformation); + mMoreFinishExit = mFinishExitAnimation.getTransformation(finishNow, mFinishExitTransformation); if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish exit: " + mFinishExitTransformation); - if (!moreStartExit && !moreFinishExit) { - if (DEBUG_STATE) Slog.v(TAG, "Finish exit animation done, clearing start/finish anims!"); - mStartExitTransformation.clear(); - mFinishExitAnimation.cancel(); - mFinishExitAnimation = null; - mFinishExitTransformation.clear(); - } } - mFinishEnterTransformation.clear(); - boolean moreFinishEnter = false; + mMoreFinishEnter = false; if (mFinishEnterAnimation != null) { - moreFinishEnter = mFinishEnterAnimation.getTransformation(finishNow, mFinishEnterTransformation); + mMoreFinishEnter = mFinishEnterAnimation.getTransformation(finishNow, mFinishEnterTransformation); if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish enter: " + mFinishEnterTransformation); - if (!moreStartEnter && !moreFinishEnter) { - if (DEBUG_STATE) Slog.v(TAG, "Finish enter animation done, clearing start/finish anims!"); - mStartEnterTransformation.clear(); - mFinishEnterAnimation.cancel(); - mFinishEnterAnimation = null; - mFinishEnterTransformation.clear(); - } } - mRotateExitTransformation.clear(); - boolean moreRotateExit = false; - if (mRotateExitAnimation != null) { - moreRotateExit = mRotateExitAnimation.getTransformation(now, mRotateExitTransformation); - if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate exit: " + mRotateExitTransformation); + mMoreFinishFrame = false; + if (mFinishFrameAnimation != null) { + mMoreFinishFrame = mFinishFrameAnimation.getTransformation(finishNow, mFinishFrameTransformation); + if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish frame: " + mFinishFrameTransformation); } - if (!moreFinishExit && !moreRotateExit) { - if (DEBUG_STATE) Slog.v(TAG, "Rotate exit animation done!"); - mRotateExitAnimation.cancel(); - mRotateExitAnimation = null; - mRotateExitTransformation.clear(); + mMoreRotateExit = false; + if (mRotateExitAnimation != null) { + mMoreRotateExit = mRotateExitAnimation.getTransformation(now, mRotateExitTransformation); + if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate exit: " + mRotateExitTransformation); } - mRotateEnterTransformation.clear(); - boolean moreRotateEnter = false; + mMoreRotateEnter = false; if (mRotateEnterAnimation != null) { - moreRotateEnter = mRotateEnterAnimation.getTransformation(now, mRotateEnterTransformation); + mMoreRotateEnter = mRotateEnterAnimation.getTransformation(now, mRotateEnterTransformation); if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate enter: " + mRotateEnterTransformation); } - if (!moreFinishEnter && !moreRotateEnter) { - if (DEBUG_STATE) Slog.v(TAG, "Rotate enter animation done!"); - mRotateEnterAnimation.cancel(); - mRotateEnterAnimation = null; - mRotateEnterTransformation.clear(); + mMoreRotateFrame = false; + if (mRotateFrameAnimation != null) { + mMoreRotateFrame = mRotateFrameAnimation.getTransformation(now, mRotateFrameTransformation); + if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate frame: " + mRotateFrameTransformation); + } + + if (!mMoreStartExit && !mMoreRotateExit && !mMoreFinishExit) { + if (mStartExitAnimation != null) { + if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, clearing start exit anim!"); + mStartExitAnimation.cancel(); + mStartExitAnimation = null; + mStartExitTransformation.clear(); + } + if (mFinishExitAnimation != null) { + if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, clearing finish exit anim!"); + mFinishExitAnimation.cancel(); + mFinishExitAnimation = null; + mFinishExitTransformation.clear(); + } + if (mRotateExitAnimation != null) { + if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, clearing rotate exit anim!"); + mRotateExitAnimation.cancel(); + mRotateExitAnimation = null; + mRotateExitTransformation.clear(); + } + } + + if (!mMoreStartEnter && !mMoreRotateEnter && !mMoreFinishEnter) { + if (mStartEnterAnimation != null) { + if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, clearing start enter anim!"); + mStartEnterAnimation.cancel(); + mStartEnterAnimation = null; + mStartEnterTransformation.clear(); + } + if (mFinishEnterAnimation != null) { + if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, clearing finish enter anim!"); + mFinishEnterAnimation.cancel(); + mFinishEnterAnimation = null; + mFinishEnterTransformation.clear(); + } + if (mRotateEnterAnimation != null) { + if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, clearing rotate enter anim!"); + mRotateEnterAnimation.cancel(); + mRotateEnterAnimation = null; + mRotateEnterTransformation.clear(); + } + } + + if (USE_CUSTOM_BLACK_FRAME && !mMoreStartFrame && !mMoreRotateFrame && !mMoreFinishFrame) { + if (mStartFrameAnimation != null) { + if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, clearing start frame anim!"); + mStartFrameAnimation.cancel(); + mStartFrameAnimation = null; + mStartFrameTransformation.clear(); + } + if (mFinishFrameAnimation != null) { + if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, clearing finish frame anim!"); + mFinishFrameAnimation.cancel(); + mFinishFrameAnimation = null; + mFinishFrameTransformation.clear(); + } + if (mRotateFrameAnimation != null) { + if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, clearing rotate frame anim!"); + mRotateFrameAnimation.cancel(); + mRotateFrameAnimation = null; + mRotateFrameTransformation.clear(); + } } mExitTransformation.set(mRotateExitTransformation); @@ -587,33 +770,109 @@ class ScreenRotationAnimation { if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final exit: " + mExitTransformation); if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final enter: " + mEnterTransformation); - if (!moreStartExit && !moreFinishExit && !moreRotateExit) { - if (mSurface != null) { + if (USE_CUSTOM_BLACK_FRAME) { + //mFrameTransformation.set(mRotateExitTransformation); + //mFrameTransformation.compose(mStartExitTransformation); + //mFrameTransformation.compose(mFinishExitTransformation); + mFrameTransformation.set(mRotateFrameTransformation); + mFrameTransformation.compose(mStartFrameTransformation); + mFrameTransformation.compose(mFinishFrameTransformation); + mFrameTransformation.getMatrix().preConcat(mFrameInitialMatrix); + if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final frame: " + mFrameTransformation); + } + + final boolean more = mMoreStartEnter || mMoreStartExit || mMoreStartFrame + || mMoreFinishEnter || mMoreFinishExit || mMoreFinishFrame + || mMoreRotateEnter || mMoreRotateExit || mMoreRotateFrame + || !mFinishAnimReady; + + mSnapshotFinalMatrix.setConcat(mExitTransformation.getMatrix(), mSnapshotInitialMatrix); + + if (DEBUG_STATE) Slog.v(TAG, "Step: more=" + more); + + return more; + } + + void updateSurfaces() { + if (mSurface != null) { + if (!mMoreStartExit && !mMoreFinishExit && !mMoreRotateExit) { if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, hiding screenshot surface"); mSurface.hide(); } } - if (!moreStartEnter && !moreFinishEnter && !moreRotateEnter) { - if (mBlackFrame != null) { - if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, hiding black frame"); - mBlackFrame.hide(); + if (mCustomBlackFrame != null) { + if (!mMoreStartFrame && !mMoreFinishFrame && !mMoreRotateFrame) { + if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, hiding black frame"); + mCustomBlackFrame.hide(); + } else { + mCustomBlackFrame.setMatrix(mFrameTransformation.getMatrix()); } - } else { - if (mBlackFrame != null) { - mBlackFrame.setMatrix(mEnterTransformation.getMatrix()); + } + + if (mExitingBlackFrame != null) { + if (!mMoreStartExit && !mMoreFinishExit && !mMoreRotateExit) { + if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, hiding exiting frame"); + mExitingBlackFrame.hide(); + } else { + mExitFrameFinalMatrix.setConcat(mExitTransformation.getMatrix(), mFrameInitialMatrix); + mExitingBlackFrame.setMatrix(mExitFrameFinalMatrix); + mExitingBlackFrame.setAlpha(mExitTransformation.getAlpha()); } } - mSnapshotFinalMatrix.setConcat(mExitTransformation.getMatrix(), mSnapshotInitialMatrix); - setSnapshotTransform(mSnapshotFinalMatrix, mExitTransformation.getAlpha()); + if (mEnteringBlackFrame != null) { + if (!mMoreStartEnter && !mMoreFinishEnter && !mMoreRotateEnter) { + if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, hiding entering frame"); + mEnteringBlackFrame.hide(); + } else { + mEnteringBlackFrame.setMatrix(mEnterTransformation.getMatrix()); + } + } - final boolean more = moreStartEnter || moreStartExit || moreFinishEnter || moreFinishExit - || moreRotateEnter || moreRotateExit || !mFinishAnimReady; + setSnapshotTransform(mSnapshotFinalMatrix, mExitTransformation.getAlpha()); + } + + public boolean stepAnimationLocked(long now) { + if (!isAnimating()) { + if (DEBUG_STATE) Slog.v(TAG, "Step: no animations running"); + mFinishAnimReady = false; + return false; + } - if (DEBUG_STATE) Slog.v(TAG, "Step: more=" + more); + if (!mAnimRunning) { + if (DEBUG_STATE) Slog.v(TAG, "Step: starting start, finish, rotate"); + if (mStartEnterAnimation != null) { + mStartEnterAnimation.setStartTime(now); + } + if (mStartExitAnimation != null) { + mStartExitAnimation.setStartTime(now); + } + if (mStartFrameAnimation != null) { + mStartFrameAnimation.setStartTime(now); + } + if (mFinishEnterAnimation != null) { + mFinishEnterAnimation.setStartTime(0); + } + if (mFinishExitAnimation != null) { + mFinishExitAnimation.setStartTime(0); + } + if (mFinishFrameAnimation != null) { + mFinishFrameAnimation.setStartTime(0); + } + if (mRotateEnterAnimation != null) { + mRotateEnterAnimation.setStartTime(now); + } + if (mRotateExitAnimation != null) { + mRotateExitAnimation.setStartTime(now); + } + if (mRotateFrameAnimation != null) { + mRotateFrameAnimation.setStartTime(now); + } + mAnimRunning = true; + } - return more; + return stepAnimation(now); } public Transformation getEnterTransformation() { 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..0d64b68 --- /dev/null +++ b/services/java/com/android/server/wm/WindowAnimator.java @@ -0,0 +1,535 @@ +// Copyright 2012 Google Inc. All Rights Reserved. + +package com.android.server.wm; + +import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; + +import static com.android.server.wm.WindowManagerService.LayoutFields.SET_UPDATE_ROTATION; +import static com.android.server.wm.WindowManagerService.LayoutFields.SET_WALLPAPER_MAY_CHANGE; +import static com.android.server.wm.WindowManagerService.LayoutFields.SET_FORCE_HIDING_CHANGED; + +import static com.android.server.wm.WindowManagerService.H.SET_DIM_PARAMETERS; + +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.WindowManagerPolicy; +import android.view.animation.Animation; + +import com.android.internal.policy.impl.PhoneWindowManager; + +import java.io.PrintWriter; +import java.util.HashSet; + +/** + * 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; + + HashSet<WindowStateAnimator> mWinAnimators = new HashSet<WindowStateAnimator>(); + HashSet<WindowStateAnimator> mFinished = new HashSet<WindowStateAnimator>(); + + boolean mAnimating; + 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; + + // Window currently running an animation that has requested it be detached + // from the wallpaper. This means we need to ensure the wallpaper is + // visible behind it in case it animates in a way that would allow it to be + // seen. + WindowState mWindowDetachedWallpaper = null; + WindowState mDetachedWallpaper = null; + DimSurface mWindowAnimationBackgroundSurface = null; + + int mBulkUpdateParams = 0; + + DimAnimator mDimAnimator = null; + DimAnimator.Parameters mDimParams = null; + + WindowAnimator(final WindowManagerService service, final Context context, + final WindowManagerPolicy policy) { + mService = service; + mContext = context; + mPolicy = policy; + } + + private void testWallpaperAndBackgroundLocked() { + if (mWindowDetachedWallpaper != mDetachedWallpaper) { + if (WindowManagerService.DEBUG_WALLPAPER) Slog.v(TAG, + "Detached wallpaper changed from " + mWindowDetachedWallpaper + + " to " + mDetachedWallpaper); + mWindowDetachedWallpaper = mDetachedWallpaper; + mBulkUpdateParams |= SET_WALLPAPER_MAY_CHANGE; + } + + if (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 = mWindowAnimationBackground; + if (mService.mWallpaperTarget == target + || mService.mLowerWallpaperTarget == target + || mService.mUpperWallpaperTarget == target) { + final int N = mService.mWindows.size(); + for (int i = 0; i < N; i++) { + WindowState w = mService.mWindows.get(i); + if (w.mIsWallpaper) { + target = w; + break; + } + } + } + if (mWindowAnimationBackgroundSurface == null) { + mWindowAnimationBackgroundSurface = new DimSurface(mService.mFxSession); + } + final int dw = mDw; + final int dh = mDh; + mWindowAnimationBackgroundSurface.show(dw, dh, + target.mWinAnimator.mAnimLayer - WindowManagerService.LAYER_OFFSET_DIM, + mWindowAnimationBackgroundColor); + } else if (mWindowAnimationBackgroundSurface != null) { + mWindowAnimationBackgroundSurface.hide(); + } + } + + private void updateWindowsAppsAndRotationAnimationsLocked() { + int i; + final int NAT = mService.mAppTokens.size(); + for (i=0; i<NAT; i++) { + final AppWindowAnimator appAnimator = mService.mAppTokens.get(i).mAppAnimator; + final boolean wasAnimating = appAnimator.animation != null + && appAnimator.animation != WindowManagerService.sDummyAnimation; + if (appAnimator.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 " + appAnimator.mAppToken + " done", + mPendingLayoutChanges); + } + } + } + + final int NEAT = mService.mExitingAppTokens.size(); + for (i=0; i<NEAT; i++) { + final AppWindowAnimator appAnimator = mService.mExitingAppTokens.get(i).mAppAnimator; + final boolean wasAnimating = appAnimator.animation != null + && appAnimator.animation != WindowManagerService.sDummyAnimation; + if (appAnimator.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 " + appAnimator.mAppToken + + " done", mPendingLayoutChanges); + } + } + } + + if (mScreenRotationAnimation != null && + (mScreenRotationAnimation.isAnimating() || + mScreenRotationAnimation.mFinishAnimReady)) { + if (mScreenRotationAnimation.stepAnimationLocked(mCurrentTime)) { + mAnimating = true; + } else { + mBulkUpdateParams |= SET_UPDATE_ROTATION; + mScreenRotationAnimation.kill(); + mScreenRotationAnimation = null; + } + } + } + + private void updateWindowsAndWallpaperLocked() { + ++mTransactionSequence; + + for (int i = mService.mWindows.size() - 1; i >= 0; i--) { + WindowState win = mService.mWindows.get(i); + WindowStateAnimator winAnimator = win.mWinAnimator; + final int flags = winAnimator.mAttrFlags; + + if (winAnimator.mSurface != null) { + final boolean wasAnimating = winAnimator.mWasAnimating; + final boolean nowAnimating = winAnimator.stepAnimationLocked(mCurrentTime); + + if (WindowManagerService.DEBUG_WALLPAPER) { + Slog.v(TAG, win + ": 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 ((flags & FLAG_SHOW_WALLPAPER) != 0 + && winAnimator.mAnimation.getDetachWallpaper()) { + mDetachedWallpaper = win; + } + final int backgroundColor = winAnimator.mAnimation.getBackgroundColor(); + if (backgroundColor != 0) { + if (mWindowAnimationBackground == null + || (winAnimator.mAnimLayer < + mWindowAnimationBackground.mWinAnimator.mAnimLayer)) { + mWindowAnimationBackground = win; + mWindowAnimationBackgroundColor = backgroundColor; + } + } + } + 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. + final AppWindowAnimator appAnimator = + win.mAppToken == null ? null : win.mAppToken.mAppAnimator; + if (appAnimator != null && appAnimator.animation != null + && appAnimator.animating) { + if ((flags & FLAG_SHOW_WALLPAPER) != 0 + && appAnimator.animation.getDetachWallpaper()) { + mDetachedWallpaper = win; + } + final int backgroundColor = appAnimator.animation.getBackgroundColor(); + if (backgroundColor != 0) { + if (mWindowAnimationBackground == null + || (winAnimator.mAnimLayer < + mWindowAnimationBackground.mWinAnimator.mAnimLayer)) { + mWindowAnimationBackground = win; + mWindowAnimationBackgroundColor = backgroundColor; + } + } + } + + if (wasAnimating && !winAnimator.mAnimating && mService.mWallpaperTarget == win) { + mBulkUpdateParams |= SET_WALLPAPER_MAY_CHANGE; + mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; + if (WindowManagerService.DEBUG_LAYOUT_REPEATS) { + mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 2", + mPendingLayoutChanges); + } + } + + if (mPolicy.doesForceHide(win, win.mAttrs)) { + if (!wasAnimating && nowAnimating) { + if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG, + "Animation started that could impact force hide: " + + win); + mBulkUpdateParams |= SET_FORCE_HIDING_CHANGED; + mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; + if (WindowManagerService.DEBUG_LAYOUT_REPEATS) { + mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 3", + mPendingLayoutChanges); + } + mService.mFocusMayChange = true; + } else if (win.isReadyForDisplay() && winAnimator.mAnimation == null) { + mForceHiding = true; + } + } else if (mPolicy.canBeForceHidden(win, win.mAttrs)) { + final boolean changed; + if (mForceHiding) { + changed = win.hideLw(false, false); + if (WindowManagerService.DEBUG_VISIBILITY && changed) Slog.v(TAG, + "Now policy hidden: " + win); + } else { + changed = win.showLw(false, false); + if (WindowManagerService.DEBUG_VISIBILITY && changed) Slog.v(TAG, + "Now policy shown: " + win); + if (changed) { + if ((mBulkUpdateParams & SET_FORCE_HIDING_CHANGED) != 0 + && win.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 < win.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 && (flags & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) { + mBulkUpdateParams |= SET_WALLPAPER_MAY_CHANGE; + mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; + if (WindowManagerService.DEBUG_LAYOUT_REPEATS) { + mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 4", + mPendingLayoutChanges); + } + } + } + } + + final AppWindowToken atoken = win.mAppToken; + if (atoken != null && (!atoken.allDrawn || atoken.mAppAnimator.freezingScreen)) { + if (atoken.lastTransactionSequence != mTransactionSequence) { + atoken.lastTransactionSequence = mTransactionSequence; + atoken.numInterestingWindows = atoken.numDrawnWindows = 0; + atoken.startingDisplayed = false; + } + if ((win.isOnScreen() || winAnimator.mAttrType + == WindowManager.LayoutParams.TYPE_BASE_APPLICATION) + && !win.mExiting && !win.mDestroying) { + if (WindowManagerService.DEBUG_VISIBILITY || + WindowManagerService.DEBUG_ORIENTATION) { + Slog.v(TAG, "Eval win " + win + ": isDrawn=" + win.isDrawnLw() + + ", isAnimating=" + winAnimator.isAnimating()); + if (!win.isDrawnLw()) { + Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurface + + " pv=" + win.mPolicyVisibility + + " mDrawState=" + winAnimator.mDrawState + + " ah=" + win.mAttachedHidden + + " th=" + atoken.hiddenRequested + + " a=" + winAnimator.mAnimating); + } + } + if (win != atoken.startingWindow) { + if (!atoken.mAppAnimator.freezingScreen || !win.mAppFreezing) { + atoken.numInterestingWindows++; + if (win.isDrawnLw()) { + atoken.numDrawnWindows++; + if (WindowManagerService.DEBUG_VISIBILITY || + WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG, + "tokenMayBeDrawn: " + atoken + + " freezingScreen=" + atoken.mAppAnimator.freezingScreen + + " mAppFreezing=" + win.mAppFreezing); + mTokenMayBeDrawn = true; + } + } + } else if (win.isDrawnLw()) { + atoken.startingDisplayed = true; + } + } + } else if (winAnimator.mDrawState == WindowStateAnimator.READY_TO_SHOW) { + if (winAnimator.performShowLocked()) { + mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM; + if (WindowManagerService.DEBUG_LAYOUT_REPEATS) { + mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 5", + mPendingLayoutChanges); + } + } + } + final AppWindowAnimator appAnimator = + atoken == null ? null : atoken.mAppAnimator; + if (appAnimator != null && appAnimator.thumbnail != null) { + if (appAnimator.thumbnailTransactionSeq != mTransactionSequence) { + appAnimator.thumbnailTransactionSeq = mTransactionSequence; + appAnimator.thumbnailLayer = 0; + } + if (appAnimator.thumbnailLayer < winAnimator.mAnimLayer) { + appAnimator.thumbnailLayer = winAnimator.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.mAppAnimator.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.mAppAnimator.showAllWindowsLocked(); + mService.unsetAppFreezingScreenLocked(wtoken, false, true); + if (WindowManagerService.DEBUG_ORIENTATION) Slog.i(TAG, + "Setting mOrientationChangeComplete=true because wtoken " + + wtoken + " numInteresting=" + numInteresting + + " numDrawn=" + wtoken.numDrawnWindows); + } + } 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", + mPendingLayoutChanges); + } + + // We can now show all of the drawn windows! + if (!mService.mOpeningApps.contains(wtoken)) { + mAnimating |= wtoken.mAppAnimator.showAllWindowsLocked(); + } + } + } + } + } + + private void performAnimationsLocked() { + mTokenMayBeDrawn = false; + mForceHiding = false; + mDetachedWallpaper = null; + mWindowAnimationBackground = null; + mWindowAnimationBackgroundColor = 0; + + updateWindowsAndWallpaperLocked(); + + if (mTokenMayBeDrawn) { + testTokenMayBeDrawnLocked(); + } + } + + void animate() { + mPendingLayoutChanges = 0; + mCurrentTime = SystemClock.uptimeMillis(); + mBulkUpdateParams = 0; + + // Update animations of all applications, including those + // associated with exiting/removed apps + Surface.openTransaction(); + + try { + testWallpaperAndBackgroundLocked(); + updateWindowsAppsAndRotationAnimationsLocked(); + performAnimationsLocked(); + + // THIRD LOOP: Update the surfaces of all windows. + + if (mScreenRotationAnimation != null) { + mScreenRotationAnimation.updateSurfaces(); + } + + mFinished.clear(); + for (final WindowStateAnimator winAnimator : mWinAnimators) { + if (winAnimator.mSurface == null) { + mFinished.add(winAnimator); + } else { + winAnimator.prepareSurfaceLocked(true); + } + } + for (final WindowStateAnimator winAnimator : mFinished) { + mWinAnimators.remove(winAnimator); + } + + if (mDimParams != null) { + mDimAnimator.updateParameters(mContext.getResources(), mDimParams, mCurrentTime); + } + if (mDimAnimator != null && mDimAnimator.mDimShown) { + mAnimating |= mDimAnimator.updateSurface(mDimParams != null, 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(); + } + + if (mBulkUpdateParams != 0) { + mService.bulkSetParameters(mBulkUpdateParams); + } + } + + WindowState mCurrentFocus; + void setCurrentFocus(final 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; + } + + void startDimming(final WindowStateAnimator winAnimator, final float target, + final int width, final int height) { + if (mDimAnimator == null) { + mDimAnimator = new DimAnimator(mService.mFxSession); + } + mService.mH.sendMessage(mService.mH.obtainMessage(SET_DIM_PARAMETERS, + new DimAnimator.Parameters(winAnimator, width, height, target))); + } + + // TODO(cmautner): Move into Handler + void stopDimming() { + mService.mH.sendMessage(mService.mH.obtainMessage(SET_DIM_PARAMETERS, null)); + } + + public void dump(PrintWriter pw, String prefix, boolean dumpAll) { + if (mWindowDetachedWallpaper != null) { + pw.print(" mWindowDetachedWallpaper="); pw.println(mWindowDetachedWallpaper); + } + if (mWindowAnimationBackgroundSurface != null) { + pw.println(" mWindowAnimationBackgroundSurface:"); + mWindowAnimationBackgroundSurface.printTo(" ", pw); + } + if (mDimAnimator != null) { + pw.println(" mDimAnimator:"); + mDimAnimator.printTo(" ", pw); + } else { + pw.println( " no DimAnimator "); + } + } + + static class SetAnimationParams { + final WindowStateAnimator mWinAnimator; + final Animation mAnimation; + final int mAnimDw; + final int mAnimDh; + public SetAnimationParams(final WindowStateAnimator winAnimator, + final Animation animation, final int animDw, final int animDh) { + mWinAnimator = winAnimator; + mAnimation = animation; + mAnimDw = animDw; + mAnimDh = animDh; + } + } +} diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 008793c..6f7852d 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; @@ -45,6 +44,8 @@ import com.android.server.EventLogTags; import com.android.server.PowerManagerService; import com.android.server.Watchdog; import com.android.server.am.BatteryStatsService; +import com.android.server.input.InputFilter; +import com.android.server.input.InputManagerService; import android.Manifest; import android.app.ActivityManagerNative; @@ -90,6 +91,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 +120,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 +173,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 = true; 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 +208,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; @@ -231,10 +245,6 @@ public class WindowManagerService extends IWindowManager.Stub */ static final boolean CUSTOM_SCREEN_ROTATION = true; - // Maximum number of milliseconds to wait for input event injection. - // FIXME is this value reasonable? - private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000; - // Maximum number of milliseconds to wait for input devices to be enumerated before // proceding with safe mode detection. private static final int INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS = 1000; @@ -415,17 +425,11 @@ public class WindowManagerService extends IWindowManager.Stub IInputMethodManager mInputMethodManager; SurfaceSession mFxSession; - private DimAnimator mDimAnimator = null; - Surface mBlurSurface; - boolean mBlurShown; Watermark mWatermark; StrictModeFlash mStrictModeFlash; - ScreenRotationAnimation mScreenRotationAnimation; BlackFrame mBlackFrame; - int mTransactionSequence = 0; - final float[] mTmpFloats = new float[9]; boolean mSafeMode; @@ -461,6 +465,7 @@ public class WindowManagerService extends IWindowManager.Stub = new ArrayList<IRotationWatcher>(); int mDeferredRotationPauseCount; + int mPendingLayoutChanges = 0; boolean mLayoutNeeded = true; boolean mTraversalScheduled = false; boolean mDisplayFrozen = false; @@ -490,8 +495,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; @@ -542,12 +551,6 @@ public class WindowManagerService extends IWindowManager.Stub // If non-null, we are in the middle of animating from one wallpaper target // to another, and this is the higher one in Z-order. WindowState mUpperWallpaperTarget = null; - // Window currently running an animation that has requested it be detached - // from the wallpaper. This means we need to ensure the wallpaper is - // visible behind it in case it animates in a way that would allow it to be - // seen. - WindowState mWindowDetachedWallpaper = null; - DimSurface mWindowAnimationBackgroundSurface = null; int mWallpaperAnimLayerAdjustment; float mLastWallpaperX = -1; float mLastWallpaperY = -1; @@ -571,7 +574,7 @@ public class WindowManagerService extends IWindowManager.Stub float mTransitionAnimationScale = 1.0f; float mAnimatorDurationScale = 1.0f; - final InputManager mInputManager; + final InputManagerService mInputManager; // Who is holding the screen on. Session mHoldingScreenOn; @@ -583,27 +586,28 @@ 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; - private int mAdjResult = 0; + class LayoutFields { + static final int SET_UPDATE_ROTATION = 1 << 0; + static final int SET_WALLPAPER_MAY_CHANGE = 1 << 1; + static final int SET_FORCE_HIDING_CHANGED = 1 << 2; + static final int CLEAR_ORIENTATION_CHANGE_COMPLETE = 1 << 3; + + boolean mWallpaperForceHidingChanged = false; + boolean mWallpaperMayChange = false; + boolean mOrientationChangeComplete = true; + 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(); + LayoutFields mInnerFields = new LayoutFields(); + + /** Only do a maximum of 6 repeated layouts. After that quit */ + private int mLayoutRepeatCount; private final class AnimationRunnable implements Runnable { @Override @@ -616,6 +620,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) { @@ -734,6 +740,7 @@ public class WindowManagerService extends IWindowManager.Stub mAllowBootMessages = allowBootMsgs; } + @Override public void run() { Looper.prepare(); WindowManagerService s = new WindowManagerService(mContext, mPM, @@ -773,6 +780,7 @@ public class WindowManagerService extends IWindowManager.Stub mPM = pm; } + @Override public void run() { Looper.prepare(); WindowManagerPolicyThread.set(this, Looper.myLooper()); @@ -834,7 +842,8 @@ public class WindowManagerService extends IWindowManager.Stub "KEEP_SCREEN_ON_FLAG"); mHoldingScreenWakeLock.setReferenceCounted(false); - mInputManager = new InputManager(context, this); + mInputManager = new InputManagerService(context, mInputMonitor); + mAnimator = new WindowAnimator(this, context, mPolicy); PolicyThread thr = new PolicyThread(mPolicy, this, context, pm); thr.start(); @@ -854,6 +863,10 @@ public class WindowManagerService extends IWindowManager.Stub Watchdog.getInstance().addMonitor(this); } + public InputManagerService getInputManagerService() { + return mInputManager; + } + @Override public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { @@ -1118,7 +1131,8 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_INPUT_METHOD) { Slog.i(TAG, "isVisibleOrAdding " + w + ": " + w.isVisibleOrAdding()); if (!w.isVisibleOrAdding()) { - Slog.i(TAG, " mSurface=" + w.mSurface + " reportDestroy=" + w.mReportDestroySurface + Slog.i(TAG, " mSurface=" + w.mWinAnimator.mSurface + " reportDestroy=" + + w.mWinAnimator.mReportDestroySurface + " relayoutCalled=" + w.mRelayoutCalled + " viewVis=" + w.mViewVisibility + " policyVis=" + w.mPolicyVisibility + " attachHid=" + w.mAttachedHidden + " exiting=" + w.mExiting + " destroying=" + w.mDestroying); @@ -1182,7 +1196,7 @@ public class WindowManagerService extends IWindowManager.Stub if (mInputMethodTarget != null && w != null && mInputMethodTarget.isDisplayedLw() && mInputMethodTarget.mExiting) { - if (mInputMethodTarget.mAnimLayer > w.mAnimLayer) { + if (mInputMethodTarget.mWinAnimator.mAnimLayer > w.mWinAnimator.mAnimLayer) { w = mInputMethodTarget; i = localmWindows.indexOf(w); if (DEBUG_INPUT_METHOD) Slog.v(TAG, "Current target higher, switching to: " + w); @@ -1203,7 +1217,7 @@ public class WindowManagerService extends IWindowManager.Stub AppWindowToken token = curTarget.mAppToken; WindowState highestTarget = null; int highestPos = 0; - if (token.animating || token.animation != null) { + if (token.mAppAnimator.animating || token.mAppAnimator.animation != null) { int pos = localmWindows.indexOf(curTarget); while (pos >= 0) { WindowState win = localmWindows.get(pos); @@ -1211,8 +1225,8 @@ public class WindowManagerService extends IWindowManager.Stub break; } if (!win.mRemoved) { - if (highestTarget == null || win.mAnimLayer > - highestTarget.mAnimLayer) { + if (highestTarget == null || win.mWinAnimator.mAnimLayer > + highestTarget.mWinAnimator.mAnimLayer) { highestTarget = win; highestPos = pos; } @@ -1224,9 +1238,9 @@ public class WindowManagerService extends IWindowManager.Stub if (highestTarget != null) { if (DEBUG_INPUT_METHOD) Slog.v(TAG, "mNextAppTransition=" + mNextAppTransition + " " + highestTarget - + " animating=" + highestTarget.isAnimating() - + " layer=" + highestTarget.mAnimLayer - + " new layer=" + w.mAnimLayer); + + " animating=" + highestTarget.mWinAnimator.isAnimating() + + " layer=" + highestTarget.mWinAnimator.mAnimLayer + + " new layer=" + w.mWinAnimator.mAnimLayer); if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { // If we are currently setting up for an animation, @@ -1234,8 +1248,8 @@ public class WindowManagerService extends IWindowManager.Stub mInputMethodTargetWaitingAnim = true; mInputMethodTarget = highestTarget; return highestPos + 1; - } else if (highestTarget.isAnimating() && - highestTarget.mAnimLayer > w.mAnimLayer) { + } else if (highestTarget.mWinAnimator.isAnimating() && + highestTarget.mWinAnimator.mAnimLayer > w.mWinAnimator.mAnimLayer) { // If the window we are currently targeting is involved // with an animation, and it is on top of the next target // we will be over, then hold off on moving until @@ -1263,7 +1277,7 @@ public class WindowManagerService extends IWindowManager.Stub mInputMethodTarget = w; mInputMethodTargetWaitingAnim = false; if (w.mAppToken != null) { - setInputMethodAnimLayerAdjustment(w.mAppToken.animLayerAdjustment); + setInputMethodAnimLayerAdjustment(w.mAppToken.mAppAnimator.animLayerAdjustment); } else { setInputMethodAnimLayerAdjustment(0); } @@ -1307,25 +1321,25 @@ public class WindowManagerService extends IWindowManager.Stub mInputMethodAnimLayerAdjustment = adj; WindowState imw = mInputMethodWindow; if (imw != null) { - imw.mAnimLayer = imw.mLayer + adj; + imw.mWinAnimator.mAnimLayer = imw.mLayer + adj; if (DEBUG_LAYERS) Slog.v(TAG, "IM win " + imw - + " anim layer: " + imw.mAnimLayer); + + " anim layer: " + imw.mWinAnimator.mAnimLayer); int wi = imw.mChildWindows.size(); while (wi > 0) { wi--; WindowState cw = imw.mChildWindows.get(wi); - cw.mAnimLayer = cw.mLayer + adj; + cw.mWinAnimator.mAnimLayer = cw.mLayer + adj; if (DEBUG_LAYERS) Slog.v(TAG, "IM win " + cw - + " anim layer: " + cw.mAnimLayer); + + " anim layer: " + cw.mWinAnimator.mAnimLayer); } } int di = mInputMethodDialogs.size(); while (di > 0) { di --; imw = mInputMethodDialogs.get(di); - imw.mAnimLayer = imw.mLayer + adj; + imw.mWinAnimator.mAnimLayer = imw.mLayer + adj; if (DEBUG_LAYERS) Slog.v(TAG, "IM win " + imw - + " anim layer: " + imw.mAnimLayer); + + " anim layer: " + imw.mWinAnimator.mAnimLayer); } } @@ -1523,15 +1537,15 @@ public class WindowManagerService extends IWindowManager.Stub } final boolean isWallpaperVisible(WindowState wallpaperTarget) { - if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper vis: target obscured=" + if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper vis: target " + wallpaperTarget + ", obscured=" + (wallpaperTarget != null ? Boolean.toString(wallpaperTarget.mObscured) : "??") + " anim=" + ((wallpaperTarget != null && wallpaperTarget.mAppToken != null) - ? wallpaperTarget.mAppToken.animation : null) + ? wallpaperTarget.mAppToken.mAppAnimator.animation : null) + " upper=" + mUpperWallpaperTarget + " lower=" + mLowerWallpaperTarget); return (wallpaperTarget != null && (!wallpaperTarget.mObscured || (wallpaperTarget.mAppToken != null - && wallpaperTarget.mAppToken.animation != null))) + && wallpaperTarget.mAppToken.mAppAnimator.animation != null))) || mUpperWallpaperTarget != null || mLowerWallpaperTarget != null; } @@ -1540,6 +1554,7 @@ public class WindowManagerService extends IWindowManager.Stub static final int ADJUST_WALLPAPER_VISIBILITY_CHANGED = 1<<2; int adjustWallpaperWindowsLocked() { + mInnerFields.mWallpaperMayChange = false; int changed = 0; final int dw = mAppDisplayWidth; @@ -1567,28 +1582,26 @@ public class WindowManagerService extends IWindowManager.Stub continue; } topCurW = null; - if (w != mWindowDetachedWallpaper && w.mAppToken != null) { + if (w != mAnimator.mWindowDetachedWallpaper && w.mAppToken != null) { // If this window's app token is hidden and not animating, // it is of no interest to us. - if (w.mAppToken.hidden && w.mAppToken.animation == null) { + if (w.mAppToken.hidden && w.mAppToken.mAppAnimator.animation == null) { if (DEBUG_WALLPAPER) Slog.v(TAG, "Skipping not hidden or animating token: " + w); continue; } } if (DEBUG_WALLPAPER) Slog.v(TAG, "Win " + w + ": readyfordisplay=" - + w.isReadyForDisplay() + " drawpending=" + w.mDrawPending - + " commitdrawpending=" + w.mCommitDrawPending); + + w.isReadyForDisplay() + " mDrawState=" + w.mWinAnimator.mDrawState); if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0 && w.isReadyForDisplay() - && (mWallpaperTarget == w - || (!w.mDrawPending && !w.mCommitDrawPending))) { + && (mWallpaperTarget == w || w.isDrawnLw())) { if (DEBUG_WALLPAPER) Slog.v(TAG, "Found wallpaper activity: #" + i + "=" + w); foundW = w; foundI = i; if (w == mWallpaperTarget && ((w.mAppToken != null - && w.mAppToken.animation != null) - || w.mAnimation != null)) { + && w.mAppToken.mAppAnimator.animation != 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. @@ -1597,7 +1610,7 @@ public class WindowManagerService extends IWindowManager.Stub continue; } break; - } else if (w == mWindowDetachedWallpaper) { + } else if (w == mAnimator.mWindowDetachedWallpaper) { windowDetachedI = i; } } @@ -1645,10 +1658,12 @@ 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 - || (oldW.mAppToken != null && oldW.mAppToken.animation != null); - boolean foundAnim = foundW.mAnimation != null - || (foundW.mAppToken != null && foundW.mAppToken.animation != null); + boolean oldAnim = oldW.mWinAnimator.mAnimation != null + || (oldW.mAppToken != null + && oldW.mAppToken.mAppAnimator.animation != null); + boolean foundAnim = foundW.mWinAnimator.mAnimation != null + || (foundW.mAppToken != null && + foundW.mAppToken.mAppAnimator.animation != null); if (DEBUG_WALLPAPER) { Slog.v(TAG, "New animation: " + foundAnim + " old animation: " + oldAnim); @@ -1699,12 +1714,12 @@ 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 + && mLowerWallpaperTarget.mAppToken.mAppAnimator.animation != null); + boolean upperAnimating = mUpperWallpaperTarget.mWinAnimator.mAnimation != null || (mUpperWallpaperTarget.mAppToken != null - && mUpperWallpaperTarget.mAppToken.animation != null); + && mUpperWallpaperTarget.mAppToken.mAppAnimator.animation != null); if (!lowerAnimating || !upperAnimating) { if (DEBUG_WALLPAPER) { Slog.v(TAG, "No longer animating wallpaper targets!"); @@ -1726,7 +1741,7 @@ public class WindowManagerService extends IWindowManager.Stub // between two wallpaper targets. mWallpaperAnimLayerAdjustment = (mLowerWallpaperTarget == null && foundW.mAppToken != null) - ? foundW.mAppToken.animLayerAdjustment : 0; + ? foundW.mAppToken.mAppAnimator.animLayerAdjustment : 0; final int maxLayer = mPolicy.getMaxWallpaperLayer() * TYPE_LAYER_MULTIPLIER @@ -1813,9 +1828,9 @@ public class WindowManagerService extends IWindowManager.Stub } } - wallpaper.mAnimLayer = wallpaper.mLayer + mWallpaperAnimLayerAdjustment; + wallpaper.mWinAnimator.mAnimLayer = wallpaper.mLayer + mWallpaperAnimLayerAdjustment; if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper win " - + wallpaper + " anim layer: " + wallpaper.mAnimLayer); + + wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer); // First, if this window is at the current index, then all // is well. @@ -1867,9 +1882,9 @@ public class WindowManagerService extends IWindowManager.Stub while (curWallpaperIndex > 0) { curWallpaperIndex--; WindowState wallpaper = token.windows.get(curWallpaperIndex); - wallpaper.mAnimLayer = wallpaper.mLayer + adj; + wallpaper.mWinAnimator.mAnimLayer = wallpaper.mLayer + adj; if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper win " - + wallpaper + " anim layer: " + wallpaper.mAnimLayer); + + wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer); } } } @@ -1910,7 +1925,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 " @@ -1961,6 +1976,11 @@ public class WindowManagerService extends IWindowManager.Stub } } + // TODO(cmautner): Move to WindowAnimator. + void setWallpaperOffset(final WindowStateAnimator winAnimator, final int left, final int top) { + mH.sendMessage(mH.obtainMessage(H.SET_WALLPAPER_OFFSET, left, top, winAnimator)); + } + void updateWallpaperOffsetLocked(WindowState changingTarget, boolean sync) { final int dw = mAppDisplayWidth; final int dh = mAppDisplayHeight; @@ -1988,20 +2008,20 @@ public class WindowManagerService extends IWindowManager.Stub curWallpaperIndex--; WindowState wallpaper = token.windows.get(curWallpaperIndex); if (updateWallpaperOffsetLocked(wallpaper, dw, dh, sync)) { - wallpaper.computeShownFrameLocked(); + WindowStateAnimator winAnimator = wallpaper.mWinAnimator; + winAnimator.computeShownFrameLocked(); // No need to lay out the windows - we can just set the wallpaper position // directly. - if (wallpaper.mSurfaceX != wallpaper.mShownFrame.left - || wallpaper.mSurfaceY != wallpaper.mShownFrame.top) { + // TODO(cmautner): Don't move this from here, just lock the WindowAnimator. + if (winAnimator.mSurfaceX != wallpaper.mShownFrame.left + || winAnimator.mSurfaceY != wallpaper.mShownFrame.top) { Surface.openTransaction(); try { if (SHOW_TRANSACTIONS) logSurface(wallpaper, "POS " + wallpaper.mShownFrame.left + ", " + wallpaper.mShownFrame.top, null); - wallpaper.mSurfaceX = wallpaper.mShownFrame.left; - wallpaper.mSurfaceY = wallpaper.mShownFrame.top; - wallpaper.mSurface.setPosition(wallpaper.mShownFrame.left, - wallpaper.mShownFrame.top); + setWallpaperOffset(winAnimator, (int) wallpaper.mShownFrame.left, + (int) wallpaper.mShownFrame.top); } catch (RuntimeException e) { Slog.w(TAG, "Error positioning surface of " + wallpaper + " pos=(" + wallpaper.mShownFrame.left @@ -2210,14 +2230,14 @@ public class WindowManagerService extends IWindowManager.Stub } } - win.mEnterAnimationPending = true; + win.mWinAnimator.mEnterAnimationPending = true; mPolicy.getContentInsetHintLw(attrs, outContentInsets); 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; } @@ -2281,18 +2301,18 @@ public class WindowManagerService extends IWindowManager.Stub TAG, "Remove " + win + " client=" + Integer.toHexString(System.identityHashCode( win.mClient.asBinder())) - + ", surface=" + win.mSurface); + + ", surface=" + win.mWinAnimator.mSurface); final long origId = Binder.clearCallingIdentity(); - + win.disposeInputChannel(); if (DEBUG_APP_TRANSITIONS) Slog.v( - TAG, "Remove " + win + ": mSurface=" + win.mSurface + TAG, "Remove " + win + ": mSurface=" + win.mWinAnimator.mSurface + " mExiting=" + win.mExiting - + " isAnimating=" + win.isAnimating() + + " isAnimating=" + win.mWinAnimator.isAnimating() + " app-animation=" - + (win.mAppToken != null ? win.mAppToken.animation : null) + + (win.mAppToken != null ? win.mAppToken.mAppAnimator.animation : null) + " inPendingTransaction=" + (win.mAppToken != null ? win.mAppToken.inPendingTransaction : false) + " mDisplayFrozen=" + mDisplayFrozen); @@ -2302,22 +2322,22 @@ 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.mHasSurface && 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. - if (applyAnimationLocked(win, transit, false)) { + if (win.mWinAnimator.applyAnimationLocked(transit, false)) { 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; @@ -2446,33 +2466,36 @@ public class WindowManagerService extends IWindowManager.Stub } static void logSurface(WindowState w, String msg, RuntimeException where) { - String str = " SURFACE " + Integer.toHexString(w.hashCode()) - + ": " + msg + " / " + w.mAttrs.getTitle(); + String str = " SURFACE " + msg + ": " + w; if (where != null) { Slog.i(TAG, str, where); } else { 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); + } + } + + // TODO(cmautner): Move to WindowStateAnimator. + void setTransparentRegionHint(final WindowStateAnimator winAnimator, final Region region) { + mH.sendMessage(mH.obtainMessage(H.SET_TRANSPARENT_REGION, + new Pair<WindowStateAnimator, Region>(winAnimator, region))); + } + void setTransparentRegionWindow(Session session, IWindow client, Region region) { long origId = Binder.clearCallingIdentity(); try { synchronized (mWindowMap) { WindowState w = windowForClientLocked(session, client, false); - if ((w != null) && (w.mSurface != null)) { - if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, - ">>> OPEN TRANSACTION setTransparentRegion"); - Surface.openTransaction(); - try { - if (SHOW_TRANSACTIONS) logSurface(w, - "transparentRegionHint=" + region, null); - w.mSurface.setTransparentRegionHint(region); - } finally { - Surface.closeTransaction(); - if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, - "<<< CLOSE TRANSACTION setTransparentRegion"); - } + if ((w != null) && w.mHasSurface) { + setTransparentRegionHint(w.mWinAnimator, region); } } } finally { @@ -2595,10 +2618,12 @@ public class WindowManagerService extends IWindowManager.Stub long origId = Binder.clearCallingIdentity(); synchronized(mWindowMap) { + // TODO(cmautner): synchronize on mAnimator or win.mWinAnimator. WindowState win = windowForClientLocked(session, client, false); if (win == null) { return 0; } + WindowStateAnimator winAnimator = win.mWinAnimator; if (win.mRequestedWidth != requestedWidth || win.mRequestedHeight != requestedHeight) { win.mLayoutNeeded = true; @@ -2613,7 +2638,7 @@ public class WindowManagerService extends IWindowManager.Stub mPolicy.adjustWindowParamsLw(attrs); } - win.mSurfaceDestroyDeferred = + winAnimator.mSurfaceDestroyDeferred = (flags&WindowManagerImpl.RELAYOUT_DEFER_SURFACE_DESTROY) != 0; int attrChanges = 0; @@ -2625,7 +2650,8 @@ public class WindowManagerService extends IWindowManager.Stub } flagChanges = win.mAttrs.flags ^= attrs.flags; attrChanges = win.mAttrs.copyFrom(attrs); - if ((attrChanges&WindowManager.LayoutParams.LAYOUT_CHANGED) != 0) { + if ((attrChanges & (WindowManager.LayoutParams.LAYOUT_CHANGED + | WindowManager.LayoutParams.SYSTEM_UI_VISIBILITY_CHANGED)) != 0) { win.mLayoutNeeded = true; } } @@ -2635,7 +2661,7 @@ public class WindowManagerService extends IWindowManager.Stub win.mEnforceSizeCompat = (win.mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0; if ((attrChanges & WindowManager.LayoutParams.ALPHA_CHANGED) != 0) { - win.mAlpha = attrs.alpha; + winAnimator.mAlpha = attrs.alpha; } final boolean scaledWindow = @@ -2677,20 +2703,19 @@ public class WindowManagerService extends IWindowManager.Stub (win.mAppToken == null || !win.mAppToken.clientHidden)) { displayed = !win.isVisibleLw(); if (win.mExiting) { - win.cancelExitAnimationForNextAnimationLocked(); + winAnimator.cancelExitAnimationForNextAnimationLocked(); + win.mExiting = false; } if (win.mDestroying) { win.mDestroying = false; mDestroySurface.remove(win); } if (oldVisibility == View.GONE) { - win.mEnterAnimationPending = true; + winAnimator.mEnterAnimationPending = true; } if (displayed) { - if (win.mSurface != null && !win.mDrawPending - && !win.mCommitDrawPending && !mDisplayFrozen - && mDisplayEnabled && mPolicy.isScreenOnFully()) { - applyEnterAnimationLocked(win); + if (win.isDrawnLw() && okToDisplay()) { + winAnimator.applyEnterAnimationLocked(); } if ((win.mAttrs.flags & WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON) != 0) { @@ -2713,19 +2738,19 @@ public class WindowManagerService extends IWindowManager.Stub } if ((attrChanges&WindowManager.LayoutParams.FORMAT_CHANGED) != 0) { // To change the format, we need to re-build the surface. - win.destroySurfaceLocked(); + winAnimator.destroySurfaceLocked(); displayed = true; surfaceChanged = true; } try { - if (win.mSurface == null) { + if (!win.mHasSurface) { surfaceChanged = true; } - Surface surface = win.createSurfaceLocked(); + Surface surface = winAnimator.createSurfaceLocked(); if (surface != null) { outSurface.copyFrom(surface); - win.mReportDestroySurface = false; - win.mSurfacePendingDestroy = false; + winAnimator.mReportDestroySurface = false; + winAnimator.mSurfacePendingDestroy = false; if (SHOW_TRANSACTIONS) Slog.i(TAG, " OUT SURFACE " + outSurface + ": copied"); } else { @@ -2764,26 +2789,26 @@ public class WindowManagerService extends IWindowManager.Stub sa.flags = (sa.flags&~mask) | (win.mAttrs.flags&mask); } } else { - win.mEnterAnimationPending = false; - if (win.mSurface != null) { + winAnimator.mEnterAnimationPending = false; + if (winAnimator.mSurface != null) { if (DEBUG_VISIBILITY) Slog.i(TAG, "Relayout invis " + win + ": mExiting=" + win.mExiting - + " mSurfacePendingDestroy=" + win.mSurfacePendingDestroy); + + " mSurfacePendingDestroy=" + winAnimator.mSurfacePendingDestroy); // If we are not currently running the exit animation, we // need to see about starting one. - if (!win.mExiting || win.mSurfacePendingDestroy) { + if (!win.mExiting || winAnimator.mSurfacePendingDestroy) { surfaceChanged = true; // 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)) { + if (!winAnimator.mSurfacePendingDestroy && win.isWinVisibleLw() && + winAnimator.applyAnimationLocked(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; @@ -2792,31 +2817,31 @@ 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; } - win.destroySurfaceLocked(); + winAnimator.destroySurfaceLocked(); } } } - if (win.mSurface == null || (win.getAttrs().flags + if (winAnimator.mSurface == null || (win.getAttrs().flags & WindowManager.LayoutParams.FLAG_KEEP_SURFACE_WHILE_ANIMATING) == 0 - || win.mSurfacePendingDestroy) { + || winAnimator.mSurfacePendingDestroy) { // We could be called from a local process, which // means outSurface holds its current surface. Ensure the // surface object is cleared, but we don't necessarily want // it actually destroyed at this point. - win.mSurfacePendingDestroy = false; + winAnimator.mSurfacePendingDestroy = false; outSurface.release(); if (DEBUG_VISIBILITY) Slog.i(TAG, "Releasing surface in: " + win); - } else if (win.mSurface != null) { + } else if (winAnimator.mSurface != null) { if (DEBUG_VISIBILITY) Slog.i(TAG, "Keeping surface, will report destroy: " + win); - win.mReportDestroySurface = true; - outSurface.copyFrom(win.mSurface); + winAnimator.mReportDestroySurface = true; + outSurface.copyFrom(winAnimator.mSurface); } } @@ -2901,7 +2926,7 @@ public class WindowManagerService extends IWindowManager.Stub if (win == null) { return; } - win.destroyDeferredSurfaceLocked(); + win.mWinAnimator.destroyDeferredSurfaceLocked(); } } finally { Binder.restoreCallingIdentity(origId); @@ -2917,7 +2942,7 @@ public class WindowManagerService extends IWindowManager.Stub if (win == null) { return false; } - return reclaimSomeSurfaceMemoryLocked(win, "from-client", false); + return reclaimSomeSurfaceMemoryLocked(win.mWinAnimator, "from-client", false); } } finally { Binder.restoreCallingIdentity(origId); @@ -2928,7 +2953,7 @@ public class WindowManagerService extends IWindowManager.Stub final long origId = Binder.clearCallingIdentity(); synchronized(mWindowMap) { WindowState win = windowForClientLocked(session, client, false); - if (win != null && win.finishDrawingLocked()) { + if (win != null && win.mWinAnimator.finishDrawingLocked()) { if ((win.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0) { adjustWallpaperWindowsLocked(); } @@ -2982,77 +3007,7 @@ public class WindowManagerService extends IWindowManager.Stub return null; } - void applyEnterAnimationLocked(WindowState win) { - int transit = WindowManagerPolicy.TRANSIT_SHOW; - if (win.mEnterAnimationPending) { - win.mEnterAnimationPending = false; - transit = WindowManagerPolicy.TRANSIT_ENTER; - } - - applyAnimationLocked(win, transit, true); - } - - boolean applyAnimationLocked(WindowState win, - int transit, boolean isEntrance) { - if (win.mLocalAnimating && win.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; - } - - // 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()) { - int anim = mPolicy.selectAnimationLw(win, transit); - int attr = -1; - Animation a = null; - if (anim != 0) { - a = AnimationUtils.loadAnimation(mContext, anim); - } else { - switch (transit) { - case WindowManagerPolicy.TRANSIT_ENTER: - attr = com.android.internal.R.styleable.WindowAnimation_windowEnterAnimation; - break; - case WindowManagerPolicy.TRANSIT_EXIT: - attr = com.android.internal.R.styleable.WindowAnimation_windowExitAnimation; - break; - case WindowManagerPolicy.TRANSIT_SHOW: - attr = com.android.internal.R.styleable.WindowAnimation_windowShowAnimation; - break; - case WindowManagerPolicy.TRANSIT_HIDE: - attr = com.android.internal.R.styleable.WindowAnimation_windowHideAnimation; - break; - } - if (attr >= 0) { - a = loadAnimation(win.mAttrs, attr); - } - } - if (DEBUG_ANIM) Slog.v(TAG, "applyAnimation: win=" + win - + " anim=" + anim + " attr=0x" + Integer.toHexString(attr) - + " mAnimation=" + win.mAnimation - + " isEntrance=" + isEntrance); - if (a != null) { - if (DEBUG_ANIM) { - RuntimeException e = null; - if (!HIDE_STACK_CRAWLS) { - e = new RuntimeException(); - e.fillInStackTrace(); - } - Slog.v(TAG, "Loaded animation " + a + " for " + win, e); - } - win.setAnimation(a); - win.mAnimationIsEntrance = isEntrance; - } - } else { - win.clearAnimation(); - } - - return win.mAnimation != null; - } - - private Animation loadAnimation(WindowManager.LayoutParams lp, int animAttr) { + Animation loadAnimation(WindowManager.LayoutParams lp, int animAttr) { int anim = 0; Context context = mContext; if (animAttr >= 0) { @@ -3084,15 +3039,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 { @@ -3164,13 +3180,13 @@ public class WindowManagerService extends IWindowManager.Stub } Slog.v(TAG, "Loaded animation " + a + " for " + wtoken, e); } - wtoken.setAnimation(a); + wtoken.mAppAnimator.setAnimation(a, initialized); } } else { - wtoken.clearAnimation(); + wtoken.mAppAnimator.clearAnimation(); } - return wtoken.animation != null; + return wtoken.mAppAnimator.animation != null; } // ------------------------------------------------------------- @@ -3223,6 +3239,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); @@ -3232,6 +3252,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()")) { @@ -3272,13 +3293,12 @@ 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; } if (win.isVisibleNow()) { - applyAnimationLocked(win, - WindowManagerPolicy.TRANSIT_EXIT, false); + win.mWinAnimator.applyAnimationLocked(WindowManagerPolicy.TRANSIT_EXIT, false); changed = true; } } @@ -3311,7 +3331,7 @@ public class WindowManagerService extends IWindowManager.Stub "addAppToken()")) { throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); } - + // Get the dispatching timeout here while we are not holding any locks so that it // can be cached by the AppWindowToken. The timeout value is used later by the // input dispatcher in code that does hold locks. If we did not cache the value @@ -3399,15 +3419,13 @@ public class WindowManagerService extends IWindowManager.Stub } public int getOrientationFromAppTokensLocked() { - int pos = mAppTokens.size() - 1; int curGroup = 0; int lastOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; boolean findingBehind = false; boolean haveGroup = false; boolean lastFullscreen = false; - while (pos >= 0) { + for (int pos = mAppTokens.size() - 1; pos >= 0; pos--) { AppWindowToken wtoken = mAppTokens.get(pos); - pos--; if (DEBUG_APP_ORIENTATION) Slog.v(TAG, "Checking app orientation: " + wtoken); @@ -3537,7 +3555,6 @@ public class WindowManagerService extends IWindowManager.Stub * android.os.IBinder) */ boolean updateOrientationFromAppTokensLocked(boolean inTransaction) { - boolean changed = false; long ident = Binder.clearCallingIdentity(); try { int req = computeForcedAppOrientationLocked(); @@ -3548,11 +3565,12 @@ public class WindowManagerService extends IWindowManager.Stub //action like disabling/enabling sensors etc., mPolicy.setCurrentOrientationLw(req); if (updateRotationUncheckedLocked(inTransaction)) { - changed = true; + // changed + return true; } } - return changed; + return false; } finally { Binder.restoreCallingIdentity(ident); } @@ -3654,7 +3672,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; @@ -3688,11 +3706,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()")) { @@ -3738,7 +3768,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; } @@ -3804,14 +3834,16 @@ public class WindowManagerService extends IWindowManager.Stub wtoken.clientHidden = ttoken.clientHidden; wtoken.sendAppVisibilityToClients(); } - if (ttoken.animation != null) { - wtoken.animation = ttoken.animation; - wtoken.animating = ttoken.animating; - wtoken.animLayerAdjustment = ttoken.animLayerAdjustment; - ttoken.animation = null; - ttoken.animLayerAdjustment = 0; - wtoken.updateLayers(); - ttoken.updateLayers(); + final AppWindowAnimator tAppAnimator = ttoken.mAppAnimator; + final AppWindowAnimator wAppAnimator = wtoken.mAppAnimator; + if (tAppAnimator.animation != null) { + wAppAnimator.animation = tAppAnimator.animation; + wAppAnimator.animating = tAppAnimator.animating; + wAppAnimator.animLayerAdjustment = tAppAnimator.animLayerAdjustment; + tAppAnimator.animation = null; + tAppAnimator.animLayerAdjustment = 0; + wAppAnimator.updateLayers(); + tAppAnimator.updateLayers(); } updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES, @@ -3836,6 +3868,21 @@ public class WindowManagerService extends IWindowManager.Stub mH.sendMessageAtFrontOfQueue(m); return; } + final AppWindowAnimator tAppAnimator = ttoken.mAppAnimator; + final AppWindowAnimator wAppAnimator = wtoken.mAppAnimator; + if (tAppAnimator.thumbnail != null) { + // The old token is animating with a thumbnail, transfer + // that to the new token. + if (wAppAnimator.thumbnail != null) { + wAppAnimator.thumbnail.destroy(); + } + wAppAnimator.thumbnail = tAppAnimator.thumbnail; + wAppAnimator.thumbnailX = tAppAnimator.thumbnailX; + wAppAnimator.thumbnailY = tAppAnimator.thumbnailY; + wAppAnimator.thumbnailLayer = tAppAnimator.thumbnailLayer; + wAppAnimator.thumbnailAnimation = tAppAnimator.thumbnailAnimation; + tAppAnimator.thumbnail = null; + } } } @@ -3924,12 +3971,12 @@ public class WindowManagerService extends IWindowManager.Stub boolean runningAppAnimation = false; if (transit != WindowManagerPolicy.TRANSIT_UNSET) { - if (wtoken.animation == sDummyAnimation) { - wtoken.animation = null; + if (wtoken.mAppAnimator.animation == sDummyAnimation) { + wtoken.mAppAnimator.animation = null; } applyAnimationLocked(wtoken, lp, transit, visible); changed = true; - if (wtoken.animation != null) { + if (wtoken.mAppAnimator.animation != null) { delayed = runningAppAnimation = true; } } @@ -3940,7 +3987,7 @@ public class WindowManagerService extends IWindowManager.Stub continue; } - if (win.isAnimating()) { + if (win.mWinAnimator.isAnimating()) { delayed = true; } @@ -3949,14 +3996,14 @@ public class WindowManagerService extends IWindowManager.Stub if (visible) { if (!win.isVisibleNow()) { if (!runningAppAnimation) { - applyAnimationLocked(win, + win.mWinAnimator.applyAnimationLocked( WindowManagerPolicy.TRANSIT_ENTER, true); } changed = true; } } else if (win.isVisibleNow()) { if (!runningAppAnimation) { - applyAnimationLocked(win, + win.mWinAnimator.applyAnimationLocked( WindowManagerPolicy.TRANSIT_EXIT, false); } changed = true; @@ -3970,8 +4017,7 @@ public class WindowManagerService extends IWindowManager.Stub // If we are being set visible, and the starting window is // not yet displayed, then make sure it doesn't get displayed. WindowState swin = wtoken.startingWindow; - if (swin != null && (swin.mDrawPending - || swin.mCommitDrawPending)) { + if (swin != null && !swin.isDrawnLw()) { swin.mPolicyVisibility = false; swin.mPolicyVisibilityAfterAnim = false; } @@ -3993,7 +4039,7 @@ public class WindowManagerService extends IWindowManager.Stub } } - if (wtoken.animation != null) { + if (wtoken.mAppAnimator.animation != null) { delayed = true; } @@ -4029,8 +4075,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; @@ -4039,7 +4084,7 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_APP_TRANSITIONS) Slog.v( TAG, "Setting dummy animation on: " + wtoken); - wtoken.setDummyAnimation(); + wtoken.mAppAnimator.setDummyAnimation(); mOpeningApps.remove(wtoken); mClosingApps.remove(wtoken); wtoken.waitingToShow = wtoken.waitingToHide = false; @@ -4089,7 +4134,7 @@ public class WindowManagerService extends IWindowManager.Stub void unsetAppFreezingScreenLocked(AppWindowToken wtoken, boolean unfreezeSurfaceNow, boolean force) { - if (wtoken.freezingScreen) { + if (wtoken.mAppAnimator.freezingScreen) { if (DEBUG_ORIENTATION) Slog.v(TAG, "Clear freezing of " + wtoken + " force=" + force); final int N = wtoken.allAppWindows.size(); @@ -4098,7 +4143,7 @@ public class WindowManagerService extends IWindowManager.Stub WindowState w = wtoken.allAppWindows.get(i); if (w.mAppFreezing) { w.mAppFreezing = false; - if (w.mSurface != null && !w.mOrientationChanging) { + if (w.mHasSurface && !w.mOrientationChanging) { if (DEBUG_ORIENTATION) Slog.v(TAG, "set mOrientationChanging of " + w); w.mOrientationChanging = true; } @@ -4107,7 +4152,7 @@ public class WindowManagerService extends IWindowManager.Stub } if (force || unfrozeWindows) { if (DEBUG_ORIENTATION) Slog.v(TAG, "No longer freezing: " + wtoken); - wtoken.freezingScreen = false; + wtoken.mAppAnimator.freezingScreen = false; mAppsFreezingScreen--; } if (unfreezeSurfaceNow) { @@ -4130,11 +4175,11 @@ public class WindowManagerService extends IWindowManager.Stub } Slog.i(TAG, "Set freezing of " + wtoken.appToken + ": hidden=" + wtoken.hidden + " freezing=" - + wtoken.freezingScreen, e); + + wtoken.mAppAnimator.freezingScreen, e); } if (!wtoken.hiddenRequested) { - if (!wtoken.freezingScreen) { - wtoken.freezingScreen = true; + if (!wtoken.mAppAnimator.freezingScreen) { + wtoken.mAppAnimator.freezingScreen = true; mAppsFreezingScreen++; if (mAppsFreezingScreen == 1) { startFreezingDisplayLocked(false); @@ -4158,7 +4203,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; } @@ -4187,7 +4232,7 @@ public class WindowManagerService extends IWindowManager.Stub } final long origId = Binder.clearCallingIdentity(); if (DEBUG_ORIENTATION) Slog.v(TAG, "Clear freezing of " + token - + ": hidden=" + wtoken.hidden + " freezing=" + wtoken.freezingScreen); + + ": hidden=" + wtoken.hidden + " freezing=" + wtoken.mAppAnimator.freezingScreen); unsetAppFreezingScreenLocked(wtoken, true, force); Binder.restoreCallingIdentity(origId); } @@ -4222,8 +4267,8 @@ public class WindowManagerService extends IWindowManager.Stub } if (DEBUG_APP_TRANSITIONS) Slog.v( TAG, "Removing app " + wtoken + " delayed=" + delayed - + " animation=" + wtoken.animation - + " animating=" + wtoken.animating); + + " animation=" + wtoken.mAppAnimator.animation + + " animating=" + wtoken.mAppAnimator.animating); if (delayed) { // set the token aside because it has an active animation to be finished if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG, @@ -4233,8 +4278,8 @@ 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.animation = null; - wtoken.animating = false; + wtoken.mAppAnimator.clearAnimation(); + wtoken.mAppAnimator.animating = false; } if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG, "removeAppToken: " + wtoken); @@ -4685,7 +4730,7 @@ public class WindowManagerService extends IWindowManager.Stub synchronized(mWindowMap) { for (int i=mWindows.size()-1; i>=0; i--) { WindowState w = mWindows.get(i); - if (w.mSurface != null) { + if (w.mHasSurface) { try { w.mClient.closeSystemDialogs(reason); } catch (RemoteException e) { @@ -4756,90 +4801,22 @@ public class WindowManagerService extends IWindowManager.Stub mAnimatorDurationScale }; } - public int getSwitchState(int sw) { - if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE, - "getSwitchState()")) { - throw new SecurityException("Requires READ_INPUT_STATE permission"); - } - return mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, sw); - } - - public int getSwitchStateForDevice(int devid, int sw) { - if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE, - "getSwitchStateForDevice()")) { - throw new SecurityException("Requires READ_INPUT_STATE permission"); - } - return mInputManager.getSwitchState(devid, InputDevice.SOURCE_ANY, sw); - } - - public int getScancodeState(int sw) { - if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE, - "getScancodeState()")) { - throw new SecurityException("Requires READ_INPUT_STATE permission"); - } - return mInputManager.getScanCodeState(-1, InputDevice.SOURCE_ANY, sw); - } - - public int getScancodeStateForDevice(int devid, int sw) { - if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE, - "getScancodeStateForDevice()")) { - throw new SecurityException("Requires READ_INPUT_STATE permission"); - } - return mInputManager.getScanCodeState(devid, InputDevice.SOURCE_ANY, sw); - } - - public int getTrackballScancodeState(int sw) { - if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE, - "getTrackballScancodeState()")) { - throw new SecurityException("Requires READ_INPUT_STATE permission"); - } - return mInputManager.getScanCodeState(-1, InputDevice.SOURCE_TRACKBALL, sw); - } - - public int getDPadScancodeState(int sw) { - if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE, - "getDPadScancodeState()")) { - throw new SecurityException("Requires READ_INPUT_STATE permission"); - } - return mInputManager.getScanCodeState(-1, InputDevice.SOURCE_DPAD, sw); - } - - public int getKeycodeState(int sw) { - if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE, - "getKeycodeState()")) { - throw new SecurityException("Requires READ_INPUT_STATE permission"); - } - return mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY, sw); - } - - public int getKeycodeStateForDevice(int devid, int sw) { - if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE, - "getKeycodeStateForDevice()")) { - throw new SecurityException("Requires READ_INPUT_STATE permission"); - } - return mInputManager.getKeyCodeState(devid, InputDevice.SOURCE_ANY, sw); - } - - public int getTrackballKeycodeState(int sw) { - if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE, - "getTrackballKeycodeState()")) { - throw new SecurityException("Requires READ_INPUT_STATE permission"); - } - return mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_TRACKBALL, sw); - } - - public int getDPadKeycodeState(int sw) { - if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE, - "getDPadKeycodeState()")) { - throw new SecurityException("Requires READ_INPUT_STATE permission"); + // Called by window manager policy. Not exposed externally. + @Override + public int getLidState() { + final int SW_LID = 0x00; + int sw = mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_LID); + if (sw > 0) { + return LID_OPEN; + } else if (sw == 0) { + return LID_CLOSED; + } else { + return LID_ABSENT; } - return mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_DPAD, sw); - } - - public boolean hasKeys(int[] keycodes, boolean[] keyExists) { - return mInputManager.hasKeys(-1, InputDevice.SOURCE_ANY, keycodes, keyExists); } + // Called by window manager policy. Not exposed externally. + @Override public InputChannel monitorInput(String inputChannelName) { if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE, "monitorInput()")) { @@ -4852,14 +4829,6 @@ public class WindowManagerService extends IWindowManager.Stub mInputManager.setInputFilter(filter); } - public InputDevice getInputDevice(int deviceId) { - return mInputManager.getInputDevice(deviceId); - } - - public int[] getInputDeviceIds() { - return mInputManager.getInputDeviceIds(); - } - public void enableScreenAfterBoot() { synchronized(mWindowMap) { if (DEBUG_BOOT) { @@ -5016,7 +4985,7 @@ public class WindowManagerService extends IWindowManager.Stub mPolicy.enableScreenAfterBoot(); // Make sure the last requested orientation has been applied. - updateRotationUnchecked(false); + updateRotationUnchecked(false, false); } public void showBootMessage(final CharSequence msg, final boolean always) { @@ -5140,8 +5109,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 @@ -5157,7 +5126,7 @@ public class WindowManagerService extends IWindowManager.Stub boolean including = false; for (int i=mWindows.size()-1; i>=0; i--) { WindowState ws = mWindows.get(i); - if (ws.mSurface == null) { + if (!ws.mHasSurface) { continue; } if (ws.mLayer >= aboveAppLayer) { @@ -5183,8 +5152,8 @@ public class WindowManagerService extends IWindowManager.Stub // window. including = !ws.mIsImWindow && !ws.isFullscreen(dw, dh); - if (maxLayer < ws.mAnimLayer) { - maxLayer = ws.mAnimLayer; + if (maxLayer < ws.mWinAnimator.mAnimLayer) { + maxLayer = ws.mWinAnimator.mAnimLayer; } // Don't include wallpaper in bounds calculation @@ -5245,8 +5214,8 @@ public class WindowManagerService extends IWindowManager.Stub Slog.i(TAG, "Screenshot: " + dw + "x" + dh + " from 0 to " + maxLayer); for (int i=0; i<mWindows.size(); i++) { Slog.i(TAG, mWindows.get(i) + ": " + mWindows.get(i).mLayer - + " animLayer=" + mWindows.get(i).mAnimLayer - + " surfaceLayer=" + mWindows.get(i).mSurfaceLayer); + + " animLayer=" + mWindows.get(i).mWinAnimator.mAnimLayer + + " surfaceLayer=" + mWindows.get(i).mWinAnimator.mSurfaceLayer); } } rawss = Surface.screenshot(dw, dh, 0, maxLayer); @@ -5261,7 +5230,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); @@ -5290,7 +5259,7 @@ public class WindowManagerService extends IWindowManager.Stub mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_LOCKED, rotation == -1 ? mRotation : rotation); - updateRotationUnchecked(false); + updateRotationUnchecked(false, false); } /** @@ -5306,7 +5275,7 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_ORIENTATION) Slog.v(TAG, "thawRotation: mRotation=" + mRotation); mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_FREE, 777); // rot not used - updateRotationUnchecked(false); + updateRotationUnchecked(false, false); } /** @@ -5316,8 +5285,8 @@ public class WindowManagerService extends IWindowManager.Stub * such that the current rotation might need to be updated, such as when the * device is docked or rotated into a new posture. */ - public void updateRotation(boolean alwaysSendConfiguration) { - updateRotationUnchecked(alwaysSendConfiguration); + public void updateRotation(boolean alwaysSendConfiguration, boolean forceRelayout) { + updateRotationUnchecked(alwaysSendConfiguration, forceRelayout); } /** @@ -5347,8 +5316,7 @@ public class WindowManagerService extends IWindowManager.Stub } } - public void updateRotationUnchecked( - boolean alwaysSendConfiguration) { + public void updateRotationUnchecked(boolean alwaysSendConfiguration, boolean forceRelayout) { if(DEBUG_ORIENTATION) Slog.v(TAG, "updateRotationUnchecked(" + "alwaysSendConfiguration=" + alwaysSendConfiguration + ")"); @@ -5356,6 +5324,10 @@ public class WindowManagerService extends IWindowManager.Stub boolean changed; synchronized(mWindowMap) { changed = updateRotationUncheckedLocked(false); + if (!changed || forceRelayout) { + mLayoutNeeded = true; + performLayoutAndPlaceSurfacesLocked(); + } } if (changed || alwaysSendConfiguration) { @@ -5379,7 +5351,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. @@ -5449,9 +5422,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(); @@ -5466,11 +5439,11 @@ public class WindowManagerService extends IWindowManager.Stub } } - rebuildBlackFrame(inTransaction); + rebuildBlackFrame(); for (int i=mWindows.size()-1; i>=0; i--) { WindowState w = mWindows.get(i); - if (w.mSurface != null) { + if (w.mHasSurface) { if (DEBUG_ORIENTATION) Slog.v(TAG, "Set mOrientationChanging of " + w); w.mOrientationChanging = true; } @@ -6153,6 +6126,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 @@ -6335,164 +6310,8 @@ public class WindowManagerService extends IWindowManager.Stub synchronized (mWindowMap) { mInputMonitor.setEventDispatchingLw(enabled); } - } - - /** - * Injects a keystroke event into the UI. - * Even when sync is false, this method may block while waiting for current - * input events to be dispatched. - * - * @param ev A motion event describing the keystroke action. (Be sure to use - * {@link SystemClock#uptimeMillis()} as the timebase.) - * @param sync If true, wait for the event to be completed before returning to the caller. - * @return Returns true if event was dispatched, false if it was dropped for any reason - */ - public boolean injectKeyEvent(KeyEvent ev, boolean sync) { - long downTime = ev.getDownTime(); - long eventTime = ev.getEventTime(); - - int action = ev.getAction(); - int code = ev.getKeyCode(); - int repeatCount = ev.getRepeatCount(); - int metaState = ev.getMetaState(); - int deviceId = ev.getDeviceId(); - int scancode = ev.getScanCode(); - int source = ev.getSource(); - int flags = ev.getFlags(); - - if (source == InputDevice.SOURCE_UNKNOWN) { - source = InputDevice.SOURCE_KEYBOARD; - } - - if (eventTime == 0) eventTime = SystemClock.uptimeMillis(); - if (downTime == 0) downTime = eventTime; - KeyEvent newEvent = new KeyEvent(downTime, eventTime, action, code, repeatCount, metaState, - deviceId, scancode, flags | KeyEvent.FLAG_FROM_SYSTEM, source); - - final int pid = Binder.getCallingPid(); - final int uid = Binder.getCallingUid(); - final long ident = Binder.clearCallingIdentity(); - - final int result = mInputManager.injectInputEvent(newEvent, pid, uid, - sync ? InputManager.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISH - : InputManager.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT, - INJECTION_TIMEOUT_MILLIS); - - Binder.restoreCallingIdentity(ident); - return reportInjectionResult(result, pid); - } - - /** - * Inject a pointer (touch) event into the UI. - * Even when sync is false, this method may block while waiting for current - * input events to be dispatched. - * - * @param ev A motion event describing the pointer (touch) action. (As noted in - * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use - * {@link SystemClock#uptimeMillis()} as the timebase.) - * @param sync If true, wait for the event to be completed before returning to the caller. - * @return Returns true if event was dispatched, false if it was dropped for any reason - */ - public boolean injectPointerEvent(MotionEvent ev, boolean sync) { - final int pid = Binder.getCallingPid(); - final int uid = Binder.getCallingUid(); - final long ident = Binder.clearCallingIdentity(); - - MotionEvent newEvent = MotionEvent.obtain(ev); - if ((newEvent.getSource() & InputDevice.SOURCE_CLASS_POINTER) == 0) { - newEvent.setSource(InputDevice.SOURCE_TOUCHSCREEN); - } - - final int result = mInputManager.injectInputEvent(newEvent, pid, uid, - sync ? InputManager.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISH - : InputManager.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT, - INJECTION_TIMEOUT_MILLIS); - - Binder.restoreCallingIdentity(ident); - return reportInjectionResult(result, pid); - } - - /** - * Inject a trackball (navigation device) event into the UI. - * Even when sync is false, this method may block while waiting for current - * input events to be dispatched. - * - * @param ev A motion event describing the trackball action. (As noted in - * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use - * {@link SystemClock#uptimeMillis()} as the timebase.) - * @param sync If true, wait for the event to be completed before returning to the caller. - * @return Returns true if event was dispatched, false if it was dropped for any reason - */ - public boolean injectTrackballEvent(MotionEvent ev, boolean sync) { - final int pid = Binder.getCallingPid(); - final int uid = Binder.getCallingUid(); - final long ident = Binder.clearCallingIdentity(); - - MotionEvent newEvent = MotionEvent.obtain(ev); - if ((newEvent.getSource() & InputDevice.SOURCE_CLASS_TRACKBALL) == 0) { - newEvent.setSource(InputDevice.SOURCE_TRACKBALL); - } - - final int result = mInputManager.injectInputEvent(newEvent, pid, uid, - sync ? InputManager.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISH - : InputManager.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT, - INJECTION_TIMEOUT_MILLIS); - - Binder.restoreCallingIdentity(ident); - return reportInjectionResult(result, pid); - } - - /** - * Inject an input event into the UI without waiting for dispatch to commence. - * This variant is useful for fire-and-forget input event injection. It does not - * block any longer than it takes to enqueue the input event. - * - * @param ev An input event. (Be sure to set the input source correctly.) - * @return Returns true if event was dispatched, false if it was dropped for any reason - */ - public boolean injectInputEventNoWait(InputEvent ev) { - final int pid = Binder.getCallingPid(); - final int uid = Binder.getCallingUid(); - final long ident = Binder.clearCallingIdentity(); - - final int result = mInputManager.injectInputEvent(ev, pid, uid, - InputManager.INPUT_EVENT_INJECTION_SYNC_NONE, - INJECTION_TIMEOUT_MILLIS); - - Binder.restoreCallingIdentity(ident); - return reportInjectionResult(result, pid); - } - - private boolean reportInjectionResult(int result, int pid) { - switch (result) { - case InputManager.INPUT_EVENT_INJECTION_PERMISSION_DENIED: - Slog.w(TAG, "Input event injection from pid " + pid + " permission denied."); - throw new SecurityException( - "Injecting to another application requires INJECT_EVENTS permission"); - case InputManager.INPUT_EVENT_INJECTION_SUCCEEDED: - return true; - case InputManager.INPUT_EVENT_INJECTION_TIMED_OUT: - Slog.w(TAG, "Input event injection from pid " + pid + " timed out."); - return false; - case InputManager.INPUT_EVENT_INJECTION_FAILED: - default: - Slog.w(TAG, "Input event injection from pid " + pid + " failed."); - return false; - } - } - - /** - * Temporarily set the pointer speed. Does not save the new setting. - * Used by the settings application. - */ - public void setPointerSpeed(int speed) { - if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED, - "setPointerSpeed()")) { - throw new SecurityException("Requires SET_POINTER_SPEED permission"); - } - - mInputManager.setPointerSpeed(speed); + sendScreenStatusToClients(); } private WindowState getFocusedWindow() { @@ -6509,11 +6328,29 @@ public class WindowManagerService extends IWindowManager.Stub if (!mInputMonitor.waitForInputDevicesReady( INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS)) { Slog.w(TAG, "Devices still not ready after waiting " - + INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS - + " milliseconds before attempting to detect safe mode."); + + INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS + + " milliseconds before attempting to detect safe mode."); + } + + final int BTN_MOUSE = 0x110; + int menuState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY, + KeyEvent.KEYCODE_MENU); + int sState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY, KeyEvent.KEYCODE_S); + int dpadState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_DPAD, + KeyEvent.KEYCODE_DPAD_CENTER); + int trackballState = mInputManager.getScanCodeState(-1, InputDevice.SOURCE_TRACKBALL, + BTN_MOUSE); + int volumeDownState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY, + KeyEvent.KEYCODE_VOLUME_DOWN); + mSafeMode = menuState > 0 || sState > 0 || dpadState > 0 || trackballState > 0 + || volumeDownState > 0; + if (mSafeMode) { + Log.i(TAG, "SAFE MODE ENABLED (menu=" + menuState + " s=" + sState + + " dpad=" + dpadState + " trackball=" + trackballState + ")"); + } else { + Log.i(TAG, "SAFE MODE not enabled"); } - - mSafeMode = mPolicy.detectSafeMode(); + mPolicy.setSafeMode(mSafeMode); return mSafeMode; } @@ -6537,11 +6374,13 @@ 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(), mDisplay.getRawExternalWidth(), mDisplay.getRawExternalHeight()); - mPolicy.setInitialDisplaySize(mInitialDisplayWidth, mInitialDisplayHeight); + mPolicy.setInitialDisplaySize(mDisplay, mInitialDisplayWidth, mInitialDisplayHeight); } try { @@ -6558,6 +6397,20 @@ public class WindowManagerService extends IWindowManager.Stub mPolicy.systemReady(); } + private void sendScreenStatusToClients() { + final ArrayList<WindowState> windows = mWindows; + final int count = windows.size(); + boolean on = mPowerManager.isScreenOn(); + for (int i = count - 1; i >= 0; i--) { + WindowState win = mWindows.get(i); + try { + win.mClient.dispatchScreenState(on); + } catch (RemoteException e) { + // Ignored + } + } + } + // This is an animation that does nothing: it just immediately finishes // itself every time it is called. It is used as a stub animation in cases // where we want to synchronize multiple things that may be animating. @@ -6595,6 +6448,13 @@ public class WindowManagerService extends IWindowManager.Stub public static final int REPORT_HARD_KEYBOARD_STATUS_CHANGE = 22; public static final int BOOT_TIMEOUT = 23; public static final int WAITING_FOR_DRAWN_TIMEOUT = 24; + public static final int BULK_UPDATE_PARAMETERS = 25; + + public static final int ANIMATOR_WHAT_OFFSET = 100000; + public static final int SET_TRANSPARENT_REGION = ANIMATOR_WHAT_OFFSET + 1; + public static final int SET_WALLPAPER_OFFSET = ANIMATOR_WHAT_OFFSET + 2; + public static final int SET_DIM_PARAMETERS = ANIMATOR_WHAT_OFFSET + 3; + public static final int SET_MOVE_ANIMATION = ANIMATOR_WHAT_OFFSET + 4; private Session mLastReportedHold; @@ -6918,14 +6778,16 @@ public class WindowManagerService extends IWindowManager.Stub case APP_FREEZE_TIMEOUT: { synchronized (mWindowMap) { - Slog.w(TAG, "App freeze timeout expired."); - int i = mAppTokens.size(); - while (i > 0) { - i--; - AppWindowToken tok = mAppTokens.get(i); - if (tok.freezingScreen) { - Slog.w(TAG, "Force clearing freeze: " + tok); - unsetAppFreezingScreenLocked(tok, true, true); + synchronized (mAnimator) { + Slog.w(TAG, "App freeze timeout expired."); + int i = mAppTokens.size(); + while (i > 0) { + i--; + AppWindowToken tok = mAppTokens.get(i); + if (tok.mAppAnimator.freezingScreen) { + Slog.w(TAG, "Force clearing freeze: " + tok); + unsetAppFreezingScreenLocked(tok, true, true); + } } } } @@ -7005,6 +6867,67 @@ public class WindowManagerService extends IWindowManager.Stub } break; } + + case BULK_UPDATE_PARAMETERS: { + // Used to send multiple changes from the animation side to the layout side. + synchronized (mWindowMap) { + // TODO(cmautner): As the number of bits grows, use masks of bit groups to + // eliminate unnecessary tests. + if ((msg.arg1 & LayoutFields.SET_UPDATE_ROTATION) != 0) { + mInnerFields.mUpdateRotation = true; + } + if ((msg.arg1 & LayoutFields.SET_WALLPAPER_MAY_CHANGE) != 0) { + mInnerFields.mWallpaperMayChange = true; + } + if ((msg.arg1 & LayoutFields.SET_FORCE_HIDING_CHANGED) != 0) { + mInnerFields.mWallpaperForceHidingChanged = true; + } + if ((msg.arg1 & LayoutFields.CLEAR_ORIENTATION_CHANGE_COMPLETE) != 0) { + mInnerFields.mOrientationChangeComplete = false; + } + + requestTraversalLocked(); + } + break; + } + + // Animation messages. Move to Window{State}Animator + case SET_TRANSPARENT_REGION: { + Pair<WindowStateAnimator, Region> pair = + (Pair<WindowStateAnimator, Region>) msg.obj; + final WindowStateAnimator winAnimator = pair.first; + winAnimator.setTransparentRegionHint(pair.second); + + scheduleAnimationLocked(); + break; + } + + case SET_WALLPAPER_OFFSET: { + final WindowStateAnimator winAnimator = (WindowStateAnimator) msg.obj; + winAnimator.setWallpaperOffset(msg.arg1, msg.arg2); + + scheduleAnimationLocked(); + break; + } + + case SET_DIM_PARAMETERS: { + mAnimator.mDimParams = (DimAnimator.Parameters) msg.obj; + + scheduleAnimationLocked(); + break; + } + + case SET_MOVE_ANIMATION: { + WindowAnimator.SetAnimationParams params = + (WindowAnimator.SetAnimationParams) msg.obj; + WindowStateAnimator winAnimator = params.mWinAnimator; + winAnimator.setAnimation(params.mAnimation); + winAnimator.mAnimDw = params.mAnimDw; + winAnimator.mAnimDh = params.mAnimDh; + + scheduleAnimationLocked(); + break; + } } } } @@ -7125,45 +7048,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) { } } } @@ -7195,7 +7105,7 @@ public class WindowManagerService extends IWindowManager.Stub mBaseDisplayWidth = width; mBaseDisplayHeight = height; } - mPolicy.setInitialDisplaySize(mBaseDisplayWidth, mBaseDisplayHeight); + mPolicy.setInitialDisplaySize(mDisplay, mBaseDisplayWidth, mBaseDisplayHeight); mLayoutNeeded = true; @@ -7214,7 +7124,7 @@ public class WindowManagerService extends IWindowManager.Stub mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); } - rebuildBlackFrame(false); + rebuildBlackFrame(); performLayoutAndPlaceSurfacesLocked(); } @@ -7227,8 +7137,8 @@ public class WindowManagerService extends IWindowManager.Stub } } - public boolean canStatusBarHide() { - return mPolicy.canStatusBarHide(); + public boolean hasSystemNavBar() { + return mPolicy.hasSystemNavBar(); } // ------------------------------------------------------------- @@ -7364,19 +7274,21 @@ public class WindowManagerService extends IWindowManager.Stub w.mLayer = curLayer; } if (w.mTargetAppToken != null) { - w.mAnimLayer = w.mLayer + w.mTargetAppToken.animLayerAdjustment; + w.mWinAnimator.mAnimLayer = + w.mLayer + w.mTargetAppToken.mAppAnimator.animLayerAdjustment; } else if (w.mAppToken != null) { - w.mAnimLayer = w.mLayer + w.mAppToken.animLayerAdjustment; + w.mWinAnimator.mAnimLayer = + w.mLayer + w.mAppToken.mAppAnimator.animLayerAdjustment; } else { - w.mAnimLayer = w.mLayer; + w.mWinAnimator.mAnimLayer = w.mLayer; } if (w.mIsImWindow) { - w.mAnimLayer += mInputMethodAnimLayerAdjustment; + w.mWinAnimator.mAnimLayer += mInputMethodAnimLayerAdjustment; } else if (w.mIsWallpaper) { - w.mAnimLayer += mWallpaperAnimLayerAdjustment; + w.mWinAnimator.mAnimLayer += mWallpaperAnimLayerAdjustment; } if (DEBUG_LAYERS) Slog.v(TAG, "Assign layer " + w + ": " - + w.mAnimLayer); + + w.mWinAnimator.mAnimLayer); //System.out.println( // "Assigned layer " + curLayer + " to " + w.mClient.asBinder()); } @@ -7452,10 +7364,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)); @@ -7599,7 +7526,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; @@ -7616,295 +7543,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. - * @return true if rotation has stopped, false otherwise - */ - private void updateWindowsAppsAndRotationAnimationsLocked(long currentTime, - int innerDw, int innerDh) { - int i; - for (i = mWindows.size() - 1; i >= 0; i--) { - mInnerFields.mAnimating |= mWindows.get(i).stepAnimationLocked(currentTime); - } - - final int NAT = mAppTokens.size(); - for (i=0; i<NAT; i++) { - mInnerFields.mAnimating |= - mAppTokens.get(i).stepAnimationLocked(currentTime, innerDw, innerDh); - } - final int NEAT = mExitingAppTokens.size(); - for (i=0; i<NEAT; i++) { - mInnerFields.mAnimating |= - mExitingAppTokens.get(i).stepAnimationLocked(currentTime, innerDw, innerDh); - } - - if (mScreenRotationAnimation != null) { - if (mScreenRotationAnimation.isAnimating()) { - if (mScreenRotationAnimation.stepAnimation(currentTime)) { - mInnerFields.mUpdateRotation = false; - mInnerFields.mAnimating = true; - } else { - mInnerFields.mUpdateRotation = true; - mScreenRotationAnimation.kill(); - mScreenRotationAnimation = null; - } - } - } - } - - /** - * 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) { - - mPolicy.beginAnimationLw(dw, dh); - - 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; - } - } - - // 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.mLocalAnimating; - - 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; - } - - 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; - 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; - } - } - - mPolicy.animatingWindowLw(w, attrs); - } - - 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(); - } - } // end forall windows - - return mPolicy.finishAnimationLw(); - } - - /** - * 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. */ @@ -8066,27 +7704,44 @@ public class WindowManagerService extends IWindowManager.Stub animLp = null; } + AppWindowToken topOpeningApp = null; + int topOpeningLayer = 0; + + // TODO(cmautner): Move to animation side. 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); + if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken); + wtoken.mAppAnimator.clearThumbnail(); wtoken.reportedVisible = false; wtoken.inPendingTransaction = false; - wtoken.animation = null; - setTokenVisibilityLocked(wtoken, animLp, true, - transit, false); + wtoken.mAppAnimator.animation = null; + setTokenVisibilityLocked(wtoken, animLp, true, transit, false); wtoken.updateReportedVisibilityLocked(); wtoken.waitingToShow = false; - wtoken.showAllWindowsLocked(); + mAnimator.mAnimating |= wtoken.mAppAnimator.showAllWindowsLocked(); + if (animLp != null) { + int layer = -1; + for (int j=0; j<wtoken.windows.size(); j++) { + WindowState win = wtoken.windows.get(j); + if (win.mWinAnimator.mAnimLayer > layer) { + layer = win.mWinAnimator.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.mAppAnimator.clearThumbnail(); wtoken.inPendingTransaction = false; - wtoken.animation = null; + wtoken.mAppAnimator.animation = null; setTokenVisibilityLocked(wtoken, animLp, false, transit, false); wtoken.updateReportedVisibilityLocked(); @@ -8097,7 +7752,47 @@ public class WindowManagerService extends IWindowManager.Stub wtoken.allDrawn = true; } + if (mNextAppTransitionThumbnail != null && topOpeningApp != null + && topOpeningApp.mAppAnimator.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.mAppAnimator.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.mAppAnimator.thumbnailLayer = topOpeningLayer; + Animation anim = createThumbnailAnimationLocked(transit, true, true); + topOpeningApp.mAppAnimator.thumbnailAnimation = anim; + anim.restrictDuration(MAX_ANIMATION_DURATION); + anim.scaleCurrentDuration(mTransitionAnimationScale); + topOpeningApp.mAppAnimator.thumbnailX = mNextAppTransitionStartX; + topOpeningApp.mAppAnimator.thumbnailY = mNextAppTransitionStartY; + } catch (Surface.OutOfResourcesException e) { + Slog.e(TAG, "Can't allocate thumbnail surface w=" + dirty.width() + + " h=" + dirty.height(), e); + topOpeningApp.mAppAnimator.clearThumbnail(); + } + } + mNextAppTransitionPackage = null; + mNextAppTransitionThumbnail = null; + if (mNextAppTransitionCallback != null) { + try { + mNextAppTransitionCallback.sendResult(null); + } catch (RemoteException e) { + } + } mOpeningApps.clear(); mClosingApps.clear(); @@ -8168,27 +7863,26 @@ public class WindowManagerService extends IWindowManager.Stub } } mInnerFields.mAdjResult |= adjustWallpaperWindowsLocked(); - mInnerFields.mWallpaperMayChange = false; - mInnerFields.mWallpaperForceHidingChanged = false; if (DEBUG_WALLPAPER) Slog.v(TAG, "****** OLD: " + oldWallpaper + " NEW: " + mWallpaperTarget + " LOWER: " + mLowerWallpaperTarget); 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) { + if (w.mHasSurface) { 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. - w.clearAnimation(); + // TODO(cmautner): We lose the enter animation when this occurs. + w.mWinAnimator.clearAnimation(); } } } @@ -8197,163 +7891,8 @@ public class WindowManagerService extends IWindowManager.Stub return changes; } - /** - * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method. - * - * @return bitmap indicating if another pass through layout must be made. - */ - private int testWallpaperAndBackgroundLocked() { - int changes = 0; - - if (mWindowDetachedWallpaper != mInnerFields.mDetachedWallpaper) { - if (DEBUG_WALLPAPER) Slog.v(TAG, - "Detached wallpaper changed from " + mWindowDetachedWallpaper - + " to " + mInnerFields.mDetachedWallpaper); - mWindowDetachedWallpaper = mInnerFields.mDetachedWallpaper; - mInnerFields.mWallpaperMayChange = true; - } - - if (mInnerFields.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) { - for (int i=0; i<mWindows.size(); i++) { - WindowState w = mWindows.get(i); - if (w.mIsWallpaper) { - target = w; - break; - } - } - } - if (mWindowAnimationBackgroundSurface == null) { - mWindowAnimationBackgroundSurface = new DimSurface(mFxSession); - } - final int dw = mCurDisplayWidth; - final int dh = mCurDisplayHeight; - mWindowAnimationBackgroundSurface.show(dw, dh, - target.mAnimLayer - LAYER_OFFSET_DIM, - mInnerFields.mWindowAnimationBackgroundColor); - } else if (mWindowAnimationBackgroundSurface != null) { - mWindowAnimationBackgroundSurface.hide(); - } - - if (mInnerFields.mWallpaperMayChange) { - if (DEBUG_WALLPAPER) Slog.v(TAG, - "Wallpaper may change! Adjusting"); - mInnerFields.mAdjResult |= adjustWallpaperWindowsLocked(); - } - - if ((mInnerFields.mAdjResult&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) { - if (DEBUG_WALLPAPER) Slog.v(TAG, - "Wallpaper layer changed: assigning layers + relayout"); - changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT; - assignLayersLocked(); - } else if ((mInnerFields.mAdjResult&ADJUST_WALLPAPER_VISIBILITY_CHANGED) != 0) { - if (DEBUG_WALLPAPER) Slog.v(TAG, - "Wallpaper visibility changed: relayout"); - changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT; - } - - if (mFocusMayChange) { - mFocusMayChange = false; - if (updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES, - false /*updateInputWindows*/)) { - changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM; - mInnerFields.mAdjResult = 0; - } - } - - return changes; - } - - /** - * 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. - 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); - } - } - } - + private void updateResizingWindows(final WindowState w) { + final WindowStateAnimator winAnimator = w.mWinAnimator; if (!w.mAppFreezing && w.mLayoutSeq == mLayoutSeq) { w.mContentInsetsChanged |= !w.mLastContentInsets.equals(w.mContentInsets); @@ -8373,13 +7912,13 @@ public class WindowManagerService extends IWindowManager.Stub w.mLastFrame.set(w.mFrame); if (w.mContentInsetsChanged || w.mVisibleInsetsChanged - || w.mSurfaceResized + || winAnimator.mSurfaceResized || configChanged) { if (DEBUG_RESIZE || DEBUG_ORIENTATION) { Slog.v(TAG, "Resize reasons: " + " contentInsetsChanged=" + w.mContentInsetsChanged + " visibleInsetsChanged=" + w.mVisibleInsetsChanged - + " surfaceResized=" + w.mSurfaceResized + + " surfaceResized=" + w.mWinAnimator.mSurfaceResized + " configChanged=" + configChanged); } @@ -8394,131 +7933,26 @@ public class WindowManagerService extends IWindowManager.Stub if (w.mOrientationChanging) { if (DEBUG_ORIENTATION) Slog.v(TAG, "Orientation start waiting for draw in " - + w + ", surface " + w.mSurface); - w.mDrawPending = true; - w.mCommitDrawPending = false; - w.mReadyToShow = false; + + w + ", surface " + w.mWinAnimator.mSurface); + winAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING; if (w.mAppToken != null) { w.mAppToken.allDrawn = false; } } if (!mResizingWindows.contains(w)) { if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG, - "Resizing window " + w + " to " + w.mSurfaceW - + "x" + w.mSurfaceH); + "Resizing window " + w + " to " + w.mWinAnimator.mSurfaceW + + "x" + w.mWinAnimator.mSurfaceH); mResizingWindows.add(w); } } else if (w.mOrientationChanging) { - if (!w.mDrawPending && !w.mCommitDrawPending) { + if (w.isDrawnLw()) { if (DEBUG_ORIENTATION) Slog.v(TAG, "Orientation not waiting for draw in " - + w + ", surface " + w.mSurface); - w.mOrientationChanging = false; - } - } - } - - 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.mDrawPending - && !w.mCommitDrawPending - && !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.mDrawPending || w.mCommitDrawPending) { - mInnerFields.mOrientationChangeComplete = false; - if (DEBUG_ORIENTATION) Slog.v(TAG, - "Orientation continue waiting for draw in " + w); - } else { + + w + ", surface " + w.mWinAnimator.mSurface); w.mOrientationChanging = false; - if (DEBUG_ORIENTATION) Slog.v(TAG, - "Orientation change complete in " + w); } } - w.mToken.hasVisible = true; } } @@ -8536,7 +7970,7 @@ public class WindowManagerService extends IWindowManager.Stub final int attrFlags = attrs.flags; final boolean canBeSeen = w.isDisplayedLw(); - if (w.mSurface != null) { + if (w.mHasSurface) { if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) { mInnerFields.mHoldScreen = w.mSession; } @@ -8559,68 +7993,24 @@ 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); - } - mDimAnimator.show(innerDw, innerDh); - 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; - } - } + } 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; + final int width, height; + if (attrs.type == WindowManager.LayoutParams.TYPE_BOOT_PROGRESS) { + width = mCurDisplayWidth; + height = mCurDisplayHeight; + } else { + width = innerDw; + height = innerDh; } + mAnimator.startDimming(w.mWinAnimator, w.mExiting ? 0 : w.mAttrs.dimAmount, + width, height); } } } @@ -8657,12 +8047,11 @@ public class WindowManagerService extends IWindowManager.Stub mExitingAppTokens.get(i).hasVisible = false; } - mInnerFields.mOrientationChangeComplete = true; mInnerFields.mHoldScreen = null; mInnerFields.mScreenBrightness = -1; mInnerFields.mButtonBrightness = -1; boolean focusDisplayed = false; - mInnerFields.mAnimating = false; + mAnimator.mAnimating = false; boolean createWatermark = false; if (mFxSession == null) { @@ -8686,9 +8075,7 @@ public class WindowManagerService extends IWindowManager.Stub } try { - mInnerFields.mWallpaperForceHidingChanged = false; int repeats = 0; - int changes = 0; do { repeats++; @@ -8698,20 +8085,25 @@ public class WindowManagerService extends IWindowManager.Stub break; } - if ((changes & WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0) { + if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("On entry to LockedInner", + mPendingLayoutChanges); + + if ((mPendingLayoutChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0) { if ((adjustWallpaperWindowsLocked()&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) { assignLayersLocked(); mLayoutNeeded = true; } } - if ((changes & WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) { + + if ((mPendingLayoutChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) { if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout"); if (updateOrientationFromAppTokensLocked(true)) { mLayoutNeeded = true; mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); } } - if ((changes & WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) { + + if ((mPendingLayoutChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) { mLayoutNeeded = true; } @@ -8722,101 +8114,34 @@ public class WindowManagerService extends IWindowManager.Stub Slog.w(TAG, "Layout repeat skipped after too many iterations"); } - ++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; - - 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; + // FIRST AND ONE HALF LOOP: Make WindowManagerPolicy think + // it is animating. + mPendingLayoutChanges = 0; + if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("loop number " + mLayoutRepeatCount, + mPendingLayoutChanges); + mPolicy.beginAnimationLw(dw, dh); + for (i = mWindows.size() - 1; i >= 0; i--) { + WindowState w = mWindows.get(i); + if (w.mHasSurface) { + mPolicy.animatingWindowLw(w, w.mAttrs); + } } + mPendingLayoutChanges |= mPolicy.finishAnimationLw(); + if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after finishAnimationLw", + mPendingLayoutChanges); + } while (mPendingLayoutChanges != 0); - if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** ANIM STEP: changes=0x" - + Integer.toHexString(changes)); - } while (changes != 0); - - // Update animations of all applications, including those - // associated with exiting/removed apps - mInnerFields.mAnimating = false; - - updateWindowsAppsAndRotationAnimationsLocked(currentTime, innerDw, innerDh); - - // THIRD LOOP: Update the surfaces of all windows. - - final boolean someoneLosingFocus = mLosingFocus.size() != 0; + final boolean someoneLosingFocus = !mLosingFocus.isEmpty(); mInnerFields.mObscured = false; - mInnerFields.mBlurring = false; mInnerFields.mDimming = false; mInnerFields.mSyswin = false; - + final int N = mWindows.size(); - for (i=N-1; i>=0; i--) { WindowState w = mWindows.get(i); - if (w.mSurface != null) { - prepareSurfaceLocked(w, recoveringMemory); - } else if (w.mOrientationChanging) { - if (DEBUG_ORIENTATION) { - Slog.v(TAG, "Orientation change skips hidden " + w); - } - w.mOrientationChanging = false; - } - - if (w.mContentChanged) { - //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing"); - w.mContentChanged = false; - } - - final boolean canBeSeen = w.isDisplayedLw(); - - if (someoneLosingFocus && w == mCurrentFocus && canBeSeen) { + if (someoneLosingFocus && w == mCurrentFocus && w.isDisplayedLw()) { focusDisplayed = true; } @@ -8835,37 +8160,135 @@ public class WindowManagerService extends IWindowManager.Stub updateWallpaperVisibilityLocked(); } } + if (!mInnerFields.mDimming && mAnimator.mDimParams != null) { + mAnimator.stopDimming(); + } + } catch (RuntimeException e) { + Log.wtf(TAG, "Unhandled exception in Window Manager", e); + } finally { + Surface.closeTransaction(); + } - if (mDimAnimator != null && mDimAnimator.mDimShown) { - mInnerFields.mAnimating |= - mDimAnimator.updateSurface(mInnerFields.mDimming, currentTime, - mDisplayFrozen || !mDisplayEnabled || !mPolicy.isScreenOnFully()); + // 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", + mPendingLayoutChanges); + } + + 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", + mPendingLayoutChanges); + } + + 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); + } + mInnerFields.mWallpaperForceHidingChanged = false; + + if (mInnerFields.mWallpaperMayChange) { + if (WindowManagerService.DEBUG_WALLPAPER) Slog.v(TAG, + "Wallpaper may change! Adjusting"); + mInnerFields.mAdjResult |= adjustWallpaperWindowsLocked(); + } + + if ((mInnerFields.mAdjResult&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) { + if (DEBUG_WALLPAPER) Slog.v(TAG, + "Wallpaper layer changed: assigning layers + relayout"); + mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT; + assignLayersLocked(); + } else if ((mInnerFields.mAdjResult&ADJUST_WALLPAPER_VISIBILITY_CHANGED) != 0) { + if (DEBUG_WALLPAPER) Slog.v(TAG, + "Wallpaper visibility changed: relayout"); + mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT; + } + + if (mFocusMayChange) { + mFocusMayChange = false; + if (updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES, + false /*updateInputWindows*/)) { + mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM; + mInnerFields.mAdjResult = 0; } + } - 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 (mLayoutNeeded) { + mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT; + if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("mLayoutNeeded", mPendingLayoutChanges); + } + + final int N = mWindows.size(); + for (i=N-1; i>=0; i--) { + final WindowState w = mWindows.get(i); + final WindowStateAnimator winAnimator = w.mWinAnimator; + + // If the window has moved due to its containing + // content frame changing, then we'd like to animate + // it. + if (w.mHasSurface && 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); + winAnimator.mAnimDw = w.mLastFrame.left - w.mFrame.left; + winAnimator.mAnimDh = w.mLastFrame.top - w.mFrame.top; + } else { + winAnimator.mAnimDw = innerDw; + winAnimator.mAnimDh = innerDh; } - if (mBlackFrame != null) { - if (mScreenRotationAnimation != null) { - mBlackFrame.setMatrix( - mScreenRotationAnimation.getEnterTransformation().getMatrix()); - } else { - mBlackFrame.clearMatrix(); + //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing"); + w.mContentChanged = false; + + // TODO(cmautner): Can this move up to the loop at the end of try/catch above? + updateResizingWindows(w); + + // Moved from updateWindowsAndWallpaperLocked(). + if (w.mHasSurface) { + // Take care of the window being ready to display. + if (winAnimator.commitFinishDrawingLocked(currentTime)) { + 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); + mInnerFields.mWallpaperMayChange = true; + mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; + if (WindowManagerService.DEBUG_LAYOUT_REPEATS) { + debugLayoutRepeats("updateWindowsAndWallpaperLocked 1", + mPendingLayoutChanges); + } + } } } - } catch (RuntimeException e) { - Log.wtf(TAG, "Unhandled exception in Window Manager", e); } - Surface.closeTransaction(); + // Update animations of all applications, including those + // associated with exiting/removed apps + mAnimator.animate(); + mPendingLayoutChanges |= mAnimator.mPendingLayoutChanges; + if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after animate()", mPendingLayoutChanges); if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces"); @@ -8885,11 +8308,10 @@ public class WindowManagerService extends IWindowManager.Stub stopFreezingDisplayLocked(); } - i = mResizingWindows.size(); - if (i > 0) { - do { - i--; + if (!mResizingWindows.isEmpty()) { + for (i = mResizingWindows.size() - 1; i >= 0; i--) { WindowState win = mResizingWindows.get(i); + final WindowStateAnimator winAnimator = win.mWinAnimator; try { if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG, "Reporting new frame to " + win + ": " + win.mCompatFrame); @@ -8901,23 +8323,26 @@ public class WindowManagerService extends IWindowManager.Stub if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION) && configChanged) { Slog.i(TAG, "Sending new config to window " + win + ": " - + win.mSurfaceW + "x" + win.mSurfaceH + + winAnimator.mSurfaceW + "x" + winAnimator.mSurfaceH + " / " + mCurConfiguration + " / 0x" + Integer.toHexString(diff)); } win.mConfiguration = mCurConfiguration; - if (DEBUG_ORIENTATION && win.mDrawPending) Slog.i( + if (DEBUG_ORIENTATION && + winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) Slog.i( TAG, "Resizing " + win + " WITH DRAW PENDING"); - win.mClient.resized((int)win.mSurfaceW, (int)win.mSurfaceH, - win.mLastContentInsets, win.mLastVisibleInsets, win.mDrawPending, + win.mClient.resized((int)winAnimator.mSurfaceW, + (int)winAnimator.mSurfaceH, + win.mLastContentInsets, win.mLastVisibleInsets, + winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING, configChanged ? win.mConfiguration : null); win.mContentInsetsChanged = false; win.mVisibleInsetsChanged = false; - win.mSurfaceResized = false; + winAnimator.mSurfaceResized = false; } catch (RemoteException e) { win.mOrientationChanging = false; } - } while (i > 0); + } mResizingWindows.clear(); } @@ -8935,7 +8360,7 @@ public class WindowManagerService extends IWindowManager.Stub if (win == mWallpaperTarget) { wallpaperDestroyed = true; } - win.destroySurfaceLocked(); + win.mWinAnimator.destroySurfaceLocked(); } while (i > 0); mDestroySurface.clear(); } @@ -8958,8 +8383,8 @@ 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.animation = null; - token.animating = false; + token.mAppAnimator.clearAnimation(); + token.mAppAnimator.animating = false; if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG, "performLayout: App token exiting now removed" + token); mAppTokens.remove(token); @@ -8967,9 +8392,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 @@ -8977,7 +8400,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. @@ -8988,12 +8411,10 @@ public class WindowManagerService extends IWindowManager.Stub mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS); } if (wallpaperDestroyed) { - needRelayout = adjustWallpaperWindowsLocked() != 0; + 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. @@ -9036,10 +8457,11 @@ public class WindowManagerService extends IWindowManager.Stub } } - if (mInnerFields.mOrientationChangeComplete && !needRelayout && + if (mInnerFields.mOrientationChangeComplete && !mLayoutNeeded && !mInnerFields.mUpdateRotation) { checkDrawnWindowsLocked(); } + mInnerFields.mOrientationChangeComplete = true; // Check to see if we are now in a state where the screen should // be enabled, because the window obscured flags have changed. @@ -9064,7 +8486,7 @@ public class WindowManagerService extends IWindowManager.Stub } mWaitingForDrawn.remove(pair); mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, pair); - } else if (win.mSurfaceShown) { + } else if (win.mWinAnimator.mSurfaceShown) { // Window is now drawn (and shown). try { pair.second.sendResult(null); @@ -9116,48 +8538,19 @@ public class WindowManagerService extends IWindowManager.Stub void scheduleAnimationLocked() { if (!mAnimationScheduled) { - mChoreographer.postAnimationCallback(mAnimationRunnable); + mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mAnimationRunnable, null); mAnimationScheduled = true; } } - /** - * Have the surface flinger show a surface, robustly dealing with - * error conditions. In particular, if there is not enough memory - * to show the surface, then we will try to get rid of other surfaces - * in order to succeed. - * - * @return Returns true if the surface was successfully shown. - */ - boolean showSurfaceRobustlyLocked(WindowState win) { - try { - if (win.mSurface != null) { - win.mSurfaceShown = true; - win.mSurface.show(); - if (win.mTurnOnScreen) { - if (DEBUG_VISIBILITY) Slog.v(TAG, - "Show surface turning screen on: " + win); - win.mTurnOnScreen = false; - mTurnOnScreen = true; - } - } - return true; - } catch (RuntimeException e) { - Slog.w(TAG, "Failure showing surface " + win.mSurface + " in " + win, e); - } - - reclaimSomeSurfaceMemoryLocked(win, "show", true); - - return false; - } - - boolean reclaimSomeSurfaceMemoryLocked(WindowState win, String operation, boolean secure) { - final Surface surface = win.mSurface; + boolean reclaimSomeSurfaceMemoryLocked(WindowStateAnimator winAnimator, String operation, + boolean secure) { + final Surface surface = winAnimator.mSurface; boolean leakedSurface = false; boolean killedApps = false; - EventLog.writeEvent(EventLogTags.WM_NO_SURFACE_MEMORY, win.toString(), - win.mSession.mPid, operation); + EventLog.writeEvent(EventLogTags.WM_NO_SURFACE_MEMORY, winAnimator.mWin.toString(), + winAnimator.mSession.mPid, operation); if (mForceRemoves == null) { mForceRemoves = new ArrayList<WindowState>(); @@ -9172,29 +8565,34 @@ public class WindowManagerService extends IWindowManager.Stub Slog.i(TAG, "Out of memory for surface! Looking for leaks..."); for (int i=0; i<N; i++) { WindowState ws = mWindows.get(i); - if (ws.mSurface != null) { - if (!mSessions.contains(ws.mSession)) { + WindowStateAnimator wsa = ws.mWinAnimator; + if (wsa.mSurface != null) { + if (!mSessions.contains(wsa.mSession)) { Slog.w(TAG, "LEAKED SURFACE (session doesn't exist): " - + ws + " surface=" + ws.mSurface - + " token=" + win.mToken + + ws + " surface=" + wsa.mSurface + + " token=" + ws.mToken + " pid=" + ws.mSession.mPid + " uid=" + ws.mSession.mUid); if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null); - ws.mSurface.destroy(); - ws.mSurfaceShown = false; - ws.mSurface = null; + wsa.mSurface.destroy(); + wsa.mSurfaceShown = false; + wsa.mSurface = null; + ws.mHasSurface = false; + mAnimator.mWinAnimators.remove(wsa); mForceRemoves.add(ws); i--; N--; leakedSurface = true; } else if (ws.mAppToken != null && ws.mAppToken.clientHidden) { Slog.w(TAG, "LEAKED SURFACE (app token hidden): " - + ws + " surface=" + ws.mSurface - + " token=" + win.mAppToken); + + ws + " surface=" + wsa.mSurface + + " token=" + ws.mAppToken); if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null); - ws.mSurface.destroy(); - ws.mSurfaceShown = false; - ws.mSurface = null; + wsa.mSurface.destroy(); + wsa.mSurfaceShown = false; + wsa.mSurface = null; + ws.mHasSurface = false; + mAnimator.mWinAnimators.remove(wsa); leakedSurface = true; } } @@ -9204,9 +8602,9 @@ public class WindowManagerService extends IWindowManager.Stub Slog.w(TAG, "No leaked surfaces; killing applicatons!"); SparseIntArray pidCandidates = new SparseIntArray(); for (int i=0; i<N; i++) { - WindowState ws = mWindows.get(i); - if (ws.mSurface != null) { - pidCandidates.append(ws.mSession.mPid, ws.mSession.mPid); + WindowStateAnimator wsa = mWindows.get(i).mWinAnimator; + if (wsa.mSurface != null) { + pidCandidates.append(wsa.mSession.mPid, wsa.mSession.mPid); } } if (pidCandidates.size() > 0) { @@ -9228,15 +8626,17 @@ public class WindowManagerService extends IWindowManager.Stub // surface and ask the app to request another one. Slog.w(TAG, "Looks like we have reclaimed some memory, clearing surface for retry."); if (surface != null) { - if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) logSurface(win, + if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) logSurface(winAnimator.mWin, "RECOVER DESTROY", null); surface.destroy(); - win.mSurfaceShown = false; - win.mSurface = null; + winAnimator.mSurfaceShown = false; + winAnimator.mSurface = null; + winAnimator.mWin.mHasSurface = false; + mAnimator.mWinAnimators.remove(winAnimator); } try { - win.mClient.dispatchGetNewSurface(); + winAnimator.mWin.mClient.dispatchGetNewSurface(); } catch (RemoteException e) { } } @@ -9258,6 +8658,7 @@ public class WindowManagerService extends IWindowManager.Stub TAG, "Changing focus from " + mCurrentFocus + " to " + newFocus); final WindowState oldFocus = mCurrentFocus; mCurrentFocus = newFocus; + mAnimator.setCurrentFocus(newFocus); mLosingFocus.remove(newFocus); int focusChanged = mPolicy.focusChangedLw(oldFocus, newFocus); @@ -9304,12 +8705,11 @@ public class WindowManagerService extends IWindowManager.Stub WindowState result = null; WindowState win; - int i = mWindows.size() - 1; int nextAppIndex = mAppTokens.size()-1; WindowToken nextApp = nextAppIndex >= 0 ? mAppTokens.get(nextAppIndex) : null; - while (i >= 0) { + for (int i = mWindows.size() - 1; i >= 0; i--) { win = mWindows.get(i); if (localLOGV || DEBUG_FOCUS) Slog.v( @@ -9322,7 +8722,6 @@ public class WindowManagerService extends IWindowManager.Stub // If this window's application has been removed, just skip it. if (thisApp != null && thisApp.removed) { - i--; continue; } @@ -9362,8 +8761,6 @@ public class WindowManagerService extends IWindowManager.Stub result = win; break; } - - i--; } return result; @@ -9389,6 +8786,7 @@ public class WindowManagerService extends IWindowManager.Stub if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET; mNextAppTransitionPackage = null; + mNextAppTransitionThumbnail = null; mAppTransitionReady = true; } @@ -9398,16 +8796,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, - mFxSession, inTransaction, mCurDisplayWidth, mCurDisplayHeight, - mDisplay.getRotation()); - } - if (!mScreenRotationAnimation.hasScreenshot()) { + + mAnimator.mScreenRotationAnimation = new ScreenRotationAnimation(mContext, + mFxSession, inTransaction, mCurDisplayWidth, mCurDisplayHeight, + mDisplay.getRotation()); + + if (!mAnimator.mScreenRotationAnimation.hasScreenshot()) { Surface.freezeDisplay(0); } } else { @@ -9421,6 +8819,10 @@ public class WindowManagerService extends IWindowManager.Stub } if (mWaitingForConfig || mAppsFreezingScreen > 0 || mWindowsFreezingScreen) { + if (DEBUG_ORIENTATION) Slog.d(TAG, + "stopFreezingDisplayLocked: Returning mWaitingForConfig=" + mWaitingForConfig + + ", mAppsFreezingScreen=" + mAppsFreezingScreen + + ", mWindowsFreezingScreen=" + mWindowsFreezingScreen); return; } @@ -9432,20 +8834,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; } @@ -9622,11 +9024,6 @@ public class WindowManagerService extends IWindowManager.Stub mPolicy.lockNow(); } - void dumpInput(FileDescriptor fd, PrintWriter pw, boolean dumpAll) { - pw.println("WINDOW MANAGER INPUT (dumpsys window input)"); - mInputManager.dump(pw); - } - void dumpPolicyLocked(FileDescriptor fd, PrintWriter pw, String[] args, boolean dumpAll) { pw.println("WINDOW MANAGER POLICY STATE (dumpsys window policy)"); mPolicy.dump(" ", fd, pw, args); @@ -9667,8 +9064,8 @@ public class WindowManagerService extends IWindowManager.Stub pw.println(); pw.println(" Application tokens in Z order:"); for (int i=mAppTokens.size()-1; i>=0; i--) { - pw.print(" App #"); pw.print(i); pw.print(": "); - pw.println(mAppTokens.get(i)); + pw.print(" App #"); pw.print(i); pw.println(": "); + mAppTokens.get(i).dump(pw, " "); } } if (mFinishedStarting.size() > 0) { @@ -9894,9 +9291,6 @@ public class WindowManagerService extends IWindowManager.Stub pw.print(" mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget); pw.print(" mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget); } - if (mWindowDetachedWallpaper != null) { - pw.print(" mWindowDetachedWallpaper="); pw.println(mWindowDetachedWallpaper); - } pw.print(" mLastWallpaperX="); pw.print(mLastWallpaperX); pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY); if (mInputMethodAnimLayerAdjustment != 0 || @@ -9906,20 +9300,9 @@ public class WindowManagerService extends IWindowManager.Stub pw.print(" mWallpaperAnimLayerAdjustment="); pw.println(mWallpaperAnimLayerAdjustment); } - if (mWindowAnimationBackgroundSurface != null) { - pw.println(" mWindowAnimationBackgroundSurface:"); - mWindowAnimationBackgroundSurface.printTo(" ", pw); - } pw.print(" mSystemBooted="); pw.print(mSystemBooted); pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled); - pw.print(" mLayoutNeeded="); pw.print(mLayoutNeeded); - pw.print(" mBlurShown="); pw.println(mBlurShown); - if (mDimAnimator != null) { - pw.println(" mDimAnimator:"); - mDimAnimator.printTo(" ", pw); - } else { - pw.println( " no DimAnimator "); - } + pw.print(" mLayoutNeeded="); pw.println(mLayoutNeeded); pw.print(" mDisplayFrozen="); pw.print(mDisplayFrozen); pw.print(" mWindowsFreezingScreen="); pw.print(mWindowsFreezingScreen); pw.print(" mAppsFreezingScreen="); pw.print(mAppsFreezingScreen); @@ -9929,9 +9312,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); @@ -9950,6 +9333,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); } @@ -9962,7 +9351,7 @@ public class WindowManagerService extends IWindowManager.Stub synchronized(mWindowMap) { for (int i=mWindows.size()-1; i>=0; i--) { WindowState w = mWindows.get(i); - if (w.mSurfaceShown) { + if (w.mWinAnimator.mSurfaceShown) { windows.add(w); } } @@ -10024,7 +9413,6 @@ public class WindowManagerService extends IWindowManager.Stub pw.println("Window manager dump options:"); pw.println(" [-a] [-h] [cmd] ..."); pw.println(" cmd may be one of:"); - pw.println(" i[input]: input subsystem state"); pw.println(" p[policy]: policy state"); pw.println(" s[essions]: active sessions"); pw.println(" t[okens]: token list"); @@ -10045,10 +9433,7 @@ public class WindowManagerService extends IWindowManager.Stub if (opti < args.length) { String cmd = args[opti]; opti++; - if ("input".equals(cmd) || "i".equals(cmd)) { - dumpInput(fd, pw, true); - return; - } else if ("policy".equals(cmd) || "p".equals(cmd)) { + if ("policy".equals(cmd) || "p".equals(cmd)) { synchronized(mWindowMap) { dumpPolicyLocked(fd, pw, args, true); } @@ -10083,8 +9468,6 @@ public class WindowManagerService extends IWindowManager.Stub } } - dumpInput(fd, pw, dumpAll); - synchronized(mWindowMap) { if (dumpAll) { pw.println("-------------------------------------------------------------------------------"); @@ -10117,4 +9500,20 @@ public class WindowManagerService extends IWindowManager.Stub public interface OnHardKeyboardStatusChangeListener { public void onHardKeyboardStatusChange(boolean available, boolean enabled); } + + void notifyAnimationChangedLayout(final int pendingLayoutChanges) { + mPendingLayoutChanges |= pendingLayoutChanges; + requestTraversalLocked(); + } + + void debugLayoutRepeats(final String msg, int pendingLayoutChanges) { + if (mLayoutRepeatCount >= LAYOUT_REPEAT_THRESHOLD) { + Slog.v(TAG, "Layouts looping: " + msg + ", mPendingLayoutChanges = 0x" + + Integer.toHexString(pendingLayoutChanges)); + } + } + + void bulkSetParameters(final int bulkUpdateParams) { + mH.sendMessage(mH.obtainMessage(H.BULK_UPDATE_PARAMETERS, bulkUpdateParams, 0)); + } } diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java index eeecad1..4de6425 100644 --- a/services/java/com/android/server/wm/WindowState.java +++ b/services/java/com/android/server/wm/WindowState.java @@ -19,13 +19,13 @@ package com.android.server.wm; import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW; import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW; -import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; -import com.android.server.wm.WindowManagerService.H; +import com.android.server.input.InputWindowHandle; +import android.content.Context; import android.content.res.Configuration; import android.graphics.Matrix; import android.graphics.PixelFormat; @@ -39,14 +39,10 @@ import android.view.Gravity; import android.view.IApplicationToken; import android.view.IWindow; import android.view.InputChannel; -import android.view.Surface; import android.view.View; 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; import java.util.ArrayList; @@ -55,18 +51,25 @@ import java.util.ArrayList; * A window in the window manager. */ final class WindowState implements WindowManagerPolicy.WindowState { + static final String TAG = "WindowState"; + static final boolean DEBUG_VISIBILITY = WindowManagerService.DEBUG_VISIBILITY; static final boolean SHOW_TRANSACTIONS = WindowManagerService.SHOW_TRANSACTIONS; static final boolean SHOW_LIGHT_TRANSACTIONS = WindowManagerService.SHOW_LIGHT_TRANSACTIONS; static final boolean SHOW_SURFACE_ALLOC = WindowManagerService.SHOW_SURFACE_ALLOC; final WindowManagerService mService; + final WindowManagerPolicy mPolicy; + final Context mContext; final Session mSession; final IWindow mClient; WindowToken mToken; WindowToken mRootToken; AppWindowToken mAppToken; AppWindowToken mTargetAppToken; + + // mAttrs.flags is tested in animation without being locked. If the bits tested are ever + // modified they will need to be locked. final WindowManager.LayoutParams mAttrs = new WindowManager.LayoutParams(); final DeathRecipient mDeathRecipient; final WindowState mAttachedWindow; @@ -84,14 +87,8 @@ final class WindowState implements WindowManagerPolicy.WindowState { boolean mPolicyVisibility = true; boolean mPolicyVisibilityAfterAnim = true; boolean mAppFreezing; - Surface mSurface; - Surface mPendingDestroySurface; - boolean mReportDestroySurface; - boolean mSurfacePendingDestroy; 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 @@ -99,18 +96,18 @@ final class WindowState implements WindowManagerPolicy.WindowState { */ int mRequestedWidth; int mRequestedHeight; + int mLastRequestedWidth; + int mLastRequestedHeight; int mLayer; - int mAnimLayer; - int mLastLayer; boolean mHaveFrame; boolean mObscured; 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 @@ -119,18 +116,6 @@ final class WindowState implements WindowManagerPolicy.WindowState { final RectF mShownFrame = new RectF(); /** - * Set when we have changed the size of the surface, to know that - * we must tell them application to resize (and thus redraw itself). - */ - boolean mSurfaceResized; - - /** - * Set if the client has asked that the destroy of its surface be delayed - * until it explicitly says it is okay. - */ - boolean mSurfaceDestroyDeferred; - - /** * Insets that determine the actually visible area. These are in the application's * coordinate space (without compatibility scale applied). */ @@ -178,11 +163,8 @@ final class WindowState implements WindowManagerPolicy.WindowState { int mTouchableInsets = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME; // Current transformation being applied. - boolean mHaveMatrix; float mGlobalScale=1; float mInvGlobalScale=1; - float mDsDx=1, mDtDx=0, mDsDy=0, mDtDy=1; - float mLastDsDx=1, mLastDtDx=0, mLastDsDy=0, mLastDtDy=1; float mHScale=1, mVScale=1; float mLastHScale=1, mLastVScale=1; final Matrix mTmpMatrix = new Matrix(); @@ -202,23 +184,6 @@ final class WindowState implements WindowManagerPolicy.WindowState { boolean mContentChanged; - float mShownAlpha = 1; - float mAlpha = 1; - float mLastAlpha = 1; - - // Set to true if, when the window gets displayed, it should perform - // 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; @@ -245,24 +210,6 @@ final class WindowState implements WindowManagerPolicy.WindowState { // when in that case until the layout is done. boolean mLayoutNeeded; - // This is set after the Surface has been created but before the - // window has been drawn. During this time the surface is hidden. - boolean mDrawPending; - - // This is set after the window has finished drawing for the first - // time but before its surface is shown. The surface will be - // displayed when the next layout is run. - boolean mCommitDrawPending; - - // This is set during the time after the window's drawing has been - // committed, and before its surface is actually shown. It is used - // to delay showing the surface until all windows in a token are ready - // to be shown. - boolean mReadyToShow; - - // Set when the window has been shown in the screen the first time. - boolean mHasDrawn; - // Currently running an exit animation? boolean mExiting; @@ -283,12 +230,6 @@ final class WindowState implements WindowManagerPolicy.WindowState { // rebuilding window list. boolean mRebuilding; - // For debugging, this is the last information given to the surface flinger. - boolean mSurfaceShown; - float mSurfaceX, mSurfaceY, mSurfaceW, mSurfaceH; - int mSurfaceLayer; - float mSurfaceAlpha; - // Input channel and input window handle used by the input dispatcher. final InputWindowHandle mInputWindowHandle; InputChannel mInputChannel; @@ -298,10 +239,9 @@ final class WindowState implements WindowManagerPolicy.WindowState { CharSequence mLastTitle; boolean mWasPaused; - // Used to save animation distances between the time they are calculated and when they are - // used. - int mAnimDw; - int mAnimDh; + final WindowStateAnimator mWinAnimator; + + boolean mHasSurface = false; WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token, WindowState attachedWindow, int seq, WindowManager.LayoutParams a, @@ -312,12 +252,13 @@ final class WindowState implements WindowManagerPolicy.WindowState { mToken = token; mAttrs.copyFrom(a); mViewVisibility = viewVisibility; + mPolicy = mService.mPolicy; + mContext = mService.mContext; DeathRecipient deathRecipient = new DeathRecipient(); - mAlpha = a.alpha; mSeq = seq; mEnforceSizeCompat = (mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0; if (WindowManagerService.localLOGV) Slog.v( - WindowManagerService.TAG, "Window " + this + " client=" + c.asBinder() + TAG, "Window " + this + " client=" + c.asBinder() + " token=" + token + " (" + mAttrs.token + ")"); try { c.asBinder().linkToDeath(deathRecipient, 0); @@ -331,6 +272,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { mBaseLayer = 0; mSubLayer = 0; mInputWindowHandle = null; + mWinAnimator = null; return; } mDeathRecipient = deathRecipient; @@ -339,12 +281,12 @@ final class WindowState implements WindowManagerPolicy.WindowState { mAttrs.type <= LAST_SUB_WINDOW)) { // The multiplier here is to reserve space for multiple // windows in the same type layer. - mBaseLayer = mService.mPolicy.windowTypeToLayerLw( + mBaseLayer = mPolicy.windowTypeToLayerLw( attachedWindow.mAttrs.type) * WindowManagerService.TYPE_LAYER_MULTIPLIER + WindowManagerService.TYPE_LAYER_OFFSET; - mSubLayer = mService.mPolicy.subWindowTypeToLayerLw(a.type); + mSubLayer = mPolicy.subWindowTypeToLayerLw(a.type); mAttachedWindow = attachedWindow; - if (WindowManagerService.DEBUG_ADD_REMOVE) Slog.v(WindowManagerService.TAG, "Adding " + this + " to " + mAttachedWindow); + if (WindowManagerService.DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + this + " to " + mAttachedWindow); mAttachedWindow.mChildWindows.add(this); mLayoutAttached = mAttrs.type != WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; @@ -355,7 +297,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { } else { // The multiplier here is to reserve space for multiple // windows in the same type layer. - mBaseLayer = mService.mPolicy.windowTypeToLayerLw(a.type) + mBaseLayer = mPolicy.windowTypeToLayerLw(a.type) * WindowManagerService.TYPE_LAYER_MULTIPLIER + WindowManagerService.TYPE_LAYER_OFFSET; mSubLayer = 0; @@ -367,9 +309,12 @@ final class WindowState implements WindowManagerPolicy.WindowState { mIsFloatingLayer = mIsImWindow || mIsWallpaper; } + mWinAnimator = new WindowStateAnimator(service, this, mAttachedWindow); + mWinAnimator.mAlpha = a.alpha; + WindowState appWin = this; while (appWin.mAttachedWindow != null) { - appWin = mAttachedWindow; + appWin = appWin.mAttachedWindow; } WindowToken appToken = appWin.mToken; while (appToken.appWindowToken == null) { @@ -382,25 +327,25 @@ final class WindowState implements WindowManagerPolicy.WindowState { mRootToken = appToken; mAppToken = appToken.appWindowToken; - mSurface = null; mRequestedWidth = 0; mRequestedHeight = 0; + mLastRequestedWidth = 0; + mLastRequestedHeight = 0; mXOffset = 0; mYOffset = 0; mLayer = 0; - mAnimLayer = 0; - mLastLayer = 0; mInputWindowHandle = new InputWindowHandle( mAppToken != null ? mAppToken.mInputApplicationHandle : null, this); } void attach() { if (WindowManagerService.localLOGV) Slog.v( - WindowManagerService.TAG, "Attaching " + this + " token=" + mToken + TAG, "Attaching " + this + " token=" + mToken + ", list=" + mToken.windows); mSession.windowAddedLocked(); } + @Override public void computeFrameLw(Rect pf, Rect df, Rect cf, Rect vf) { mHaveFrame = true; @@ -452,6 +397,11 @@ final class WindowState implements WindowManagerPolicy.WindowState { mParentFrame.set(pf); mContentChanged = true; } + if (mRequestedWidth != mLastRequestedWidth || mRequestedHeight != mLastRequestedHeight) { + mLastRequestedWidth = mRequestedWidth; + mLastRequestedHeight = mRequestedHeight; + mContentChanged = true; + } final Rect content = mContentFrame; content.set(cf); @@ -528,7 +478,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { if (WindowManagerService.localLOGV) { //if ("com.google.android.youtube".equals(mAttrs.packageName) // && mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) { - Slog.v(WindowManagerService.TAG, "Resolving (mRequestedWidth=" + Slog.v(TAG, "Resolving (mRequestedWidth=" + mRequestedWidth + ", mRequestedheight=" + mRequestedHeight + ") to" + " (pw=" + pw + ", ph=" + ph + "): frame=" + mFrame.toShortString() @@ -538,38 +488,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; } @@ -623,542 +582,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; - mSurfacePendingDestroy = false; - if (WindowManagerService.DEBUG_ORIENTATION) Slog.i(WindowManagerService.TAG, - "createSurface " + this + ": DRAW NOW PENDING"); - mDrawPending = true; - mCommitDrawPending = false; - mReadyToShow = false; - if (mAppToken != null) { - mAppToken.allDrawn = false; - } - - mService.makeWindowFreezingScreenIfNeededLocked(this); - - int flags = 0; - - if ((mAttrs.flags&WindowManager.LayoutParams.FLAG_SECURE) != 0) { - flags |= Surface.SECURE; - } - if (DEBUG_VISIBILITY) Slog.v( - WindowManagerService.TAG, "Creating surface in session " - + mSession.mSurfaceSession + " window " + this - + " w=" + mCompatFrame.width() - + " h=" + mCompatFrame.height() + " format=" - + mAttrs.format + " flags=" + flags); - - int w = mCompatFrame.width(); - int h = mCompatFrame.height(); - if ((mAttrs.flags & LayoutParams.FLAG_SCALED) != 0) { - // for a scaled surface, we always want the requested - // size. - w = mRequestedWidth; - h = mRequestedHeight; - } - - // Something is wrong and SurfaceFlinger will not like this, - // try to revert to sane values - if (w <= 0) w = 1; - if (h <= 0) h = 1; - - mSurfaceShown = false; - mSurfaceLayer = 0; - mSurfaceAlpha = 1; - mSurfaceX = 0; - mSurfaceY = 0; - mSurfaceW = w; - mSurfaceH = h; - try { - final boolean isHwAccelerated = (mAttrs.flags & - WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0; - final int format = isHwAccelerated ? PixelFormat.TRANSLUCENT : mAttrs.format; - if (!PixelFormat.formatHasAlpha(mAttrs.format)) { - flags |= Surface.OPAQUE; - } - mSurface = new Surface( - mSession.mSurfaceSession, mSession.mPid, - mAttrs.getTitle().toString(), - 0, w, h, format, flags); - if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG, - " CREATE SURFACE " - + mSurface + " IN SESSION " - + mSession.mSurfaceSession - + ": pid=" + mSession.mPid + " format=" - + mAttrs.format + " flags=0x" - + Integer.toHexString(flags) - + " / " + this); - } catch (Surface.OutOfResourcesException e) { - Slog.w(WindowManagerService.TAG, "OutOfResourcesException creating surface"); - mService.reclaimSomeSurfaceMemoryLocked(this, "create", true); - return null; - } catch (Exception e) { - Slog.e(WindowManagerService.TAG, "Exception creating surface", e); - return null; - } - - if (WindowManagerService.localLOGV) Slog.v( - WindowManagerService.TAG, "Got surface: " + mSurface - + ", set left=" + mFrame.left + " top=" + mFrame.top - + ", animLayer=" + mAnimLayer); - if (SHOW_LIGHT_TRANSACTIONS) { - Slog.i(WindowManagerService.TAG, ">>> OPEN TRANSACTION createSurfaceLocked"); - WindowManagerService.logSurface(this, "CREATE pos=(" + mFrame.left - + "," + mFrame.top + ") (" + - mCompatFrame.width() + "x" + mCompatFrame.height() + "), layer=" + - mAnimLayer + " HIDE", null); - } - Surface.openTransaction(); - try { - try { - mSurfaceX = mFrame.left + mXOffset; - mSurfaceY = mFrame.top + mYOffset; - mSurface.setPosition(mSurfaceX, mSurfaceY); - mSurfaceLayer = mAnimLayer; - mSurface.setLayer(mAnimLayer); - mSurfaceShown = false; - mSurface.hide(); - if ((mAttrs.flags&WindowManager.LayoutParams.FLAG_DITHER) != 0) { - if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(this, "DITHER", null); - mSurface.setFlags(Surface.SURFACE_DITHER, - Surface.SURFACE_DITHER); - } - } catch (RuntimeException e) { - Slog.w(WindowManagerService.TAG, "Error creating surface in " + w, e); - mService.reclaimSomeSurfaceMemoryLocked(this, "create-init", true); - } - mLastHidden = true; - } finally { - Surface.closeTransaction(); - if (SHOW_LIGHT_TRANSACTIONS) Slog.i(WindowManagerService.TAG, - "<<< CLOSE TRANSACTION createSurfaceLocked"); - } - if (WindowManagerService.localLOGV) Slog.v( - WindowManagerService.TAG, "Created surface " + this); - } - return mSurface; - } - - void destroySurfaceLocked() { - if (mAppToken != null && this == mAppToken.startingWindow) { - mAppToken.startingDisplayed = false; - } - - if (mSurface != null) { - mDrawPending = false; - mCommitDrawPending = false; - mReadyToShow = false; - - int i = mChildWindows.size(); - while (i > 0) { - i--; - WindowState c = mChildWindows.get(i); - c.mAttachedHidden = true; - } - - if (mReportDestroySurface) { - mReportDestroySurface = false; - mSurfacePendingDestroy = true; - try { - mClient.dispatchGetNewSurface(); - // We'll really destroy on the next time around. - return; - } catch (RemoteException e) { - } - } - - try { - if (DEBUG_VISIBILITY) { - RuntimeException e = null; - if (!WindowManagerService.HIDE_STACK_CRAWLS) { - e = new RuntimeException(); - e.fillInStackTrace(); - } - Slog.w(WindowManagerService.TAG, "Window " + this + " destroying surface " - + mSurface + ", session " + mSession, e); - } - if (mSurfaceDestroyDeferred) { - if (mSurface != null && mPendingDestroySurface != mSurface) { - if (mPendingDestroySurface != null) { - if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) { - RuntimeException e = null; - if (!WindowManagerService.HIDE_STACK_CRAWLS) { - e = new RuntimeException(); - e.fillInStackTrace(); - } - WindowManagerService.logSurface(this, "DESTROY PENDING", e); - } - mPendingDestroySurface.destroy(); - } - mPendingDestroySurface = mSurface; - } - } else { - if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) { - RuntimeException e = null; - if (!WindowManagerService.HIDE_STACK_CRAWLS) { - e = new RuntimeException(); - e.fillInStackTrace(); - } - WindowManagerService.logSurface(this, "DESTROY", e); - } - mSurface.destroy(); - } - } catch (RuntimeException e) { - Slog.w(WindowManagerService.TAG, "Exception thrown when destroying Window " + this - + " surface " + mSurface + " session " + mSession - + ": " + e.toString()); - } - - mSurfaceShown = false; - mSurface = null; - } - } - - void destroyDeferredSurfaceLocked() { - try { - if (mPendingDestroySurface != null) { - if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) { - RuntimeException e = null; - if (!WindowManagerService.HIDE_STACK_CRAWLS) { - e = new RuntimeException(); - e.fillInStackTrace(); - } - mService.logSurface(this, "DESTROY PENDING", e); - } - mPendingDestroySurface.destroy(); - } - } catch (RuntimeException e) { - Slog.w(WindowManagerService.TAG, "Exception thrown when destroying Window " - + this + " surface " + mPendingDestroySurface - + " session " + mSession + ": " + e.toString()); - } - mSurfaceDestroyDeferred = false; - mPendingDestroySurface = null; - } - - boolean finishDrawingLocked() { - if (mDrawPending) { - if (SHOW_TRANSACTIONS || WindowManagerService.DEBUG_ORIENTATION) Slog.v( - WindowManagerService.TAG, "finishDrawingLocked: " + this + " in " + mSurface); - mCommitDrawPending = true; - mDrawPending = false; - return true; - } - return false; - } - - // This must be called while inside a transaction. - boolean commitFinishDrawingLocked(long currentTime) { - //Slog.i(TAG, "commitFinishDrawingLocked: " + mSurface); - if (!mCommitDrawPending) { - return false; - } - mCommitDrawPending = false; - mReadyToShow = true; - final boolean starting = mAttrs.type == TYPE_APPLICATION_STARTING; - final AppWindowToken atoken = mAppToken; - if (atoken == null || atoken.allDrawn || starting) { - performShowLocked(); - } - return true; - } - - // This must be called while inside a transaction. - boolean performShowLocked() { - if (DEBUG_VISIBILITY) { - RuntimeException e = null; - if (!WindowManagerService.HIDE_STACK_CRAWLS) { - e = new RuntimeException(); - e.fillInStackTrace(); - } - Slog.v(WindowManagerService.TAG, "performShow on " + this - + ": readyToShow=" + mReadyToShow + " readyForDisplay=" + isReadyForDisplay() - + " starting=" + (mAttrs.type == TYPE_APPLICATION_STARTING), e); - } - if (mReadyToShow && isReadyForDisplay()) { - if (SHOW_TRANSACTIONS || WindowManagerService.DEBUG_ORIENTATION) WindowManagerService.logSurface(this, - "SHOW (performShowLocked)", null); - if (DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "Showing " + this - + " during animation: policyVis=" + mPolicyVisibility - + " attHidden=" + mAttachedHidden - + " tok.hiddenRequested=" - + (mAppToken != null ? mAppToken.hiddenRequested : false) - + " tok.hidden=" - + (mAppToken != null ? mAppToken.hidden : false) - + " animating=" + mAnimating - + " tok animating=" - + (mAppToken != null ? mAppToken.animating : false)); - if (!mService.showSurfaceRobustlyLocked(this)) { - return false; - } - mLastAlpha = -1; - mHasDrawn = true; - mLastHidden = false; - mReadyToShow = false; - mService.enableScreenIfNeededLocked(); - - mService.applyEnterAnimationLocked(this); - - int i = mChildWindows.size(); - while (i > 0) { - i--; - WindowState c = mChildWindows.get(i); - if (c.mAttachedHidden) { - c.mAttachedHidden = false; - if (c.mSurface != null) { - c.performShowLocked(); - // It hadn't been shown, which means layout not - // performed on it, so now we want to make sure to - // do a layout. If called from within the transaction - // loop, this will cause it to restart with a new - // layout. - mService.mLayoutNeeded = true; - } - } - } - - if (mAttrs.type != TYPE_APPLICATION_STARTING - && mAppToken != null) { - mAppToken.firstWindowDrawn = true; - - if (mAppToken.startingData != null) { - if (WindowManagerService.DEBUG_STARTING_WINDOW || WindowManagerService.DEBUG_ANIM) Slog.v(WindowManagerService.TAG, - "Finish starting " + mToken - + ": first real window is shown, no animation"); - // If this initial window is animating, stop it -- we - // 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; - // Make sure we clean up the animation. - mAnimating = true; - } - mService.mFinishedStarting.add(mAppToken); - mService.mH.sendEmptyMessage(H.FINISHED_STARTING); - } - mAppToken.updateReportedVisibilityLocked(); - } - } - return true; - } - - // 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 (!mDrawPending && !mCommitDrawPending && 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; - } - 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); - if (more) { - // we're not done! - return true; - } - if (WindowManagerService.DEBUG_ANIM) Slog.v( - WindowManagerService.TAG, "Finished animation in " + this + - " @ " + currentTime); - - if (mAnimation != null) { - mAnimation.cancel(); - mAnimation = null; - } - //WindowManagerService.this.dump(); - } - mHasLocalTransformation = false; - if ((!mLocalAnimating || mAnimationIsEntrance) && mAppToken != null - && mAppToken.animation != null) { - // When our app token is animating, we kind-of pretend like - // we are as well. Note the mLocalAnimating mAnimationIsEntrance - // part of this check means that we will only do this if - // our window is not currently exiting, or it is not - // locally animating itself. The idea being that one that - // is exiting and doing a local animation should be removed - // once that animation is done. - mAnimating = true; - mHasTransformation = true; - mTransformation.clear(); - return false; - } else if (mHasTransformation) { - // Little trick to get through the path below to act like - // we have finished an animation. - mAnimating = true; - } else if (isAnimating()) { - mAnimating = true; - } - } else if (mAnimation != null) { - // If the display is frozen, and there is a pending animation, - // clear it and make sure we run the cleanup code. - mAnimating = true; - mLocalAnimating = true; - mAnimation.cancel(); - mAnimation = null; - } - - if (!mAnimating && !mLocalAnimating) { - return false; - } - - if (WindowManagerService.DEBUG_ANIM) Slog.v( - WindowManagerService.TAG, "Animation done in " + this + ": exiting=" + mExiting - + ", reportedVisible=" - + (mAppToken != null ? mAppToken.reportedVisible : false)); - - mAnimating = false; - mLocalAnimating = false; - if (mAnimation != null) { - mAnimation.cancel(); - mAnimation = null; - } - if (mService.mWindowDetachedWallpaper == this) { - mService.mWindowDetachedWallpaper = null; - } - mAnimLayer = mLayer; - if (mIsImWindow) { - mAnimLayer += mService.mInputMethodAnimLayerAdjustment; - } else if (mIsWallpaper) { - mAnimLayer += mService.mWallpaperAnimLayerAdjustment; - } - if (WindowManagerService.DEBUG_LAYERS) Slog.v(WindowManagerService.TAG, "Stepping win " + this - + " anim layer: " + mAnimLayer); - mHasTransformation = false; - mHasLocalTransformation = false; - if (mPolicyVisibility != mPolicyVisibilityAfterAnim) { - if (DEBUG_VISIBILITY) { - Slog.v(WindowManagerService.TAG, "Policy visibility changing after anim in " + this + ": " - + mPolicyVisibilityAfterAnim); - } - mPolicyVisibility = mPolicyVisibilityAfterAnim; - mService.mLayoutNeeded = true; - if (!mPolicyVisibility) { - if (mService.mCurrentFocus == this) { - mService.mFocusMayChange = true; - } - // Window is no longer visible -- make sure if we were waiting - // for it to be displayed before enabling the display, that - // we allow the display to be enabled now. - mService.enableScreenIfNeededLocked(); - } - } - mTransformation.clear(); - if (mHasDrawn - && mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING - && mAppToken != null - && mAppToken.firstWindowDrawn - && mAppToken.startingData != null) { - if (WindowManagerService.DEBUG_STARTING_WINDOW) Slog.v(WindowManagerService.TAG, "Finish starting " - + mToken + ": first real window done animating"); - mService.mFinishedStarting.add(mAppToken); - mService.mH.sendEmptyMessage(H.FINISHED_STARTING); - } - - finishExit(); - - if (mAppToken != null) { - mAppToken.updateReportedVisibilityLocked(); - } - - return false; - } - - void finishExit() { - if (WindowManagerService.DEBUG_ANIM) Slog.v( - WindowManagerService.TAG, "finishExit in " + this - + ": exiting=" + mExiting - + " remove=" + mRemoveOnExit - + " windowAnimating=" + isWindowAnimating()); - - final int N = mChildWindows.size(); - for (int i=0; i<N; i++) { - mChildWindows.get(i).finishExit(); - } - - if (!mExiting) { - return; - } - - if (isWindowAnimating()) { - return; - } - - if (WindowManagerService.localLOGV) Slog.v( - WindowManagerService.TAG, "Exit animation finished in " + this - + ": remove=" + mRemoveOnExit); - if (mSurface != null) { - mService.mDestroySurface.add(this); - mDestroying = true; - if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(this, "HIDE (finishExit)", null); - mSurfaceShown = false; - try { - mSurface.hide(); - } catch (RuntimeException e) { - Slog.w(WindowManagerService.TAG, "Error hiding surface in " + this, e); - } - mLastHidden = true; - } - mExiting = false; - if (mRemoveOnExit) { - mService.mPendingRemove.add(this); - mRemoveOnExit = false; - } - } - boolean isIdentityMatrix(float dsdx, float dtdx, float dsdy, float dtdy) { if (dsdx < .99999f || dsdx > 1.00001f) return false; if (dtdy < .99999f || dtdy > 1.00001f) return false; @@ -1176,147 +599,6 @@ final class WindowState implements WindowManagerPolicy.WindowState { } } - void computeShownFrameLocked() { - final boolean selfTransformation = mHasLocalTransformation; - Transformation attachedTransformation = - (mAttachedWindow != null && mAttachedWindow.mHasLocalTransformation) - ? mAttachedWindow.mTransformation : null; - Transformation appTransformation = - (mAppToken != null && mAppToken.hasTransformation) - ? mAppToken.transformation : null; - - // Wallpapers are animated based on the "real" window they - // 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 (WindowManagerService.DEBUG_WALLPAPER && attachedTransformation != null) { - Slog.v(WindowManagerService.TAG, "WP target attached xform: " + attachedTransformation); - } - } - if (mService.mWallpaperTarget.mAppToken != null && - mService.mWallpaperTarget.mAppToken.hasTransformation && - mService.mWallpaperTarget.mAppToken.animation != null && - !mService.mWallpaperTarget.mAppToken.animation.getDetachWallpaper()) { - appTransformation = mService.mWallpaperTarget.mAppToken.transformation; - if (WindowManagerService.DEBUG_WALLPAPER && appTransformation != null) { - Slog.v(WindowManagerService.TAG, "WP target app xform: " + appTransformation); - } - } - } - - final boolean screenAnimation = mService.mScreenRotationAnimation != null - && mService.mScreenRotationAnimation.isAnimating(); - if (selfTransformation || attachedTransformation != null - || appTransformation != null || screenAnimation) { - // cache often used attributes locally - final Rect frame = mFrame; - final float tmpFloats[] = mService.mTmpFloats; - final Matrix tmpMatrix = mTmpMatrix; - - // Compute the desired transformation. - if (screenAnimation) { - // If we are doing a screen animation, the global rotation - // applied to windows can result in windows that are carefully - // aligned with each other to slightly separate, allowing you - // to see what is behind them. An unsightly mess. This... - // thing... magically makes it call good: scale each window - // slightly (two pixels larger in each dimension, from the - // window's center). - final float w = frame.width(); - final float h = frame.height(); - if (w>=1 && h>=1) { - tmpMatrix.setScale(1 + 2/w, 1 + 2/h, w/2, h/2); - } else { - tmpMatrix.reset(); - } - } else { - tmpMatrix.reset(); - } - tmpMatrix.postScale(mGlobalScale, mGlobalScale); - if (selfTransformation) { - tmpMatrix.postConcat(mTransformation.getMatrix()); - } - tmpMatrix.postTranslate(frame.left + mXOffset, frame.top + mYOffset); - if (attachedTransformation != null) { - tmpMatrix.postConcat(attachedTransformation.getMatrix()); - } - if (appTransformation != null) { - tmpMatrix.postConcat(appTransformation.getMatrix()); - } - if (screenAnimation) { - tmpMatrix.postConcat( - mService.mScreenRotationAnimation.getEnterTransformation().getMatrix()); - } - - // "convert" it into SurfaceFlinger's format - // (a 2x2 matrix + an offset) - // Here we must not transform the position of the surface - // since it is already included in the transformation. - //Slog.i(TAG, "Transform: " + matrix); - - mHaveMatrix = true; - tmpMatrix.getValues(tmpFloats); - mDsDx = tmpFloats[Matrix.MSCALE_X]; - mDtDx = tmpFloats[Matrix.MSKEW_Y]; - mDsDy = tmpFloats[Matrix.MSKEW_X]; - mDtDy = tmpFloats[Matrix.MSCALE_Y]; - float x = tmpFloats[Matrix.MTRANS_X]; - float y = tmpFloats[Matrix.MTRANS_Y]; - int w = frame.width(); - int h = frame.height(); - mShownFrame.set(x, y, x+w, y+h); - - // Now set the alpha... but because our current hardware - // can't do alpha transformation on a non-opaque surface, - // turn it off if we are running an animation that is also - // transforming since it is more important to have that - // animation be smooth. - mShownAlpha = mAlpha; - if (!mService.mLimitedAlphaCompositing - || (!PixelFormat.formatHasAlpha(mAttrs.format) - || (isIdentityMatrix(mDsDx, mDtDx, mDsDy, mDtDy) - && x == frame.left && y == frame.top))) { - //Slog.i(TAG, "Applying alpha transform"); - if (selfTransformation) { - mShownAlpha *= mTransformation.getAlpha(); - } - if (attachedTransformation != null) { - mShownAlpha *= attachedTransformation.getAlpha(); - } - if (appTransformation != null) { - mShownAlpha *= appTransformation.getAlpha(); - } - if (screenAnimation) { - mShownAlpha *= - mService.mScreenRotationAnimation.getEnterTransformation().getAlpha(); - } - } else { - //Slog.i(TAG, "Not applying alpha transform"); - } - - if (WindowManagerService.localLOGV) Slog.v( - WindowManagerService.TAG, "Continuing animation in " + this + - ": " + mShownFrame + - ", alpha=" + mTransformation.getAlpha()); - return; - } - - mShownFrame.set(mFrame); - if (mXOffset != 0 || mYOffset != 0) { - mShownFrame.offset(mXOffset, mYOffset); - } - mShownAlpha = mAlpha; - mHaveMatrix = false; - mDsDx = mGlobalScale; - mDtDx = 0; - mDsDy = 0; - mDtDy = mGlobalScale; - } - /** * Is this window visible? It is not visible if there is no * surface, or we are in the process of running an exit animation @@ -1324,7 +606,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { */ public boolean isVisibleLw() { final AppWindowToken atoken = mAppToken; - return mSurface != null && mPolicyVisibility && !mAttachedHidden + return mHasSurface && mPolicyVisibility && !mAttachedHidden && (atoken == null || !atoken.hiddenRequested) && !mExiting && !mDestroying; } @@ -1344,12 +626,12 @@ final class WindowState implements WindowManagerPolicy.WindowState { } final AppWindowToken atoken = mAppToken; final boolean animating = atoken != null - ? (atoken.animation != null) : false; - return mSurface != null && !mDestroying && !mExiting + ? (atoken.mAppAnimator.animation != null) : false; + return mHasSurface && !mDestroying && !mExiting && (atoken == null ? mPolicyVisibility : !atoken.hiddenRequested) && ((!mAttachedHidden && mViewVisibility == View.VISIBLE && !mRootToken.hidden) - || mAnimation != null || animating); + || mWinAnimator.mAnimation != null || animating); } /** @@ -1359,8 +641,8 @@ final class WindowState implements WindowManagerPolicy.WindowState { */ public boolean isWinVisibleLw() { final AppWindowToken atoken = mAppToken; - return mSurface != null && mPolicyVisibility && !mAttachedHidden - && (atoken == null || !atoken.hiddenRequested || atoken.animating) + return mHasSurface && mPolicyVisibility && !mAttachedHidden + && (atoken == null || !atoken.hiddenRequested || atoken.mAppAnimator.animating) && !mExiting && !mDestroying; } @@ -1369,7 +651,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { * the associated app token, not the pending requested hidden state. */ boolean isVisibleNow() { - return mSurface != null && mPolicyVisibility && !mAttachedHidden + return mHasSurface && mPolicyVisibility && !mAttachedHidden && !mRootToken.hidden && !mExiting && !mDestroying; } @@ -1389,7 +671,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { */ boolean isVisibleOrAdding() { final AppWindowToken atoken = mAppToken; - return ((mSurface != null && !mReportDestroySurface) + return ((mHasSurface && !mWinAnimator.mReportDestroySurface) || (!mRelayoutCalled && mViewVisibility == View.VISIBLE)) && mPolicyVisibility && !mAttachedHidden && (atoken == null || !atoken.hiddenRequested) @@ -1402,15 +684,15 @@ final class WindowState implements WindowManagerPolicy.WindowState { * being visible. */ boolean isOnScreen() { + if (!mHasSurface || !mPolicyVisibility || mDestroying) { + return false; + } final AppWindowToken atoken = mAppToken; if (atoken != null) { - return mSurface != null && mPolicyVisibility && !mDestroying - && ((!mAttachedHidden && !atoken.hiddenRequested) - || mAnimation != null || atoken.animation != null); - } else { - return mSurface != null && mPolicyVisibility && !mDestroying - && (!mAttachedHidden || mAnimation != null); + return ((!mAttachedHidden && !atoken.hiddenRequested) + || mWinAnimator.mAnimation != null || atoken.mAppAnimator.animation != null); } + return !mAttachedHidden || mWinAnimator.mAnimation != null; } /** @@ -1422,29 +704,11 @@ final class WindowState implements WindowManagerPolicy.WindowState { mService.mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { return false; } - final AppWindowToken atoken = mAppToken; - final boolean animating = atoken != null - ? (atoken.animation != null) : false; - return mSurface != null && mPolicyVisibility && !mDestroying + return mHasSurface && mPolicyVisibility && !mDestroying && ((!mAttachedHidden && mViewVisibility == View.VISIBLE && !mRootToken.hidden) - || mAnimation != null || animating); - } - - /** 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; + || mWinAnimator.mAnimation != null + || ((mAppToken != null) && (mAppToken.mAppAnimator.animation != null))); } /** @@ -1453,11 +717,10 @@ final class WindowState implements WindowManagerPolicy.WindowState { */ public boolean isDisplayedLw() { final AppWindowToken atoken = mAppToken; - return mSurface != null && mPolicyVisibility && !mDestroying - && !mDrawPending && !mCommitDrawPending + return isDrawnLw() && mPolicyVisibility && ((!mAttachedHidden && (atoken == null || !atoken.hiddenRequested)) - || mAnimating); + || mWinAnimator.mAnimating); } public boolean isGoneForLayoutLw() { @@ -1475,9 +738,9 @@ final class WindowState implements WindowManagerPolicy.WindowState { * complete UI in to. */ public boolean isDrawnLw() { - final AppWindowToken atoken = mAppToken; - return mSurface != null && !mDestroying - && !mDrawPending && !mCommitDrawPending; + return mHasSurface && !mDestroying && + (mWinAnimator.mDrawState == WindowStateAnimator.READY_TO_SHOW + || mWinAnimator.mDrawState == WindowStateAnimator.HAS_DRAWN); } /** @@ -1487,9 +750,8 @@ final class WindowState implements WindowManagerPolicy.WindowState { boolean isOpaqueDrawn() { return (mAttrs.format == PixelFormat.OPAQUE || mAttrs.type == TYPE_WALLPAPER) - && mSurface != null && mAnimation == null - && (mAppToken == null || mAppToken.animation == null) - && !mDrawPending && !mCommitDrawPending; + && isDrawnLw() && mWinAnimator.mAnimation == null + && (mAppToken == null || mAppToken.mAppAnimator.animation == null); } /** @@ -1498,11 +760,10 @@ final class WindowState implements WindowManagerPolicy.WindowState { * sense to call from performLayoutAndPlaceSurfacesLockedInner().) */ boolean shouldAnimateMove() { - return mContentChanged && !mExiting && !mLastHidden && !mService.mDisplayFrozen + return mContentChanged && !mExiting && !mWinAnimator.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) { @@ -1514,11 +775,11 @@ final class WindowState implements WindowManagerPolicy.WindowState { disposeInputChannel(); if (mAttachedWindow != null) { - if (WindowManagerService.DEBUG_ADD_REMOVE) Slog.v(WindowManagerService.TAG, "Removing " + this + " from " + mAttachedWindow); + if (WindowManagerService.DEBUG_ADD_REMOVE) Slog.v(TAG, "Removing " + this + " from " + mAttachedWindow); mAttachedWindow.mChildWindows.remove(this); } - destroyDeferredSurfaceLocked(); - destroySurfaceLocked(); + mWinAnimator.destroyDeferredSurfaceLocked(); + mWinAnimator.destroySurfaceLocked(); mSession.windowRemovedLocked(); try { mClient.asBinder().unlinkToDeath(mDeathRecipient, 0); @@ -1553,7 +814,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { try { synchronized(mService.mWindowMap) { WindowState win = mService.windowForClientLocked(mSession, mClient, false); - Slog.i(WindowManagerService.TAG, "WIN DEATH: " + win); + Slog.i(TAG, "WIN DEATH: " + win); if (win != null) { mService.removeWindowLocked(mSession, win); } @@ -1572,25 +833,28 @@ final class WindowState implements WindowManagerPolicy.WindowState { && ((mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) == 0); } + @Override public boolean hasDrawnLw() { - return mHasDrawn; + return mWinAnimator.mDrawState == WindowStateAnimator.HAS_DRAWN; } + @Override public boolean showLw(boolean doAnimation) { return showLw(doAnimation, true); } boolean showLw(boolean doAnimation, boolean requestAnim) { if (mPolicyVisibility && mPolicyVisibilityAfterAnim) { + // Already showing. return false; } - if (DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "Policy visibility true: " + this); + if (DEBUG_VISIBILITY) Slog.v(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()) { + if (DEBUG_VISIBILITY) Slog.v(TAG, "doAnimation: mPolicyVisibility=" + + 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. @@ -1600,7 +864,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { mPolicyVisibility = true; mPolicyVisibilityAfterAnim = true; if (doAnimation) { - mService.applyAnimationLocked(this, WindowManagerPolicy.TRANSIT_ENTER, true); + mWinAnimator.applyAnimationLocked(WindowManagerPolicy.TRANSIT_ENTER, true); } if (requestAnim) { mService.scheduleAnimationLocked(); @@ -1608,31 +872,33 @@ final class WindowState implements WindowManagerPolicy.WindowState { return true; } + @Override public boolean hideLw(boolean doAnimation) { return hideLw(doAnimation, true); } boolean hideLw(boolean doAnimation, boolean requestAnim) { if (doAnimation) { - if (mService.mDisplayFrozen || !mService.mPolicy.isScreenOnFully()) { + if (!mService.okToDisplay()) { doAnimation = false; } } boolean current = doAnimation ? mPolicyVisibilityAfterAnim : mPolicyVisibility; if (!current) { + // Already hiding. return false; } if (doAnimation) { - mService.applyAnimationLocked(this, WindowManagerPolicy.TRANSIT_EXIT, false); - if (mAnimation == null) { + mWinAnimator.applyAnimationLocked(WindowManagerPolicy.TRANSIT_EXIT, false); + if (mWinAnimator.mAnimation == null) { doAnimation = false; } } if (doAnimation) { mPolicyVisibilityAfterAnim = false; } else { - if (DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "Policy visibility false: " + this); + if (DEBUG_VISIBILITY) Slog.v(TAG, "Policy visibility false: " + this); mPolicyVisibilityAfterAnim = false; mPolicyVisibility = false; // Window is no longer visible -- make sure if we were waiting @@ -1649,6 +915,11 @@ final class WindowState implements WindowManagerPolicy.WindowState { return true; } + @Override + public boolean isAlive() { + return mClient.asBinder().isBinderAlive(); + } + private static void applyInsets(Region outRegion, Rect frame, Rect inset) { outRegion.set( frame.left + inset.left, frame.top + inset.top, @@ -1684,6 +955,10 @@ final class WindowState implements WindowManagerPolicy.WindowState { pw.print(prefix); pw.print("Requested w="); pw.print(mRequestedWidth); pw.print(" h="); pw.print(mRequestedHeight); pw.print(" mLayoutSeq="); pw.println(mLayoutSeq); + if (mRequestedWidth != mLastRequestedWidth || mRequestedHeight != mLastRequestedHeight) { + pw.print(prefix); pw.print("LastRequested w="); pw.print(mLastRequestedWidth); + pw.print(" h="); pw.println(mLastRequestedHeight); + } if (mAttachedWindow != null || mLayoutAttached) { pw.print(prefix); pw.print("mAttachedWindow="); pw.print(mAttachedWindow); pw.print(" mLayoutAttached="); pw.println(mLayoutAttached); @@ -1698,26 +973,11 @@ final class WindowState implements WindowManagerPolicy.WindowState { pw.print(prefix); pw.print("mBaseLayer="); pw.print(mBaseLayer); pw.print(" mSubLayer="); pw.print(mSubLayer); pw.print(" mAnimLayer="); pw.print(mLayer); pw.print("+"); - pw.print((mTargetAppToken != null ? mTargetAppToken.animLayerAdjustment - : (mAppToken != null ? mAppToken.animLayerAdjustment : 0))); - pw.print("="); pw.print(mAnimLayer); - pw.print(" mLastLayer="); pw.println(mLastLayer); - } - if (mSurface != null) { - if (dumpAll) { - pw.print(prefix); pw.print("mSurface="); pw.println(mSurface); - } - pw.print(prefix); pw.print("Surface: shown="); pw.print(mSurfaceShown); - pw.print(" layer="); pw.print(mSurfaceLayer); - pw.print(" alpha="); pw.print(mSurfaceAlpha); - pw.print(" rect=("); pw.print(mSurfaceX); - pw.print(","); pw.print(mSurfaceY); - pw.print(") "); pw.print(mSurfaceW); - pw.print(" x "); pw.println(mSurfaceH); - } - if (mPendingDestroySurface != null) { - pw.print(prefix); pw.print("mPendingDestroySurface="); - pw.println(mPendingDestroySurface); + pw.print((mTargetAppToken != null ? + mTargetAppToken.mAppAnimator.animLayerAdjustment + : (mAppToken != null ? mAppToken.mAppAnimator.animLayerAdjustment : 0))); + pw.print("="); pw.print(mWinAnimator.mAnimLayer); + pw.print(" mLastLayer="); pw.println(mWinAnimator.mLastLayer); } if (dumpAll) { pw.print(prefix); pw.print("mToken="); pw.println(mToken); @@ -1730,7 +990,6 @@ final class WindowState implements WindowManagerPolicy.WindowState { } pw.print(prefix); pw.print("mViewVisibility=0x"); pw.print(Integer.toHexString(mViewVisibility)); - pw.print(" mLastHidden="); pw.print(mLastHidden); pw.print(" mHaveFrame="); pw.print(mHaveFrame); pw.print(" mObscured="); pw.println(mObscured); pw.print(prefix); pw.print("mSeq="); pw.print(mSeq); @@ -1748,10 +1007,6 @@ final class WindowState implements WindowManagerPolicy.WindowState { pw.print(prefix); pw.print("mRelayoutCalled="); pw.print(mRelayoutCalled); pw.print(" mLayoutNeeded="); pw.println(mLayoutNeeded); } - if (mSurfaceResized || mSurfaceDestroyDeferred) { - pw.print(prefix); pw.print("mSurfaceResized="); pw.print(mSurfaceResized); - pw.print(" mSurfaceDestroyDeferred="); pw.println(mSurfaceDestroyDeferred); - } if (mXOffset != 0 || mYOffset != 0) { pw.print(prefix); pw.print("Offsets x="); pw.print(mXOffset); pw.print(" y="); pw.println(mYOffset); @@ -1768,8 +1023,8 @@ final class WindowState implements WindowManagerPolicy.WindowState { } pw.print(prefix); pw.print("mConfiguration="); pw.println(mConfiguration); } - pw.print(prefix); pw.print("mShownFrame="); - mShownFrame.printShortString(pw); pw.println(); + pw.print(prefix); pw.print("mHasSurface="); pw.print(mHasSurface); + pw.print(" mShownFrame="); mShownFrame.printShortString(pw); pw.println(); if (dumpAll) { pw.print(prefix); pw.print("mFrame="); mFrame.printShortString(pw); pw.print(" last="); mLastFrame.printShortString(pw); @@ -1796,38 +1051,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(); - } - if (mShownAlpha != 1 || mAlpha != 1 || mLastAlpha != 1) { - pw.print(prefix); pw.print("mShownAlpha="); pw.print(mShownAlpha); - pw.print(" mAlpha="); pw.print(mAlpha); - pw.print(" mLastAlpha="); pw.println(mLastAlpha); - } - if (mHaveMatrix || mGlobalScale != 1) { - pw.print(prefix); pw.print("mGlobalScale="); pw.print(mGlobalScale); - pw.print(" mDsDx="); pw.print(mDsDx); - pw.print(" mDtDx="); pw.print(mDtDx); - pw.print(" mDsDy="); pw.print(mDsDy); - pw.print(" mDtDy="); pw.println(mDtDy); - } - if (dumpAll) { - pw.print(prefix); pw.print("mDrawPending="); pw.print(mDrawPending); - pw.print(" mCommitDrawPending="); pw.print(mCommitDrawPending); - pw.print(" mReadyToShow="); pw.print(mReadyToShow); - pw.print(" mHasDrawn="); pw.println(mHasDrawn); - } + mWinAnimator.dump(pw, prefix, dumpAll); if (mExiting || mRemoveOnExit || mDestroying || mRemoved) { pw.print(prefix); pw.print("mExiting="); pw.print(mExiting); pw.print(" mRemoveOnExit="); pw.print(mRemoveOnExit); 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..220f5e0 --- /dev/null +++ b/services/java/com/android/server/wm/WindowStateAnimator.java @@ -0,0 +1,1231 @@ +// Copyright 2012 Google Inc. All Rights Reserved. + +package com.android.server.wm; + +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; +import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; + +import static com.android.server.wm.WindowManagerService.LayoutFields.CLEAR_ORIENTATION_CHANGE_COMPLETE; + +import android.content.Context; +import android.graphics.Matrix; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.Region; +import android.os.RemoteException; +import android.util.Slog; +import android.view.Surface; +import android.view.WindowManager; +import android.view.WindowManagerPolicy; +import android.view.WindowManager.LayoutParams; +import android.view.animation.Animation; +import android.view.animation.AnimationUtils; +import android.view.animation.Transformation; + +import com.android.server.wm.WindowManagerService.H; + +import java.io.PrintWriter; + +/** + * Keep track of animations and surface operations for a single WindowState. + **/ +class WindowStateAnimator { + static final boolean DEBUG_VISIBILITY = WindowManagerService.DEBUG_VISIBILITY; + static final boolean DEBUG_ANIM = WindowManagerService.DEBUG_ANIM; + static final boolean DEBUG_LAYERS = WindowManagerService.DEBUG_LAYERS; + static final boolean DEBUG_STARTING_WINDOW = WindowManagerService.DEBUG_STARTING_WINDOW; + static final boolean SHOW_TRANSACTIONS = WindowManagerService.SHOW_TRANSACTIONS; + static final boolean SHOW_LIGHT_TRANSACTIONS = WindowManagerService.SHOW_LIGHT_TRANSACTIONS; + static final boolean SHOW_SURFACE_ALLOC = WindowManagerService.SHOW_SURFACE_ALLOC; + static final boolean localLOGV = WindowManagerService.localLOGV; + static final boolean DEBUG_ORIENTATION = WindowManagerService.DEBUG_ORIENTATION; + + static final String TAG = "WindowStateAnimator"; + + final WindowManagerService mService; + final WindowState mWin; + final WindowState mAttachedWindow; + final WindowAnimator mAnimator; + final Session mSession; + final WindowManagerPolicy mPolicy; + final Context mContext; + + // 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? + int mAnimLayer; + int mLastLayer; + + Surface mSurface; + Surface mPendingDestroySurface; + boolean mReportDestroySurface; + boolean mSurfacePendingDestroy; + + /** + * Set when we have changed the size of the surface, to know that + * we must tell them application to resize (and thus redraw itself). + */ + boolean mSurfaceResized; + + /** + * Set if the client has asked that the destroy of its surface be delayed + * until it explicitly says it is okay. + */ + boolean mSurfaceDestroyDeferred; + + float mShownAlpha = 1; + float mAlpha = 1; + float mLastAlpha = 1; + + // Used to save animation distances between the time they are calculated and when they are + // used. + int mAnimDw; + int mAnimDh; + float mDsDx=1, mDtDx=0, mDsDy=0, mDtDy=1; + float mLastDsDx=1, mLastDtDx=0, mLastDsDy=0, mLastDtDy=1; + + boolean mHaveMatrix; + + // For debugging, this is the last information given to the surface flinger. + boolean mSurfaceShown; + float mSurfaceX, mSurfaceY, mSurfaceW, mSurfaceH; + int mSurfaceLayer; + float mSurfaceAlpha; + + // Set to true if, when the window gets displayed, it should perform + // an enter animation. + boolean mEnterAnimationPending; + + /** This is set when there is no Surface */ + static final int NO_SURFACE = 0; + /** This is set after the Surface has been created but before the window has been drawn. During + * this time the surface is hidden. */ + static final int DRAW_PENDING = 1; + /** This is set after the window has finished drawing for the first time but before its surface + * is shown. The surface will be displayed when the next layout is run. */ + static final int COMMIT_DRAW_PENDING = 2; + /** This is set during the time after the window's drawing has been committed, and before its + * surface is actually shown. It is used to delay showing the surface until all windows in a + * token are ready to be shown. */ + static final int READY_TO_SHOW = 3; + /** Set when the window has been shown in the screen the first time. */ + static final int HAS_DRAWN = 4; + int mDrawState; + + /** Was this window last hidden? */ + boolean mLastHidden; + + int mAttrFlags; + int mAttrType; + + public WindowStateAnimator(final WindowManagerService service, final WindowState win, + final WindowState attachedWindow) { + mService = service; + mWin = win; + mAttachedWindow = attachedWindow; + mAnimator = mService.mAnimator; + mSession = win.mSession; + mPolicy = mService.mPolicy; + mContext = mService.mContext; + mAttrFlags = win.mAttrs.flags; + mAttrType = win.mAttrs.type; + } + + public void setAnimation(Animation anim) { + if (localLOGV) Slog.v(TAG, "Setting animation in " + this + ": " + anim); + mAnimating = false; + mLocalAnimating = false; + mAnimation = anim; + mAnimation.restrictDuration(WindowManagerService.MAX_ANIMATION_DURATION); + mAnimation.scaleCurrentDuration(mService.mWindowAnimationScale); + // Start out animation gone if window is gone, or visible if window is visible. + mTransformation.clear(); + mTransformation.setAlpha(mLastHidden ? 0 : 1); + mHasLocalTransformation = true; + } + + public void clearAnimation() { + if (mAnimation != null) { + mAnimating = true; + mLocalAnimating = false; + mAnimation.cancel(); + mAnimation = null; + } + } + + /** 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.mAppAnimator.animation != null + || atoken.inPendingTransaction)); + } + + /** Is this window currently animating? */ + boolean isWindowAnimating() { + return mAnimation != null; + } + + void cancelExitAnimationForNextAnimationLocked() { + if (mAnimation != null) { + mAnimation.cancel(); + mAnimation = null; + destroySurfaceLocked(); + } + } + + private boolean stepAnimation(long currentTime) { + if ((mAnimation == null) || !mLocalAnimating) { + return false; + } + mTransformation.clear(); + final boolean more = mAnimation.getTransformation(currentTime, mTransformation); + if (DEBUG_ANIM) Slog.v( + 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 (DEBUG_ANIM) Slog.v( + TAG, "Starting animation in " + this + + " @ " + currentTime + ": ww=" + mWin.mFrame.width() + + " wh=" + mWin.mFrame.height() + + " dw=" + mAnimDw + " dh=" + mAnimDh + + " scale=" + mService.mWindowAnimationScale); + mAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(), + mAnimDw, mAnimDh); + mAnimation.setStartTime(currentTime); + mLocalAnimating = true; + mAnimating = true; + } + if ((mAnimation != null) && mLocalAnimating) { + if (stepAnimation(currentTime)) { + return true; + } + } + if (DEBUG_ANIM) Slog.v( + TAG, "Finished animation in " + this + + " @ " + currentTime); + //WindowManagerService.this.dump(); + } + mHasLocalTransformation = false; + if ((!mLocalAnimating || mAnimationIsEntrance) && mWin.mAppToken != null + && mWin.mAppToken.mAppAnimator.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; + } + + // Done animating, clean up. + if (DEBUG_ANIM) Slog.v( + 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 (mAnimator.mWindowDetachedWallpaper == mWin) { + mAnimator.mWindowDetachedWallpaper = null; + } + mAnimLayer = mWin.mLayer; + if (mWin.mIsImWindow) { + mAnimLayer += mService.mInputMethodAnimLayerAdjustment; + } else if (mWin.mIsWallpaper) { + mAnimLayer += mService.mWallpaperAnimLayerAdjustment; + } + if (DEBUG_LAYERS) Slog.v(TAG, "Stepping win " + this + + " anim layer: " + mAnimLayer); + mHasTransformation = false; + mHasLocalTransformation = false; + if (mWin.mPolicyVisibility != mWin.mPolicyVisibilityAfterAnim) { + if (WindowState.DEBUG_VISIBILITY) { + Slog.v(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 (mDrawState == HAS_DRAWN + && mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING + && mWin.mAppToken != null + && mWin.mAppToken.firstWindowDrawn + && mWin.mAppToken.startingData != null) { + if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Finish starting " + + mWin.mToken + ": first real window done animating"); + mService.mFinishedStarting.add(mWin.mAppToken); + mService.mH.sendEmptyMessage(H.FINISHED_STARTING); + } + + finishExit(); + mAnimator.mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM; + if (WindowManagerService.DEBUG_LAYOUT_REPEATS) mService.debugLayoutRepeats( + "WindowStateAnimator", mAnimator.mPendingLayoutChanges); + + if (mWin.mAppToken != null) { + mWin.mAppToken.updateReportedVisibilityLocked(); + } + + return false; + } + + void finishExit() { + if (WindowManagerService.DEBUG_ANIM) Slog.v( + 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( + TAG, "Exit animation finished in " + this + + ": remove=" + mWin.mRemoveOnExit); + if (mSurface != null) { + mService.mDestroySurface.add(mWin); + mWin.mDestroying = true; + if (WindowState.SHOW_TRANSACTIONS) WindowManagerService.logSurface( + mWin, "HIDE (finishExit)", null); + mSurfaceShown = false; + try { + mSurface.hide(); + } catch (RuntimeException e) { + Slog.w(TAG, "Error hiding surface in " + this, e); + } + mLastHidden = true; + } + mWin.mExiting = false; + if (mWin.mRemoveOnExit) { + mService.mPendingRemove.add(mWin); + mWin.mRemoveOnExit = false; + } + } + + boolean finishDrawingLocked() { + if (mDrawState == DRAW_PENDING) { + if (SHOW_TRANSACTIONS || DEBUG_ORIENTATION) Slog.v( + TAG, "finishDrawingLocked: " + this + " in " + mSurface); + mDrawState = COMMIT_DRAW_PENDING; + return true; + } + return false; + } + + // This must be called while inside a transaction. + boolean commitFinishDrawingLocked(long currentTime) { + //Slog.i(TAG, "commitFinishDrawingLocked: " + mSurface); + if (mDrawState != COMMIT_DRAW_PENDING) { + return false; + } + mDrawState = READY_TO_SHOW; + final boolean starting = mWin.mAttrs.type == TYPE_APPLICATION_STARTING; + final AppWindowToken atoken = mWin.mAppToken; + if (atoken == null || atoken.allDrawn || starting) { + performShowLocked(); + } + return true; + } + + Surface createSurfaceLocked() { + if (mSurface == null) { + mReportDestroySurface = false; + mSurfacePendingDestroy = false; + if (DEBUG_ORIENTATION) Slog.i(TAG, + "createSurface " + this + ": DRAW NOW PENDING"); + mDrawState = DRAW_PENDING; + if (mWin.mAppToken != null) { + mWin.mAppToken.allDrawn = false; + } + + mService.makeWindowFreezingScreenIfNeededLocked(mWin); + + int flags = 0; + final WindowManager.LayoutParams attrs = mWin.mAttrs; + + if ((attrs.flags&WindowManager.LayoutParams.FLAG_SECURE) != 0) { + flags |= Surface.SECURE; + } + if (WindowState.DEBUG_VISIBILITY) Slog.v( + TAG, "Creating surface in session " + + mSession.mSurfaceSession + " window " + this + + " w=" + mWin.mCompatFrame.width() + + " h=" + mWin.mCompatFrame.height() + " format=" + + attrs.format + " flags=" + flags); + + int w = mWin.mCompatFrame.width(); + int h = mWin.mCompatFrame.height(); + if ((attrs.flags & LayoutParams.FLAG_SCALED) != 0) { + // for a scaled surface, we always want the requested + // size. + w = mWin.mRequestedWidth; + h = mWin.mRequestedHeight; + } + + // Something is wrong and SurfaceFlinger will not like this, + // try to revert to sane values + if (w <= 0) w = 1; + if (h <= 0) h = 1; + + mSurfaceShown = false; + mSurfaceLayer = 0; + mSurfaceAlpha = 1; + mSurfaceX = 0; + mSurfaceY = 0; + mSurfaceW = w; + mSurfaceH = h; + try { + final boolean isHwAccelerated = (attrs.flags & + WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0; + final int format = isHwAccelerated ? PixelFormat.TRANSLUCENT : attrs.format; + if (!PixelFormat.formatHasAlpha(attrs.format)) { + flags |= Surface.OPAQUE; + } + mSurface = new Surface( + mSession.mSurfaceSession, mSession.mPid, + attrs.getTitle().toString(), + 0, w, h, format, flags); + mWin.mHasSurface = true; + mAnimator.mWinAnimators.add(this); + if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(TAG, + " CREATE SURFACE " + + mSurface + " IN SESSION " + + mSession.mSurfaceSession + + ": pid=" + mSession.mPid + " format=" + + attrs.format + " flags=0x" + + Integer.toHexString(flags) + + " / " + this); + } catch (Surface.OutOfResourcesException e) { + mWin.mHasSurface = false; + mAnimator.mWinAnimators.remove(this); + Slog.w(TAG, "OutOfResourcesException creating surface"); + mService.reclaimSomeSurfaceMemoryLocked(this, "create", true); + mDrawState = NO_SURFACE; + return null; + } catch (Exception e) { + mWin.mHasSurface = false; + mAnimator.mWinAnimators.remove(this); + Slog.e(TAG, "Exception creating surface", e); + mDrawState = NO_SURFACE; + return null; + } + + if (WindowManagerService.localLOGV) Slog.v( + TAG, "Got surface: " + mSurface + + ", set left=" + mWin.mFrame.left + " top=" + mWin.mFrame.top + + ", animLayer=" + mAnimLayer); + if (SHOW_LIGHT_TRANSACTIONS) { + Slog.i(TAG, ">>> OPEN TRANSACTION createSurfaceLocked"); + WindowManagerService.logSurface(mWin, "CREATE pos=(" + + mWin.mFrame.left + "," + mWin.mFrame.top + ") (" + + mWin.mCompatFrame.width() + "x" + mWin.mCompatFrame.height() + + "), layer=" + mAnimLayer + " HIDE", null); + } + Surface.openTransaction(); + try { + try { + mSurfaceX = mWin.mFrame.left + mWin.mXOffset; + mSurfaceY = mWin.mFrame.top + mWin.mYOffset; + mSurface.setPosition(mSurfaceX, mSurfaceY); + mSurfaceLayer = mAnimLayer; + mSurface.setLayer(mAnimLayer); + mSurfaceShown = false; + mSurface.hide(); + if ((mWin.mAttrs.flags&WindowManager.LayoutParams.FLAG_DITHER) != 0) { + if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(mWin, "DITHER", null); + mSurface.setFlags(Surface.SURFACE_DITHER, Surface.SURFACE_DITHER); + } + } catch (RuntimeException e) { + Slog.w(TAG, "Error creating surface in " + w, e); + mService.reclaimSomeSurfaceMemoryLocked(this, "create-init", true); + } + mLastHidden = true; + } finally { + Surface.closeTransaction(); + if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, + "<<< CLOSE TRANSACTION createSurfaceLocked"); + } + if (WindowManagerService.localLOGV) Slog.v( + TAG, "Created surface " + this); + } + return mSurface; + } + + void destroySurfaceLocked() { + if (mWin.mAppToken != null && mWin == mWin.mAppToken.startingWindow) { + mWin.mAppToken.startingDisplayed = false; + } + + mDrawState = NO_SURFACE; + if (mSurface != null) { + + int i = mWin.mChildWindows.size(); + while (i > 0) { + i--; + WindowState c = mWin.mChildWindows.get(i); + c.mAttachedHidden = true; + } + + if (mReportDestroySurface) { + mReportDestroySurface = false; + mSurfacePendingDestroy = true; + try { + mWin.mClient.dispatchGetNewSurface(); + // We'll really destroy on the next time around. + return; + } catch (RemoteException e) { + } + } + + try { + if (DEBUG_VISIBILITY) { + RuntimeException e = null; + if (!WindowManagerService.HIDE_STACK_CRAWLS) { + e = new RuntimeException(); + e.fillInStackTrace(); + } + Slog.w(TAG, "Window " + this + " destroying surface " + + mSurface + ", session " + mSession, e); + } + if (mSurfaceDestroyDeferred) { + if (mSurface != null && mPendingDestroySurface != mSurface) { + if (mPendingDestroySurface != null) { + if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) { + RuntimeException e = null; + if (!WindowManagerService.HIDE_STACK_CRAWLS) { + e = new RuntimeException(); + e.fillInStackTrace(); + } + WindowManagerService.logSurface(mWin, "DESTROY PENDING", e); + } + mPendingDestroySurface.destroy(); + } + mPendingDestroySurface = mSurface; + } + } else { + if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) { + RuntimeException e = null; + if (!WindowManagerService.HIDE_STACK_CRAWLS) { + e = new RuntimeException(); + e.fillInStackTrace(); + } + WindowManagerService.logSurface(mWin, "DESTROY", e); + } + mSurface.destroy(); + } + } catch (RuntimeException e) { + Slog.w(TAG, "Exception thrown when destroying Window " + this + + " surface " + mSurface + " session " + mSession + + ": " + e.toString()); + } + + mSurfaceShown = false; + mSurface = null; + mWin.mHasSurface =false; + mAnimator.mWinAnimators.remove(this); + } + } + + void destroyDeferredSurfaceLocked() { + try { + if (mPendingDestroySurface != null) { + if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) { + RuntimeException e = null; + if (!WindowManagerService.HIDE_STACK_CRAWLS) { + e = new RuntimeException(); + e.fillInStackTrace(); + } + WindowManagerService.logSurface(mWin, "DESTROY PENDING", e); + } + mPendingDestroySurface.destroy(); + } + } catch (RuntimeException e) { + Slog.w(TAG, "Exception thrown when destroying Window " + + this + " surface " + mPendingDestroySurface + + " session " + mSession + ": " + e.toString()); + } + mSurfaceDestroyDeferred = false; + mPendingDestroySurface = null; + } + + void computeShownFrameLocked() { + final boolean selfTransformation = mHasLocalTransformation; + Transformation attachedTransformation = + (mAttachedWindow != null && mAttachedWindow.mWinAnimator.mHasLocalTransformation) + ? mAttachedWindow.mWinAnimator.mTransformation : null; + final AppWindowAnimator appAnimator = + mWin.mAppToken == null ? null : mWin.mAppToken.mAppAnimator; + Transformation appTransformation = (appAnimator != null && appAnimator.hasTransformation) + ? appAnimator.transformation : null; + + // Wallpapers are animated based on the "real" window they + // are currently targeting. + if (mWin.mAttrs.type == TYPE_WALLPAPER && mService.mLowerWallpaperTarget == null + && mService.mWallpaperTarget != null) { + 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(TAG, "WP target attached xform: " + attachedTransformation); + } + } + final AppWindowAnimator wpAppAnimator = mService.mWallpaperTarget.mAppToken == null + ? null : mService.mWallpaperTarget.mAppToken.mAppAnimator; + if (wpAppAnimator != null && + wpAppAnimator.hasTransformation && + wpAppAnimator.animation != null && + !wpAppAnimator.animation.getDetachWallpaper()) { + appTransformation = wpAppAnimator.transformation; + if (WindowManagerService.DEBUG_WALLPAPER && appTransformation != null) { + Slog.v(TAG, "WP target app xform: " + appTransformation); + } + } + } + + final boolean screenAnimation = mService.mAnimator.mScreenRotationAnimation != null + && mService.mAnimator.mScreenRotationAnimation.isAnimating(); + if (selfTransformation || attachedTransformation != null + || appTransformation != null || screenAnimation) { + // cache often used attributes locally + final Rect frame = mWin.mFrame; + final float tmpFloats[] = mService.mTmpFloats; + final Matrix tmpMatrix = mWin.mTmpMatrix; + + // Compute the desired transformation. + if (screenAnimation) { + // If we are doing a screen animation, the global rotation + // applied to windows can result in windows that are carefully + // aligned with each other to slightly separate, allowing you + // to see what is behind them. An unsightly mess. This... + // thing... magically makes it call good: scale each window + // slightly (two pixels larger in each dimension, from the + // window's center). + final float w = frame.width(); + final float h = frame.height(); + if (w>=1 && h>=1) { + tmpMatrix.setScale(1 + 2/w, 1 + 2/h, w/2, h/2); + } else { + tmpMatrix.reset(); + } + } else { + tmpMatrix.reset(); + } + tmpMatrix.postScale(mWin.mGlobalScale, mWin.mGlobalScale); + if (selfTransformation) { + tmpMatrix.postConcat(mTransformation.getMatrix()); + } + tmpMatrix.postTranslate(frame.left + mWin.mXOffset, frame.top + mWin.mYOffset); + if (attachedTransformation != null) { + tmpMatrix.postConcat(attachedTransformation.getMatrix()); + } + if (appTransformation != null) { + tmpMatrix.postConcat(appTransformation.getMatrix()); + } + if (screenAnimation) { + tmpMatrix.postConcat( + mService.mAnimator.mScreenRotationAnimation.getEnterTransformation().getMatrix()); + } + + // "convert" it into SurfaceFlinger's format + // (a 2x2 matrix + an offset) + // Here we must not transform the position of the surface + // since it is already included in the transformation. + //Slog.i(TAG, "Transform: " + matrix); + + mHaveMatrix = true; + tmpMatrix.getValues(tmpFloats); + mDsDx = tmpFloats[Matrix.MSCALE_X]; + mDtDx = tmpFloats[Matrix.MSKEW_Y]; + mDsDy = tmpFloats[Matrix.MSKEW_X]; + mDtDy = tmpFloats[Matrix.MSCALE_Y]; + float x = tmpFloats[Matrix.MTRANS_X]; + float y = tmpFloats[Matrix.MTRANS_Y]; + int w = frame.width(); + int h = frame.height(); + mWin.mShownFrame.set(x, y, x+w, y+h); + + // Now set the alpha... but because our current hardware + // can't do alpha transformation on a non-opaque surface, + // turn it off if we are running an animation that is also + // transforming since it is more important to have that + // animation be smooth. + mShownAlpha = mAlpha; + if (!mService.mLimitedAlphaCompositing + || (!PixelFormat.formatHasAlpha(mWin.mAttrs.format) + || (mWin.isIdentityMatrix(mDsDx, mDtDx, mDsDy, mDtDy) + && x == frame.left && y == frame.top))) { + //Slog.i(TAG, "Applying alpha transform"); + if (selfTransformation) { + mShownAlpha *= mTransformation.getAlpha(); + } + if (attachedTransformation != null) { + mShownAlpha *= attachedTransformation.getAlpha(); + } + if (appTransformation != null) { + mShownAlpha *= appTransformation.getAlpha(); + } + if (screenAnimation) { + mShownAlpha *= + mService.mAnimator.mScreenRotationAnimation.getEnterTransformation().getAlpha(); + } + } else { + //Slog.i(TAG, "Not applying alpha transform"); + } + + if (WindowManagerService.localLOGV) Slog.v( + TAG, "computeShownFrameLocked: Animating " + this + + ": " + mWin.mShownFrame + + ", alpha=" + mTransformation.getAlpha() + ", mShownAlpha=" + mShownAlpha); + return; + } + + if (WindowManagerService.localLOGV) Slog.v( + TAG, "computeShownFrameLocked: " + this + + " not attached, mAlpha=" + mAlpha); + mWin.mShownFrame.set(mWin.mFrame); + if (mWin.mXOffset != 0 || mWin.mYOffset != 0) { + mWin.mShownFrame.offset(mWin.mXOffset, mWin.mYOffset); + } + mShownAlpha = mAlpha; + mHaveMatrix = false; + mDsDx = mWin.mGlobalScale; + mDtDx = 0; + mDsDy = 0; + mDtDy = mWin.mGlobalScale; + } + + public void prepareSurfaceLocked(final boolean recoveringMemory) { + final WindowState w = mWin; + if (mSurface == null) { + if (w.mOrientationChanging) { + if (DEBUG_ORIENTATION) { + Slog.v(TAG, "Orientation change skips hidden " + w); + } + w.mOrientationChanging = false; + } + return; + } + + boolean displayed = false; + + 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 = mSurfaceW != width || mSurfaceH != height; + if (surfaceResized) { + mSurfaceW = width; + mSurfaceH = height; + } + + if (mSurfaceX != w.mShownFrame.left + || mSurfaceY != w.mShownFrame.top) { + try { + if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w, + "POS " + w.mShownFrame.left + + ", " + w.mShownFrame.top, null); + mSurfaceX = w.mShownFrame.left; + mSurfaceY = w.mShownFrame.top; + 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(this, "position", true); + } + } + } + + if (surfaceResized) { + try { + if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w, + "SIZE " + width + "x" + height, null); + mSurfaceResized = true; + 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(this, "size", true); + } + } + } + + if (w.mAttachedHidden || !w.isReadyForDisplay()) { + if (!mLastHidden) { + //dump(); + mLastHidden = true; + if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w, + "HIDE (performLayout)", null); + if (mSurface != null) { + mSurfaceShown = false; + try { + 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 (mLastLayer != mAnimLayer + || mLastAlpha != mShownAlpha + || mLastDsDx != mDsDx + || mLastDtDx != mDtDx + || mLastDsDy != mDsDy + || mLastDtDy != mDtDy + || w.mLastHScale != w.mHScale + || w.mLastVScale != w.mVScale + || mLastHidden) { + displayed = true; + mLastAlpha = mShownAlpha; + mLastLayer = mAnimLayer; + mLastDsDx = mDsDx; + mLastDtDx = mDtDx; + mLastDsDy = mDsDy; + mLastDtDy = mDtDy; + w.mLastHScale = w.mHScale; + w.mLastVScale = w.mVScale; + if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w, + "alpha=" + mShownAlpha + " layer=" + mAnimLayer + + " matrix=[" + (mDsDx*w.mHScale) + + "," + (mDtDx*w.mVScale) + + "][" + (mDsDy*w.mHScale) + + "," + (mDtDy*w.mVScale) + "]", null); + if (mSurface != null) { + try { + mSurfaceAlpha = mShownAlpha; + mSurface.setAlpha(mShownAlpha); + mSurfaceLayer = w.mWinAnimator.mAnimLayer; + mSurface.setLayer(w.mWinAnimator.mAnimLayer); + mSurface.setMatrix( + mDsDx*w.mHScale, mDtDx*w.mVScale, + mDsDy*w.mHScale, mDtDy*w.mVScale); + + if (mLastHidden && mDrawState == HAS_DRAWN) { + if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w, + "SHOW (performLayout)", null); + if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + w + + " during relayout"); + if (showSurfaceRobustlyLocked()) { + mLastHidden = false; + } else { + w.mOrientationChanging = false; + } + } + if (mSurface != null) { + w.mToken.hasVisible = true; + } + } catch (RuntimeException e) { + Slog.w(TAG, "Error updating surface in " + w, e); + if (!recoveringMemory) { + mService.reclaimSomeSurfaceMemoryLocked(this, "update", true); + } + } + } + } else { + displayed = true; + } + + if (displayed) { + if (w.mOrientationChanging) { + if (!w.isDrawnLw()) { + mAnimator.mBulkUpdateParams |= CLEAR_ORIENTATION_CHANGE_COMPLETE; + 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; + } + } + + void setTransparentRegionHint(final Region region) { + if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, + ">>> OPEN TRANSACTION setTransparentRegion"); + Surface.openTransaction(); + try { + if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(mWin, + "transparentRegionHint=" + region, null); + mSurface.setTransparentRegionHint(region); + } finally { + Surface.closeTransaction(); + if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, + "<<< CLOSE TRANSACTION setTransparentRegion"); + } + } + + void setWallpaperOffset(int left, int top) { + Surface.openTransaction(); + try { + mSurfaceX = left; + mSurfaceY = top; + mSurface.setPosition(left, top); + } catch (RuntimeException e) { + Slog.w(TAG, "Error positioning surface of " + mWin + + " pos=(" + left + "," + top + ")", e); + } + Surface.closeTransaction(); + } + + // This must be called while inside a transaction. + boolean performShowLocked() { + if (DEBUG_VISIBILITY) { + RuntimeException e = null; + if (!WindowManagerService.HIDE_STACK_CRAWLS) { + e = new RuntimeException(); + e.fillInStackTrace(); + } + Slog.v(TAG, "performShow on " + this + + ": mDrawState=" + mDrawState + " readyForDisplay=" + + mWin.isReadyForDisplay() + + " starting=" + (mWin.mAttrs.type == TYPE_APPLICATION_STARTING), e); + } + if (mDrawState == READY_TO_SHOW && mWin.isReadyForDisplay()) { + if (SHOW_TRANSACTIONS || DEBUG_ORIENTATION) + WindowManagerService.logSurface(mWin, "SHOW (performShowLocked)", null); + if (DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + this + + " during animation: policyVis=" + mWin.mPolicyVisibility + + " attHidden=" + mWin.mAttachedHidden + + " tok.hiddenRequested=" + + (mWin.mAppToken != null ? mWin.mAppToken.hiddenRequested : false) + + " tok.hidden=" + + (mWin.mAppToken != null ? mWin.mAppToken.hidden : false) + + " animating=" + mAnimating + + " tok animating=" + + (mWin.mAppToken != null ? mWin.mAppToken.mAppAnimator.animating : false)); + if (!showSurfaceRobustlyLocked()) { + return false; + } + + mService.enableScreenIfNeededLocked(); + + applyEnterAnimationLocked(); + + mLastAlpha = -1; + mLastHidden = false; + mDrawState = HAS_DRAWN; + + int i = mWin.mChildWindows.size(); + while (i > 0) { + i--; + WindowState c = mWin.mChildWindows.get(i); + if (c.mAttachedHidden) { + c.mAttachedHidden = false; + if (c.mWinAnimator.mSurface != null) { + c.mWinAnimator.performShowLocked(); + // It hadn't been shown, which means layout not + // performed on it, so now we want to make sure to + // do a layout. If called from within the transaction + // loop, this will cause it to restart with a new + // layout. + mService.mLayoutNeeded = true; + } + } + } + + if (mWin.mAttrs.type != TYPE_APPLICATION_STARTING + && mWin.mAppToken != null) { + mWin.mAppToken.firstWindowDrawn = true; + + if (mWin.mAppToken.startingData != null) { + if (WindowManagerService.DEBUG_STARTING_WINDOW || + WindowManagerService.DEBUG_ANIM) Slog.v(TAG, + "Finish starting " + mWin.mToken + + ": first real window is shown, no animation"); + // If this initial window is animating, stop it -- we + // 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; + // Make sure we clean up the animation. + mAnimating = true; + } + mService.mFinishedStarting.add(mWin.mAppToken); + mService.mH.sendEmptyMessage(H.FINISHED_STARTING); + } + mWin.mAppToken.updateReportedVisibilityLocked(); + } + + return true; + } + + return false; + } + + /** + * Have the surface flinger show a surface, robustly dealing with + * error conditions. In particular, if there is not enough memory + * to show the surface, then we will try to get rid of other surfaces + * in order to succeed. + * + * @return Returns true if the surface was successfully shown. + */ + boolean showSurfaceRobustlyLocked() { + try { + if (mSurface != null) { + mSurfaceShown = true; + mSurface.show(); + if (mWin.mTurnOnScreen) { + if (DEBUG_VISIBILITY) Slog.v(TAG, + "Show surface turning screen on: " + mWin); + mWin.mTurnOnScreen = false; + mService.mTurnOnScreen = true; + } + } + return true; + } catch (RuntimeException e) { + Slog.w(TAG, "Failure showing surface " + mSurface + " in " + mWin, e); + } + + mService.reclaimSomeSurfaceMemoryLocked(this, "show", true); + + return false; + } + + void applyEnterAnimationLocked() { + final int transit; + if (mEnterAnimationPending) { + mEnterAnimationPending = false; + transit = WindowManagerPolicy.TRANSIT_ENTER; + } else { + transit = WindowManagerPolicy.TRANSIT_SHOW; + } + + applyAnimationLocked(transit, true); + } + + // TODO(cmautner): Move back to WindowState? + /** + * Choose the correct animation and set it to the passed WindowState. + * @param transit If WindowManagerPolicy.TRANSIT_PREVIEW_DONE and the app window has been drawn + * then the animation will be app_starting_exit. Any other value loads the animation from + * the switch statement below. + * @param isEntrance The animation type the last time this was called. Used to keep from + * loading the same animation twice. + * @return true if an animation has been loaded. + */ + boolean applyAnimationLocked(int transit, boolean isEntrance) { + if (mLocalAnimating && 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; + } + + // 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 (mService.okToDisplay()) { + int anim = mPolicy.selectAnimationLw(mWin, transit); + int attr = -1; + Animation a = null; + if (anim != 0) { + a = AnimationUtils.loadAnimation(mContext, anim); + } else { + switch (transit) { + case WindowManagerPolicy.TRANSIT_ENTER: + attr = com.android.internal.R.styleable.WindowAnimation_windowEnterAnimation; + break; + case WindowManagerPolicy.TRANSIT_EXIT: + attr = com.android.internal.R.styleable.WindowAnimation_windowExitAnimation; + break; + case WindowManagerPolicy.TRANSIT_SHOW: + attr = com.android.internal.R.styleable.WindowAnimation_windowShowAnimation; + break; + case WindowManagerPolicy.TRANSIT_HIDE: + attr = com.android.internal.R.styleable.WindowAnimation_windowHideAnimation; + break; + } + if (attr >= 0) { + a = mService.loadAnimation(mWin.mAttrs, attr); + } + } + if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG, + "applyAnimation: win=" + this + + " anim=" + anim + " attr=0x" + Integer.toHexString(attr) + + " mAnimation=" + mAnimation + + " isEntrance=" + isEntrance); + if (a != null) { + if (WindowManagerService.DEBUG_ANIM) { + RuntimeException e = null; + if (!WindowManagerService.HIDE_STACK_CRAWLS) { + e = new RuntimeException(); + e.fillInStackTrace(); + } + Slog.v(TAG, "Loaded animation " + a + " for " + this, e); + } + setAnimation(a); + mAnimationIsEntrance = isEntrance; + } + } else { + clearAnimation(); + } + + return mAnimation != null; + } + + 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(); + } + if (mSurface != null) { + if (dumpAll) { + pw.print(prefix); pw.print("mSurface="); pw.println(mSurface); + pw.print(prefix); pw.print("mDrawState="); pw.print(mDrawState); + pw.print(" mLastHidden="); pw.println(mLastHidden); + } + pw.print(prefix); pw.print("Surface: shown="); pw.print(mSurfaceShown); + pw.print(" layer="); pw.print(mSurfaceLayer); + pw.print(" alpha="); pw.print(mSurfaceAlpha); + pw.print(" rect=("); pw.print(mSurfaceX); + pw.print(","); pw.print(mSurfaceY); + pw.print(") "); pw.print(mSurfaceW); + pw.print(" x "); pw.println(mSurfaceH); + } + if (mPendingDestroySurface != null) { + pw.print(prefix); pw.print("mPendingDestroySurface="); + pw.println(mPendingDestroySurface); + } + if (mSurfaceResized || mSurfaceDestroyDeferred) { + pw.print(prefix); pw.print("mSurfaceResized="); pw.print(mSurfaceResized); + pw.print(" mSurfaceDestroyDeferred="); pw.println(mSurfaceDestroyDeferred); + } + if (mShownAlpha != 1 || mAlpha != 1 || mLastAlpha != 1) { + pw.print(prefix); pw.print("mShownAlpha="); pw.print(mShownAlpha); + pw.print(" mAlpha="); pw.print(mAlpha); + pw.print(" mLastAlpha="); pw.println(mLastAlpha); + } + if (mHaveMatrix || mWin.mGlobalScale != 1) { + pw.print(prefix); pw.print("mGlobalScale="); pw.print(mWin.mGlobalScale); + pw.print(" mDsDx="); pw.print(mDsDx); + pw.print(" mDtDx="); pw.print(mDtDx); + pw.print(" mDsDy="); pw.print(mDsDy); + pw.print(" mDtDy="); pw.println(mDtDy); + } + } + + @Override + public String toString() { + StringBuffer sb = new StringBuffer("WindowStateAnimator ("); + sb.append(mWin.mLastTitle + "): "); + sb.append("mSurface " + mSurface); + sb.append(", mAnimation " + mAnimation); + return sb.toString(); + } +} |
