diff options
Diffstat (limited to 'com/android/server')
116 files changed, 3524 insertions, 4674 deletions
diff --git a/com/android/server/AppOpsService.java b/com/android/server/AppOpsService.java index 4ffa5f1f..50b8df2a 100644 --- a/com/android/server/AppOpsService.java +++ b/com/android/server/AppOpsService.java @@ -491,8 +491,7 @@ public class AppOpsService extends IAppOpsService.Stub { return Collections.emptyList(); } synchronized (this) { - Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* edit */, - false /* uidMismatchExpected */); + Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false); if (pkgOps == null) { return null; } @@ -531,8 +530,7 @@ public class AppOpsService extends IAppOpsService.Stub { private void pruneOp(Op op, int uid, String packageName) { if (op.time == 0 && op.rejectTime == 0) { - Ops ops = getOpsRawLocked(uid, packageName, false /* edit */, - false /* uidMismatchExpected */); + Ops ops = getOpsRawLocked(uid, packageName, false); if (ops != null) { ops.remove(op.op); if (ops.size() <= 0) { @@ -1048,9 +1046,7 @@ public class AppOpsService extends IAppOpsService.Stub { public int checkPackage(int uid, String packageName) { Preconditions.checkNotNull(packageName); synchronized (this) { - Ops ops = getOpsRawLocked(uid, packageName, true /* edit */, - true /* uidMismatchExpected */); - if (ops != null) { + if (getOpsRawLocked(uid, packageName, true) != null) { return AppOpsManager.MODE_ALLOWED; } else { return AppOpsManager.MODE_ERRORED; @@ -1094,8 +1090,7 @@ public class AppOpsService extends IAppOpsService.Stub { private int noteOperationUnchecked(int code, int uid, String packageName, int proxyUid, String proxyPackageName) { synchronized (this) { - Ops ops = getOpsRawLocked(uid, packageName, true /* edit */, - false /* uidMismatchExpected */); + Ops ops = getOpsRawLocked(uid, packageName, true); if (ops == null) { if (DEBUG) Log.d(TAG, "noteOperation: no op for code " + code + " uid " + uid + " package " + packageName); @@ -1153,8 +1148,7 @@ public class AppOpsService extends IAppOpsService.Stub { } ClientState client = (ClientState)token; synchronized (this) { - Ops ops = getOpsRawLocked(uid, resolvedPackageName, true /* edit */, - false /* uidMismatchExpected */); + Ops ops = getOpsRawLocked(uid, resolvedPackageName, true); if (ops == null) { if (DEBUG) Log.d(TAG, "startOperation: no op for code " + code + " uid " + uid + " package " + resolvedPackageName); @@ -1280,8 +1274,7 @@ public class AppOpsService extends IAppOpsService.Stub { return uidState; } - private Ops getOpsRawLocked(int uid, String packageName, boolean edit, - boolean uidMismatchExpected) { + private Ops getOpsRawLocked(int uid, String packageName, boolean edit) { UidState uidState = getUidStateLocked(uid, edit); if (uidState == null) { return null; @@ -1333,12 +1326,10 @@ public class AppOpsService extends IAppOpsService.Stub { if (pkgUid != uid) { // Oops! The package name is not valid for the uid they are calling // under. Abort. - if (!uidMismatchExpected) { - RuntimeException ex = new RuntimeException("here"); - ex.fillInStackTrace(); - Slog.w(TAG, "Bad call: specified package " + packageName - + " under uid " + uid + " but it is really " + pkgUid, ex); - } + RuntimeException ex = new RuntimeException("here"); + ex.fillInStackTrace(); + Slog.w(TAG, "Bad call: specified package " + packageName + + " under uid " + uid + " but it is really " + pkgUid, ex); return null; } } finally { @@ -1368,8 +1359,7 @@ public class AppOpsService extends IAppOpsService.Stub { } private Op getOpLocked(int code, int uid, String packageName, boolean edit) { - Ops ops = getOpsRawLocked(uid, packageName, edit, - false /* uidMismatchExpected */); + Ops ops = getOpsRawLocked(uid, packageName, edit); if (ops == null) { return null; } @@ -1403,8 +1393,7 @@ public class AppOpsService extends IAppOpsService.Stub { if (AppOpsManager.opAllowSystemBypassRestriction(code)) { // If we are the system, bypass user restrictions for certain codes synchronized (this) { - Ops ops = getOpsRawLocked(uid, packageName, true /* edit */, - false /* uidMismatchExpected */); + Ops ops = getOpsRawLocked(uid, packageName, true); if ((ops != null) && ops.isPrivileged) { return false; } @@ -1724,8 +1713,7 @@ public class AppOpsService extends IAppOpsService.Stub { out.startTag(null, "uid"); out.attribute(null, "n", Integer.toString(pkg.getUid())); synchronized (this) { - Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(), - false /* edit */, false /* uidMismatchExpected */); + Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(), false); // Should always be present as the list of PackageOps is generated // from Ops. if (ops != null) { diff --git a/com/android/server/BatteryService.java b/com/android/server/BatteryService.java index 47be0a70..5106c8d7 100644 --- a/com/android/server/BatteryService.java +++ b/com/android/server/BatteryService.java @@ -24,7 +24,6 @@ import android.os.PowerManager; import android.os.ResultReceiver; import android.os.ShellCallback; import android.os.ShellCommand; -import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IBatteryStats; import com.android.internal.util.DumpUtils; import com.android.server.am.BatteryStatsService; @@ -36,10 +35,6 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; -import android.hidl.manager.V1_0.IServiceManager; -import android.hidl.manager.V1_0.IServiceNotification; -import android.hardware.health.V2_0.HealthInfo; -import android.hardware.health.V2_0.IHealth; import android.os.BatteryManager; import android.os.BatteryManagerInternal; import android.os.BatteryProperties; @@ -67,9 +62,6 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; -import java.util.Arrays; -import java.util.List; -import java.util.NoSuchElementException; /** * <p>BatteryService monitors the charging status, and charge level of the device @@ -126,8 +118,8 @@ public final class BatteryService extends SystemService { private final Object mLock = new Object(); - private HealthInfo mHealthInfo; - private final HealthInfo mLastHealthInfo = new HealthInfo(); + private BatteryProperties mBatteryProps; + private final BatteryProperties mLastBatteryProps = new BatteryProperties(); private boolean mBatteryLevelCritical; private int mLastBatteryStatus; private int mLastBatteryHealth; @@ -259,16 +251,16 @@ public final class BatteryService extends SystemService { private boolean isPoweredLocked(int plugTypeSet) { // assume we are powered if battery state is unknown so // the "stay on while plugged in" option will work. - if (mHealthInfo.legacy.batteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) { + if (mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) { return true; } - if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_AC) != 0 && mHealthInfo.legacy.chargerAcOnline) { + if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_AC) != 0 && mBatteryProps.chargerAcOnline) { return true; } - if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_USB) != 0 && mHealthInfo.legacy.chargerUsbOnline) { + if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_USB) != 0 && mBatteryProps.chargerUsbOnline) { return true; } - if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_WIRELESS) != 0 && mHealthInfo.legacy.chargerWirelessOnline) { + if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_WIRELESS) != 0 && mBatteryProps.chargerWirelessOnline) { return true; } return false; @@ -285,15 +277,15 @@ public final class BatteryService extends SystemService { * (becomes <= mLowBatteryWarningLevel). */ return !plugged - && mHealthInfo.legacy.batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN - && mHealthInfo.legacy.batteryLevel <= mLowBatteryWarningLevel + && mBatteryProps.batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN + && mBatteryProps.batteryLevel <= mLowBatteryWarningLevel && (oldPlugged || mLastBatteryLevel > mLowBatteryWarningLevel); } private void shutdownIfNoPowerLocked() { // shut down gracefully if our battery is critically low and we are not powered. // wait until the system has booted before attempting to display the shutdown dialog. - if (mHealthInfo.legacy.batteryLevel == 0 && !isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)) { + if (mBatteryProps.batteryLevel == 0 && !isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)) { mHandler.post(new Runnable() { @Override public void run() { @@ -314,7 +306,7 @@ public final class BatteryService extends SystemService { // shut down gracefully if temperature is too high (> 68.0C by default) // wait until the system has booted before attempting to display the // shutdown dialog. - if (mHealthInfo.legacy.batteryTemperature > mShutdownBatteryTemperature) { + if (mBatteryProps.batteryTemperature > mShutdownBatteryTemperature) { mHandler.post(new Runnable() { @Override public void run() { @@ -334,66 +326,25 @@ public final class BatteryService extends SystemService { private void update(BatteryProperties props) { synchronized (mLock) { if (!mUpdatesStopped) { - mHealthInfo = new HealthInfo(); - copy(mHealthInfo, props); + mBatteryProps = props; // Process the new values. processValuesLocked(false); } else { - copy(mLastHealthInfo, props); + mLastBatteryProps.set(props); } } } - private static void copy(HealthInfo dst, HealthInfo src) { - dst.legacy.chargerAcOnline = src.legacy.chargerAcOnline; - dst.legacy.chargerUsbOnline = src.legacy.chargerUsbOnline; - dst.legacy.chargerWirelessOnline = src.legacy.chargerWirelessOnline; - dst.legacy.maxChargingCurrent = src.legacy.maxChargingCurrent; - dst.legacy.maxChargingVoltage = src.legacy.maxChargingVoltage; - dst.legacy.batteryStatus = src.legacy.batteryStatus; - dst.legacy.batteryHealth = src.legacy.batteryHealth; - dst.legacy.batteryPresent = src.legacy.batteryPresent; - dst.legacy.batteryLevel = src.legacy.batteryLevel; - dst.legacy.batteryVoltage = src.legacy.batteryVoltage; - dst.legacy.batteryTemperature = src.legacy.batteryTemperature; - dst.legacy.batteryCurrent = src.legacy.batteryCurrent; - dst.legacy.batteryCycleCount = src.legacy.batteryCycleCount; - dst.legacy.batteryFullCharge = src.legacy.batteryFullCharge; - dst.legacy.batteryChargeCounter = src.legacy.batteryChargeCounter; - dst.legacy.batteryTechnology = src.legacy.batteryTechnology; - dst.batteryCurrentAverage = src.batteryCurrentAverage; - dst.batteryCapacity = src.batteryCapacity; - dst.energyCounter = src.energyCounter; - } - - // TODO(b/62229583): remove this function when BatteryProperties are completely replaced. - private static void copy(HealthInfo dst, BatteryProperties src) { - dst.legacy.chargerAcOnline = src.chargerAcOnline; - dst.legacy.chargerUsbOnline = src.chargerUsbOnline; - dst.legacy.chargerWirelessOnline = src.chargerWirelessOnline; - dst.legacy.maxChargingCurrent = src.maxChargingCurrent; - dst.legacy.maxChargingVoltage = src.maxChargingVoltage; - dst.legacy.batteryStatus = src.batteryStatus; - dst.legacy.batteryHealth = src.batteryHealth; - dst.legacy.batteryPresent = src.batteryPresent; - dst.legacy.batteryLevel = src.batteryLevel; - dst.legacy.batteryVoltage = src.batteryVoltage; - dst.legacy.batteryTemperature = src.batteryTemperature; - dst.legacy.batteryFullCharge = src.batteryFullCharge; - dst.legacy.batteryChargeCounter = src.batteryChargeCounter; - dst.legacy.batteryTechnology = src.batteryTechnology; - } - private void processValuesLocked(boolean force) { boolean logOutlier = false; long dischargeDuration = 0; - mBatteryLevelCritical = (mHealthInfo.legacy.batteryLevel <= mCriticalBatteryLevel); - if (mHealthInfo.legacy.chargerAcOnline) { + mBatteryLevelCritical = (mBatteryProps.batteryLevel <= mCriticalBatteryLevel); + if (mBatteryProps.chargerAcOnline) { mPlugType = BatteryManager.BATTERY_PLUGGED_AC; - } else if (mHealthInfo.legacy.chargerUsbOnline) { + } else if (mBatteryProps.chargerUsbOnline) { mPlugType = BatteryManager.BATTERY_PLUGGED_USB; - } else if (mHealthInfo.legacy.chargerWirelessOnline) { + } else if (mBatteryProps.chargerWirelessOnline) { mPlugType = BatteryManager.BATTERY_PLUGGED_WIRELESS; } else { mPlugType = BATTERY_PLUGGED_NONE; @@ -401,17 +352,30 @@ public final class BatteryService extends SystemService { if (DEBUG) { Slog.d(TAG, "Processing new values: " - + "info=" + mHealthInfo + + "chargerAcOnline=" + mBatteryProps.chargerAcOnline + + ", chargerUsbOnline=" + mBatteryProps.chargerUsbOnline + + ", chargerWirelessOnline=" + mBatteryProps.chargerWirelessOnline + + ", maxChargingCurrent" + mBatteryProps.maxChargingCurrent + + ", maxChargingVoltage" + mBatteryProps.maxChargingVoltage + + ", batteryStatus=" + mBatteryProps.batteryStatus + + ", batteryHealth=" + mBatteryProps.batteryHealth + + ", batteryPresent=" + mBatteryProps.batteryPresent + + ", batteryLevel=" + mBatteryProps.batteryLevel + + ", batteryTechnology=" + mBatteryProps.batteryTechnology + + ", batteryVoltage=" + mBatteryProps.batteryVoltage + + ", batteryChargeCounter=" + mBatteryProps.batteryChargeCounter + + ", batteryFullCharge=" + mBatteryProps.batteryFullCharge + + ", batteryTemperature=" + mBatteryProps.batteryTemperature + ", mBatteryLevelCritical=" + mBatteryLevelCritical + ", mPlugType=" + mPlugType); } // Let the battery stats keep track of the current level. try { - mBatteryStats.setBatteryState(mHealthInfo.legacy.batteryStatus, mHealthInfo.legacy.batteryHealth, - mPlugType, mHealthInfo.legacy.batteryLevel, mHealthInfo.legacy.batteryTemperature, - mHealthInfo.legacy.batteryVoltage, mHealthInfo.legacy.batteryChargeCounter, - mHealthInfo.legacy.batteryFullCharge); + mBatteryStats.setBatteryState(mBatteryProps.batteryStatus, mBatteryProps.batteryHealth, + mPlugType, mBatteryProps.batteryLevel, mBatteryProps.batteryTemperature, + mBatteryProps.batteryVoltage, mBatteryProps.batteryChargeCounter, + mBatteryProps.batteryFullCharge); } catch (RemoteException e) { // Should never happen. } @@ -419,16 +383,16 @@ public final class BatteryService extends SystemService { shutdownIfNoPowerLocked(); shutdownIfOverTempLocked(); - if (force || (mHealthInfo.legacy.batteryStatus != mLastBatteryStatus || - mHealthInfo.legacy.batteryHealth != mLastBatteryHealth || - mHealthInfo.legacy.batteryPresent != mLastBatteryPresent || - mHealthInfo.legacy.batteryLevel != mLastBatteryLevel || + if (force || (mBatteryProps.batteryStatus != mLastBatteryStatus || + mBatteryProps.batteryHealth != mLastBatteryHealth || + mBatteryProps.batteryPresent != mLastBatteryPresent || + mBatteryProps.batteryLevel != mLastBatteryLevel || mPlugType != mLastPlugType || - mHealthInfo.legacy.batteryVoltage != mLastBatteryVoltage || - mHealthInfo.legacy.batteryTemperature != mLastBatteryTemperature || - mHealthInfo.legacy.maxChargingCurrent != mLastMaxChargingCurrent || - mHealthInfo.legacy.maxChargingVoltage != mLastMaxChargingVoltage || - mHealthInfo.legacy.batteryChargeCounter != mLastChargeCounter || + mBatteryProps.batteryVoltage != mLastBatteryVoltage || + mBatteryProps.batteryTemperature != mLastBatteryTemperature || + mBatteryProps.maxChargingCurrent != mLastMaxChargingCurrent || + mBatteryProps.maxChargingVoltage != mLastMaxChargingVoltage || + mBatteryProps.batteryChargeCounter != mLastChargeCounter || mInvalidCharger != mLastInvalidCharger)) { if (mPlugType != mLastPlugType) { @@ -437,33 +401,33 @@ public final class BatteryService extends SystemService { // There's no value in this data unless we've discharged at least once and the // battery level has changed; so don't log until it does. - if (mDischargeStartTime != 0 && mDischargeStartLevel != mHealthInfo.legacy.batteryLevel) { + if (mDischargeStartTime != 0 && mDischargeStartLevel != mBatteryProps.batteryLevel) { dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime; logOutlier = true; EventLog.writeEvent(EventLogTags.BATTERY_DISCHARGE, dischargeDuration, - mDischargeStartLevel, mHealthInfo.legacy.batteryLevel); + mDischargeStartLevel, mBatteryProps.batteryLevel); // make sure we see a discharge event before logging again mDischargeStartTime = 0; } } else if (mPlugType == BATTERY_PLUGGED_NONE) { // charging -> discharging or we just powered up mDischargeStartTime = SystemClock.elapsedRealtime(); - mDischargeStartLevel = mHealthInfo.legacy.batteryLevel; + mDischargeStartLevel = mBatteryProps.batteryLevel; } } - if (mHealthInfo.legacy.batteryStatus != mLastBatteryStatus || - mHealthInfo.legacy.batteryHealth != mLastBatteryHealth || - mHealthInfo.legacy.batteryPresent != mLastBatteryPresent || + if (mBatteryProps.batteryStatus != mLastBatteryStatus || + mBatteryProps.batteryHealth != mLastBatteryHealth || + mBatteryProps.batteryPresent != mLastBatteryPresent || mPlugType != mLastPlugType) { EventLog.writeEvent(EventLogTags.BATTERY_STATUS, - mHealthInfo.legacy.batteryStatus, mHealthInfo.legacy.batteryHealth, mHealthInfo.legacy.batteryPresent ? 1 : 0, - mPlugType, mHealthInfo.legacy.batteryTechnology); + mBatteryProps.batteryStatus, mBatteryProps.batteryHealth, mBatteryProps.batteryPresent ? 1 : 0, + mPlugType, mBatteryProps.batteryTechnology); } - if (mHealthInfo.legacy.batteryLevel != mLastBatteryLevel) { + if (mBatteryProps.batteryLevel != mLastBatteryLevel) { // Don't do this just from voltage or temperature changes, that is // too noisy. EventLog.writeEvent(EventLogTags.BATTERY_LEVEL, - mHealthInfo.legacy.batteryLevel, mHealthInfo.legacy.batteryVoltage, mHealthInfo.legacy.batteryTemperature); + mBatteryProps.batteryLevel, mBatteryProps.batteryVoltage, mBatteryProps.batteryTemperature); } if (mBatteryLevelCritical && !mLastBatteryLevelCritical && mPlugType == BATTERY_PLUGGED_NONE) { @@ -476,16 +440,16 @@ public final class BatteryService extends SystemService { if (!mBatteryLevelLow) { // Should we now switch in to low battery mode? if (mPlugType == BATTERY_PLUGGED_NONE - && mHealthInfo.legacy.batteryLevel <= mLowBatteryWarningLevel) { + && mBatteryProps.batteryLevel <= mLowBatteryWarningLevel) { mBatteryLevelLow = true; } } else { // Should we now switch out of low battery mode? if (mPlugType != BATTERY_PLUGGED_NONE) { mBatteryLevelLow = false; - } else if (mHealthInfo.legacy.batteryLevel >= mLowBatteryCloseWarningLevel) { + } else if (mBatteryProps.batteryLevel >= mLowBatteryCloseWarningLevel) { mBatteryLevelLow = false; - } else if (force && mHealthInfo.legacy.batteryLevel >= mLowBatteryWarningLevel) { + } else if (force && mBatteryProps.batteryLevel >= mLowBatteryWarningLevel) { // If being forced, the previous state doesn't matter, we will just // absolutely check to see if we are now above the warning level. mBatteryLevelLow = false; @@ -532,7 +496,7 @@ public final class BatteryService extends SystemService { } }); } else if (mSentLowBatteryBroadcast && - mHealthInfo.legacy.batteryLevel >= mLowBatteryCloseWarningLevel) { + mBatteryProps.batteryLevel >= mLowBatteryCloseWarningLevel) { mSentLowBatteryBroadcast = false; final Intent statusIntent = new Intent(Intent.ACTION_BATTERY_OKAY); statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); @@ -558,16 +522,16 @@ public final class BatteryService extends SystemService { logOutlierLocked(dischargeDuration); } - mLastBatteryStatus = mHealthInfo.legacy.batteryStatus; - mLastBatteryHealth = mHealthInfo.legacy.batteryHealth; - mLastBatteryPresent = mHealthInfo.legacy.batteryPresent; - mLastBatteryLevel = mHealthInfo.legacy.batteryLevel; + mLastBatteryStatus = mBatteryProps.batteryStatus; + mLastBatteryHealth = mBatteryProps.batteryHealth; + mLastBatteryPresent = mBatteryProps.batteryPresent; + mLastBatteryLevel = mBatteryProps.batteryLevel; mLastPlugType = mPlugType; - mLastBatteryVoltage = mHealthInfo.legacy.batteryVoltage; - mLastBatteryTemperature = mHealthInfo.legacy.batteryTemperature; - mLastMaxChargingCurrent = mHealthInfo.legacy.maxChargingCurrent; - mLastMaxChargingVoltage = mHealthInfo.legacy.maxChargingVoltage; - mLastChargeCounter = mHealthInfo.legacy.batteryChargeCounter; + mLastBatteryVoltage = mBatteryProps.batteryVoltage; + mLastBatteryTemperature = mBatteryProps.batteryTemperature; + mLastMaxChargingCurrent = mBatteryProps.maxChargingCurrent; + mLastMaxChargingVoltage = mBatteryProps.maxChargingVoltage; + mLastChargeCounter = mBatteryProps.batteryChargeCounter; mLastBatteryLevelCritical = mBatteryLevelCritical; mLastInvalidCharger = mInvalidCharger; } @@ -579,26 +543,38 @@ public final class BatteryService extends SystemService { intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_REPLACE_PENDING); - int icon = getIconLocked(mHealthInfo.legacy.batteryLevel); + int icon = getIconLocked(mBatteryProps.batteryLevel); intent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence); - intent.putExtra(BatteryManager.EXTRA_STATUS, mHealthInfo.legacy.batteryStatus); - intent.putExtra(BatteryManager.EXTRA_HEALTH, mHealthInfo.legacy.batteryHealth); - intent.putExtra(BatteryManager.EXTRA_PRESENT, mHealthInfo.legacy.batteryPresent); - intent.putExtra(BatteryManager.EXTRA_LEVEL, mHealthInfo.legacy.batteryLevel); + intent.putExtra(BatteryManager.EXTRA_STATUS, mBatteryProps.batteryStatus); + intent.putExtra(BatteryManager.EXTRA_HEALTH, mBatteryProps.batteryHealth); + intent.putExtra(BatteryManager.EXTRA_PRESENT, mBatteryProps.batteryPresent); + intent.putExtra(BatteryManager.EXTRA_LEVEL, mBatteryProps.batteryLevel); intent.putExtra(BatteryManager.EXTRA_SCALE, BATTERY_SCALE); intent.putExtra(BatteryManager.EXTRA_ICON_SMALL, icon); intent.putExtra(BatteryManager.EXTRA_PLUGGED, mPlugType); - intent.putExtra(BatteryManager.EXTRA_VOLTAGE, mHealthInfo.legacy.batteryVoltage); - intent.putExtra(BatteryManager.EXTRA_TEMPERATURE, mHealthInfo.legacy.batteryTemperature); - intent.putExtra(BatteryManager.EXTRA_TECHNOLOGY, mHealthInfo.legacy.batteryTechnology); + intent.putExtra(BatteryManager.EXTRA_VOLTAGE, mBatteryProps.batteryVoltage); + intent.putExtra(BatteryManager.EXTRA_TEMPERATURE, mBatteryProps.batteryTemperature); + intent.putExtra(BatteryManager.EXTRA_TECHNOLOGY, mBatteryProps.batteryTechnology); intent.putExtra(BatteryManager.EXTRA_INVALID_CHARGER, mInvalidCharger); - intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_CURRENT, mHealthInfo.legacy.maxChargingCurrent); - intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE, mHealthInfo.legacy.maxChargingVoltage); - intent.putExtra(BatteryManager.EXTRA_CHARGE_COUNTER, mHealthInfo.legacy.batteryChargeCounter); + intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_CURRENT, mBatteryProps.maxChargingCurrent); + intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE, mBatteryProps.maxChargingVoltage); + intent.putExtra(BatteryManager.EXTRA_CHARGE_COUNTER, mBatteryProps.batteryChargeCounter); if (DEBUG) { - Slog.d(TAG, "Sending ACTION_BATTERY_CHANGED. scale:" + BATTERY_SCALE - + ", info:" + mHealthInfo.toString()); + Slog.d(TAG, "Sending ACTION_BATTERY_CHANGED. level:" + mBatteryProps.batteryLevel + + ", scale:" + BATTERY_SCALE + ", status:" + mBatteryProps.batteryStatus + + ", health:" + mBatteryProps.batteryHealth + + ", present:" + mBatteryProps.batteryPresent + + ", voltage: " + mBatteryProps.batteryVoltage + + ", temperature: " + mBatteryProps.batteryTemperature + + ", technology: " + mBatteryProps.batteryTechnology + + ", AC powered:" + mBatteryProps.chargerAcOnline + + ", USB powered:" + mBatteryProps.chargerUsbOnline + + ", Wireless powered:" + mBatteryProps.chargerWirelessOnline + + ", icon:" + icon + ", invalid charger:" + mInvalidCharger + + ", maxChargingCurrent:" + mBatteryProps.maxChargingCurrent + + ", maxChargingVoltage:" + mBatteryProps.maxChargingVoltage + + ", chargeCounter:" + mBatteryProps.batteryChargeCounter); } mHandler.post(new Runnable() { @@ -659,14 +635,14 @@ public final class BatteryService extends SystemService { long durationThreshold = Long.parseLong(durationThresholdString); int dischargeThreshold = Integer.parseInt(dischargeThresholdString); if (duration <= durationThreshold && - mDischargeStartLevel - mHealthInfo.legacy.batteryLevel >= dischargeThreshold) { + mDischargeStartLevel - mBatteryProps.batteryLevel >= dischargeThreshold) { // If the discharge cycle is bad enough we want to know about it. logBatteryStatsLocked(); } if (DEBUG) Slog.v(TAG, "duration threshold: " + durationThreshold + " discharge threshold: " + dischargeThreshold); if (DEBUG) Slog.v(TAG, "duration: " + duration + " discharge: " + - (mDischargeStartLevel - mHealthInfo.legacy.batteryLevel)); + (mDischargeStartLevel - mBatteryProps.batteryLevel)); } catch (NumberFormatException e) { Slog.e(TAG, "Invalid DischargeThresholds GService string: " + durationThresholdString + " or " + dischargeThresholdString); @@ -675,14 +651,14 @@ public final class BatteryService extends SystemService { } private int getIconLocked(int level) { - if (mHealthInfo.legacy.batteryStatus == BatteryManager.BATTERY_STATUS_CHARGING) { + if (mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_CHARGING) { return com.android.internal.R.drawable.stat_sys_battery_charge; - } else if (mHealthInfo.legacy.batteryStatus == BatteryManager.BATTERY_STATUS_DISCHARGING) { + } else if (mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_DISCHARGING) { return com.android.internal.R.drawable.stat_sys_battery; - } else if (mHealthInfo.legacy.batteryStatus == BatteryManager.BATTERY_STATUS_NOT_CHARGING - || mHealthInfo.legacy.batteryStatus == BatteryManager.BATTERY_STATUS_FULL) { + } else if (mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_NOT_CHARGING + || mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_FULL) { if (isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY) - && mHealthInfo.legacy.batteryLevel >= 100) { + && mBatteryProps.batteryLevel >= 100) { return com.android.internal.R.drawable.stat_sys_battery_charge; } else { return com.android.internal.R.drawable.stat_sys_battery; @@ -744,11 +720,11 @@ public final class BatteryService extends SystemService { getContext().enforceCallingOrSelfPermission( android.Manifest.permission.DEVICE_POWER, null); if (!mUpdatesStopped) { - copy(mLastHealthInfo, mHealthInfo); + mLastBatteryProps.set(mBatteryProps); } - mHealthInfo.legacy.chargerAcOnline = false; - mHealthInfo.legacy.chargerUsbOnline = false; - mHealthInfo.legacy.chargerWirelessOnline = false; + mBatteryProps.chargerAcOnline = false; + mBatteryProps.chargerUsbOnline = false; + mBatteryProps.chargerWirelessOnline = false; long ident = Binder.clearCallingIdentity(); try { mUpdatesStopped = true; @@ -775,30 +751,30 @@ public final class BatteryService extends SystemService { } try { if (!mUpdatesStopped) { - copy(mLastHealthInfo, mHealthInfo); + mLastBatteryProps.set(mBatteryProps); } boolean update = true; switch (key) { case "present": - mHealthInfo.legacy.batteryPresent = Integer.parseInt(value) != 0; + mBatteryProps.batteryPresent = Integer.parseInt(value) != 0; break; case "ac": - mHealthInfo.legacy.chargerAcOnline = Integer.parseInt(value) != 0; + mBatteryProps.chargerAcOnline = Integer.parseInt(value) != 0; break; case "usb": - mHealthInfo.legacy.chargerUsbOnline = Integer.parseInt(value) != 0; + mBatteryProps.chargerUsbOnline = Integer.parseInt(value) != 0; break; case "wireless": - mHealthInfo.legacy.chargerWirelessOnline = Integer.parseInt(value) != 0; + mBatteryProps.chargerWirelessOnline = Integer.parseInt(value) != 0; break; case "status": - mHealthInfo.legacy.batteryStatus = Integer.parseInt(value); + mBatteryProps.batteryStatus = Integer.parseInt(value); break; case "level": - mHealthInfo.legacy.batteryLevel = Integer.parseInt(value); + mBatteryProps.batteryLevel = Integer.parseInt(value); break; case "temp": - mHealthInfo.legacy.batteryTemperature = Integer.parseInt(value); + mBatteryProps.batteryTemperature = Integer.parseInt(value); break; case "invalid": mInvalidCharger = Integer.parseInt(value); @@ -830,7 +806,7 @@ public final class BatteryService extends SystemService { try { if (mUpdatesStopped) { mUpdatesStopped = false; - copy(mHealthInfo, mLastHealthInfo); + mBatteryProps.set(mLastBatteryProps); processValuesFromShellLocked(pw, opts); } } finally { @@ -857,20 +833,20 @@ public final class BatteryService extends SystemService { if (mUpdatesStopped) { pw.println(" (UPDATES STOPPED -- use 'reset' to restart)"); } - pw.println(" AC powered: " + mHealthInfo.legacy.chargerAcOnline); - pw.println(" USB powered: " + mHealthInfo.legacy.chargerUsbOnline); - pw.println(" Wireless powered: " + mHealthInfo.legacy.chargerWirelessOnline); - pw.println(" Max charging current: " + mHealthInfo.legacy.maxChargingCurrent); - pw.println(" Max charging voltage: " + mHealthInfo.legacy.maxChargingVoltage); - pw.println(" Charge counter: " + mHealthInfo.legacy.batteryChargeCounter); - pw.println(" status: " + mHealthInfo.legacy.batteryStatus); - pw.println(" health: " + mHealthInfo.legacy.batteryHealth); - pw.println(" present: " + mHealthInfo.legacy.batteryPresent); - pw.println(" level: " + mHealthInfo.legacy.batteryLevel); + pw.println(" AC powered: " + mBatteryProps.chargerAcOnline); + pw.println(" USB powered: " + mBatteryProps.chargerUsbOnline); + pw.println(" Wireless powered: " + mBatteryProps.chargerWirelessOnline); + pw.println(" Max charging current: " + mBatteryProps.maxChargingCurrent); + pw.println(" Max charging voltage: " + mBatteryProps.maxChargingVoltage); + pw.println(" Charge counter: " + mBatteryProps.batteryChargeCounter); + pw.println(" status: " + mBatteryProps.batteryStatus); + pw.println(" health: " + mBatteryProps.batteryHealth); + pw.println(" present: " + mBatteryProps.batteryPresent); + pw.println(" level: " + mBatteryProps.batteryLevel); pw.println(" scale: " + BATTERY_SCALE); - pw.println(" voltage: " + mHealthInfo.legacy.batteryVoltage); - pw.println(" temperature: " + mHealthInfo.legacy.batteryTemperature); - pw.println(" technology: " + mHealthInfo.legacy.batteryTechnology); + pw.println(" voltage: " + mBatteryProps.batteryVoltage); + pw.println(" temperature: " + mBatteryProps.batteryTemperature); + pw.println(" technology: " + mBatteryProps.batteryTechnology); } else { Shell shell = new Shell(); shell.exec(mBinderService, null, fd, null, args, null, new ResultReceiver(null)); @@ -884,25 +860,25 @@ public final class BatteryService extends SystemService { synchronized (mLock) { proto.write(BatteryServiceDumpProto.ARE_UPDATES_STOPPED, mUpdatesStopped); int batteryPluggedValue = BatteryServiceDumpProto.BATTERY_PLUGGED_NONE; - if (mHealthInfo.legacy.chargerAcOnline) { + if (mBatteryProps.chargerAcOnline) { batteryPluggedValue = BatteryServiceDumpProto.BATTERY_PLUGGED_AC; - } else if (mHealthInfo.legacy.chargerUsbOnline) { + } else if (mBatteryProps.chargerUsbOnline) { batteryPluggedValue = BatteryServiceDumpProto.BATTERY_PLUGGED_USB; - } else if (mHealthInfo.legacy.chargerWirelessOnline) { + } else if (mBatteryProps.chargerWirelessOnline) { batteryPluggedValue = BatteryServiceDumpProto.BATTERY_PLUGGED_WIRELESS; } proto.write(BatteryServiceDumpProto.PLUGGED, batteryPluggedValue); - proto.write(BatteryServiceDumpProto.MAX_CHARGING_CURRENT, mHealthInfo.legacy.maxChargingCurrent); - proto.write(BatteryServiceDumpProto.MAX_CHARGING_VOLTAGE, mHealthInfo.legacy.maxChargingVoltage); - proto.write(BatteryServiceDumpProto.CHARGE_COUNTER, mHealthInfo.legacy.batteryChargeCounter); - proto.write(BatteryServiceDumpProto.STATUS, mHealthInfo.legacy.batteryStatus); - proto.write(BatteryServiceDumpProto.HEALTH, mHealthInfo.legacy.batteryHealth); - proto.write(BatteryServiceDumpProto.IS_PRESENT, mHealthInfo.legacy.batteryPresent); - proto.write(BatteryServiceDumpProto.LEVEL, mHealthInfo.legacy.batteryLevel); + proto.write(BatteryServiceDumpProto.MAX_CHARGING_CURRENT, mBatteryProps.maxChargingCurrent); + proto.write(BatteryServiceDumpProto.MAX_CHARGING_VOLTAGE, mBatteryProps.maxChargingVoltage); + proto.write(BatteryServiceDumpProto.CHARGE_COUNTER, mBatteryProps.batteryChargeCounter); + proto.write(BatteryServiceDumpProto.STATUS, mBatteryProps.batteryStatus); + proto.write(BatteryServiceDumpProto.HEALTH, mBatteryProps.batteryHealth); + proto.write(BatteryServiceDumpProto.IS_PRESENT, mBatteryProps.batteryPresent); + proto.write(BatteryServiceDumpProto.LEVEL, mBatteryProps.batteryLevel); proto.write(BatteryServiceDumpProto.SCALE, BATTERY_SCALE); - proto.write(BatteryServiceDumpProto.VOLTAGE, mHealthInfo.legacy.batteryVoltage); - proto.write(BatteryServiceDumpProto.TEMPERATURE, mHealthInfo.legacy.batteryTemperature); - proto.write(BatteryServiceDumpProto.TECHNOLOGY, mHealthInfo.legacy.batteryTechnology); + proto.write(BatteryServiceDumpProto.VOLTAGE, mBatteryProps.batteryVoltage); + proto.write(BatteryServiceDumpProto.TEMPERATURE, mBatteryProps.batteryTemperature); + proto.write(BatteryServiceDumpProto.TECHNOLOGY, mBatteryProps.batteryTechnology); } proto.flush(); } @@ -935,8 +911,8 @@ public final class BatteryService extends SystemService { * Synchronize on BatteryService. */ public void updateLightsLocked() { - final int level = mHealthInfo.legacy.batteryLevel; - final int status = mHealthInfo.legacy.batteryStatus; + final int level = mBatteryProps.batteryLevel; + final int status = mBatteryProps.batteryStatus; if (level < mLowBatteryWarningLevel) { if (status == BatteryManager.BATTERY_STATUS_CHARGING) { // Solid red when battery is charging @@ -1009,7 +985,7 @@ public final class BatteryService extends SystemService { @Override public int getBatteryLevel() { synchronized (mLock) { - return mHealthInfo.legacy.batteryLevel; + return mBatteryProps.batteryLevel; } } @@ -1027,121 +1003,4 @@ public final class BatteryService extends SystemService { } } } - - /** - * HealthServiceWrapper wraps the internal IHealth service and refreshes the service when - * necessary. - * - * On new registration of IHealth service, {@link #onRegistration onRegistration} is called and - * the internal service is refreshed. - * On death of an existing IHealth service, the internal service is NOT cleared to avoid - * race condition between death notification and new service notification. Hence, - * a caller must check for transaction errors when calling into the service. - * - * @hide Should only be used internally. - */ - @VisibleForTesting - static final class HealthServiceWrapper { - private static final String TAG = "HealthServiceWrapper"; - public static final String INSTANCE_HEALTHD = "backup"; - public static final String INSTANCE_VENDOR = "default"; - // All interesting instances, sorted by priority high -> low. - private static final List<String> sAllInstances = - Arrays.asList(INSTANCE_VENDOR, INSTANCE_HEALTHD); - - private final IServiceNotification mNotification = new Notification(); - private Callback mCallback; - private IHealthSupplier mHealthSupplier; - - /** - * init should be called after constructor. For testing purposes, init is not called by - * constructor. - */ - HealthServiceWrapper() { - } - - /** - * Start monitoring registration of new IHealth services. Only instances that are in - * {@code sAllInstances} and in device / framework manifest are used. This function should - * only be called once. - * @throws RemoteException transaction error when talking to IServiceManager - * @throws NoSuchElementException if one of the following cases: - * - No service manager; - * - none of {@code sAllInstances} are in manifests (i.e. not - * available on this device), or none of these instances are available to current - * process. - * @throws NullPointerException when callback is null or supplier is null - */ - void init(Callback callback, - IServiceManagerSupplier managerSupplier, - IHealthSupplier healthSupplier) - throws RemoteException, NoSuchElementException, NullPointerException { - if (callback == null || managerSupplier == null || healthSupplier == null) - throw new NullPointerException(); - - mCallback = callback; - mHealthSupplier = healthSupplier; - - IServiceManager manager = managerSupplier.get(); - for (String name : sAllInstances) { - if (manager.getTransport(IHealth.kInterfaceName, name) == - IServiceManager.Transport.EMPTY) { - continue; - } - - manager.registerForNotifications(IHealth.kInterfaceName, name, mNotification); - Slog.i(TAG, "health: HealthServiceWrapper listening to instance " + name); - return; - } - - throw new NoSuchElementException(String.format( - "No IHealth service instance among %s is available. Perhaps no permission?", - sAllInstances.toString())); - } - - interface Callback { - /** - * This function is invoked asynchronously when a new and related IServiceNotification - * is received. - * @param service the recently retrieved service from IServiceManager. - * Can be a dead service before service notification of a new service is delivered. - * Implementation must handle cases for {@link RemoteException}s when calling - * into service. - * @param instance instance name. - */ - void onRegistration(IHealth service, String instance); - } - - /** - * Supplier of services. - * Must not return null; throw {@link NoSuchElementException} if a service is not available. - */ - interface IServiceManagerSupplier { - IServiceManager get() throws NoSuchElementException, RemoteException; - } - /** - * Supplier of services. - * Must not return null; throw {@link NoSuchElementException} if a service is not available. - */ - interface IHealthSupplier { - IHealth get(String instanceName) throws NoSuchElementException, RemoteException; - } - - private class Notification extends IServiceNotification.Stub { - @Override - public final void onRegistration(String interfaceName, String instanceName, - boolean preexisting) { - if (!IHealth.kInterfaceName.equals(interfaceName)) return; - if (!sAllInstances.contains(instanceName)) return; - try { - IHealth service = mHealthSupplier.get(instanceName); - Slog.i(TAG, "health: new instance registered " + instanceName); - mCallback.onRegistration(service, instanceName); - } catch (NoSuchElementException | RemoteException ex) { - Slog.e(TAG, "health: Cannot get instance '" + instanceName + "': " + - ex.getMessage() + ". Perhaps no permission?"); - } - } - } - } } diff --git a/com/android/server/IntentResolver.java b/com/android/server/IntentResolver.java index 119c9df6..40499c96 100644 --- a/com/android/server/IntentResolver.java +++ b/com/android/server/IntentResolver.java @@ -38,8 +38,6 @@ import android.util.Printer; import android.content.Intent; import android.content.IntentFilter; -import android.util.proto.ProtoOutputStream; - import com.android.internal.util.FastPrintWriter; /** @@ -281,31 +279,6 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> { return printedSomething; } - void writeProtoMap(ProtoOutputStream proto, long fieldId, ArrayMap<String, F[]> map) { - int N = map.size(); - for (int mapi = 0; mapi < N; mapi++) { - long token = proto.start(fieldId); - proto.write(IntentResolverProto.ArrayMapEntry.KEY, map.keyAt(mapi)); - for (F f : map.valueAt(mapi)) { - if (f != null) { - proto.write(IntentResolverProto.ArrayMapEntry.VALUES, f.toString()); - } - } - proto.end(token); - } - } - - public void writeToProto(ProtoOutputStream proto, long fieldId) { - long token = proto.start(fieldId); - writeProtoMap(proto, IntentResolverProto.FULL_MIME_TYPES, mTypeToFilter); - writeProtoMap(proto, IntentResolverProto.BASE_MIME_TYPES, mBaseTypeToFilter); - writeProtoMap(proto, IntentResolverProto.WILD_MIME_TYPES, mWildTypeToFilter); - writeProtoMap(proto, IntentResolverProto.SCHEMES, mSchemeToFilter); - writeProtoMap(proto, IntentResolverProto.NON_DATA_ACTIONS, mActionToFilter); - writeProtoMap(proto, IntentResolverProto.MIME_TYPED_ACTIONS, mTypedActionToFilter); - proto.end(token); - } - public boolean dump(PrintWriter out, String title, String prefix, String packageName, boolean printFilter, boolean collapseDuplicates) { String innerPrefix = prefix + " "; diff --git a/com/android/server/SystemServer.java b/com/android/server/SystemServer.java index 49dd5285..92cbd3d5 100644 --- a/com/android/server/SystemServer.java +++ b/com/android/server/SystemServer.java @@ -125,7 +125,6 @@ import java.util.Timer; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Future; -import static android.os.IServiceManager.DUMP_PRIORITY_CRITICAL; import static android.view.Display.DEFAULT_DISPLAY; public final class SystemServer { @@ -825,8 +824,7 @@ public final class SystemServer { wm = WindowManagerService.main(context, inputManager, mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL, !mFirstBoot, mOnlyCore, new PhoneWindowManager()); - ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false, - DUMP_PRIORITY_CRITICAL); + ServiceManager.addService(Context.WINDOW_SERVICE, wm); ServiceManager.addService(Context.INPUT_SERVICE, inputManager); traceEnd(); @@ -1642,7 +1640,11 @@ public final class SystemServer { traceEnd(); traceBeginAndSlog("MakePackageManagerServiceReady"); - mPackageManagerService.systemReady(); + try { + mPackageManagerService.systemReady(); + } catch (Throwable e) { + reportWtf("making Package Manager Service ready", e); + } traceEnd(); traceBeginAndSlog("MakeDisplayManagerServiceReady"); diff --git a/com/android/server/VibratorService.java b/com/android/server/VibratorService.java index 8b79b9dd..046eb761 100644 --- a/com/android/server/VibratorService.java +++ b/com/android/server/VibratorService.java @@ -373,24 +373,12 @@ public class VibratorService extends IVibratorService.Stub if (mCurrentVibration.hasLongerTimeout(newOneShot.getTiming()) && newOneShot.getAmplitude() == currentOneShot.getAmplitude()) { if (DEBUG) { - Slog.d(TAG, "Ignoring incoming vibration in favor of current vibration"); + Slog.e(TAG, "Ignoring incoming vibration in favor of current vibration"); } return; } } - // If the current vibration is repeating and the incoming one is non-repeating, then ignore - // the non-repeating vibration. This is so that we don't cancel vibrations that are meant - // to grab the attention of the user, like ringtones and alarms, in favor of one-shot - // vibrations that are likely quite short. - if (!isRepeatingVibration(effect) - && mCurrentVibration != null && isRepeatingVibration(mCurrentVibration.mEffect)) { - if (DEBUG) { - Slog.d(TAG, "Ignoring incoming vibration in favor of alarm vibration"); - } - return; - } - Vibration vib = new Vibration(token, effect, usageHint, uid, opPkg); // Only link against waveforms since they potentially don't have a finish if @@ -416,16 +404,6 @@ public class VibratorService extends IVibratorService.Stub } } - private static boolean isRepeatingVibration(VibrationEffect effect) { - if (effect instanceof VibrationEffect.Waveform) { - final VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) effect; - if (waveform.getRepeatIndex() >= 0) { - return true; - } - } - return false; - } - private void addToPreviousVibrationsLocked(Vibration vib) { if (mPreviousVibrations.size() > mPreviousVibrationsLimit) { mPreviousVibrations.removeFirst(); diff --git a/com/android/server/accessibility/AccessibilityInputFilter.java b/com/android/server/accessibility/AccessibilityInputFilter.java index f6fcaae4..c60647fa 100644 --- a/com/android/server/accessibility/AccessibilityInputFilter.java +++ b/com/android/server/accessibility/AccessibilityInputFilter.java @@ -19,9 +19,6 @@ package com.android.server.accessibility; import android.content.Context; import android.os.Handler; import android.os.PowerManager; -import android.util.DebugUtils; -import android.util.ExceptionUtils; -import android.util.Log; import android.util.Pools.SimplePool; import android.util.Slog; import android.util.SparseBooleanArray; @@ -34,7 +31,6 @@ import android.view.MotionEvent; import android.view.WindowManagerPolicy; import android.view.accessibility.AccessibilityEvent; -import com.android.internal.util.BitUtils; import com.android.server.LocalServices; /** @@ -192,7 +188,6 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo } if (mEventHandler == null) { - if (DEBUG) Slog.d(TAG, "mEventHandler == null for event " + event); super.onInputEvent(event, policyFlags); return; } @@ -344,8 +339,6 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo MotionEvent transformedEvent = MotionEvent.obtain(event); mEventHandler.onMotionEvent(transformedEvent, event, policyFlags); transformedEvent.recycle(); - } else { - if (DEBUG) Slog.d(TAG, "mEventHandler == null for " + event); } } @@ -373,20 +366,11 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo } @Override - public EventStreamTransformation getNext() { - return null; - } - - @Override public void clearEvents(int inputSource) { /* do nothing */ } void setUserAndEnabledFeatures(int userId, int enabledFeatures) { - if (DEBUG) { - Slog.i(TAG, "setUserAndEnabledFeatures(userId = " + userId + ", enabledFeatures = 0x" - + Integer.toHexString(enabledFeatures) + ")"); - } if (mEnabledFeatures == enabledFeatures && mUserId == userId) { return; } @@ -413,8 +397,6 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo } private void enableFeatures() { - if (DEBUG) Slog.i(TAG, "enableFeatures()"); - resetStreamState(); if ((mEnabledFeatures & FLAG_FEATURE_AUTOCLICK) != 0) { @@ -461,7 +443,7 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo */ private void addFirstEventHandler(EventStreamTransformation handler) { if (mEventHandler != null) { - handler.setNext(mEventHandler); + handler.setNext(mEventHandler); } else { handler.setNext(this); } diff --git a/com/android/server/accessibility/AutoclickController.java b/com/android/server/accessibility/AutoclickController.java index f5b0eb1e..892e9da4 100644 --- a/com/android/server/accessibility/AutoclickController.java +++ b/com/android/server/accessibility/AutoclickController.java @@ -23,12 +23,15 @@ import android.database.ContentObserver; import android.net.Uri; import android.os.Handler; import android.os.SystemClock; +import android.os.UserHandle; import android.provider.Settings; +import android.util.Slog; import android.view.InputDevice; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.MotionEvent.PointerCoords; import android.view.MotionEvent.PointerProperties; +import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; /** @@ -52,10 +55,11 @@ import android.view.accessibility.AccessibilityManager; * * Each instance is associated to a single user (and it does not handle user switch itself). */ -public class AutoclickController extends BaseEventStreamTransformation { +public class AutoclickController implements EventStreamTransformation { private static final String LOG_TAG = AutoclickController.class.getSimpleName(); + private EventStreamTransformation mNext; private final Context mContext; private final int mUserId; @@ -84,7 +88,9 @@ public class AutoclickController extends BaseEventStreamTransformation { mClickScheduler.cancel(); } - super.onMotionEvent(event, rawEvent, policyFlags); + if (mNext != null) { + mNext.onMotionEvent(event, rawEvent, policyFlags); + } } @Override @@ -97,7 +103,21 @@ public class AutoclickController extends BaseEventStreamTransformation { } } - super.onKeyEvent(event, policyFlags); + if (mNext != null) { + mNext.onKeyEvent(event, policyFlags); + } + } + + @Override + public void onAccessibilityEvent(AccessibilityEvent event) { + if (mNext != null) { + mNext.onAccessibilityEvent(event); + } + } + + @Override + public void setNext(EventStreamTransformation next) { + mNext = next; } @Override @@ -106,7 +126,9 @@ public class AutoclickController extends BaseEventStreamTransformation { mClickScheduler.cancel(); } - super.clearEvents(inputSource); + if (mNext != null) { + mNext.clearEvents(inputSource); + } } @Override @@ -396,7 +418,7 @@ public class AutoclickController extends BaseEventStreamTransformation { * Creates and forwards click event sequence. */ private void sendClick() { - if (mLastMotionEvent == null || getNext() == null) { + if (mLastMotionEvent == null || mNext == null) { return; } @@ -426,10 +448,10 @@ public class AutoclickController extends BaseEventStreamTransformation { MotionEvent upEvent = MotionEvent.obtain(downEvent); upEvent.setAction(MotionEvent.ACTION_UP); - AutoclickController.super.onMotionEvent(downEvent, downEvent, mEventPolicyFlags); + mNext.onMotionEvent(downEvent, downEvent, mEventPolicyFlags); downEvent.recycle(); - AutoclickController.super.onMotionEvent(upEvent, upEvent, mEventPolicyFlags); + mNext.onMotionEvent(upEvent, upEvent, mEventPolicyFlags); upEvent.recycle(); } diff --git a/com/android/server/accessibility/BaseEventStreamTransformation.java b/com/android/server/accessibility/BaseEventStreamTransformation.java deleted file mode 100644 index ce54586c..00000000 --- a/com/android/server/accessibility/BaseEventStreamTransformation.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - ** Copyright 2017, 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.accessibility; - -abstract class BaseEventStreamTransformation implements EventStreamTransformation { - private EventStreamTransformation mNext; - - @Override - public void setNext(EventStreamTransformation next) { - mNext = next; - } - - @Override - public EventStreamTransformation getNext() { - return mNext; - } -}
\ No newline at end of file diff --git a/com/android/server/accessibility/EventStreamTransformation.java b/com/android/server/accessibility/EventStreamTransformation.java index 7982996e..fdc40984 100644 --- a/com/android/server/accessibility/EventStreamTransformation.java +++ b/com/android/server/accessibility/EventStreamTransformation.java @@ -65,12 +65,7 @@ interface EventStreamTransformation { * @param rawEvent The raw motion event. * @param policyFlags Policy flags for the event. */ - default void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) { - EventStreamTransformation next = getNext(); - if (next != null) { - next.onMotionEvent(event, rawEvent, policyFlags); - } - } + public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags); /** * Receives a key event. @@ -78,24 +73,14 @@ interface EventStreamTransformation { * @param event The key event. * @param policyFlags Policy flags for the event. */ - default void onKeyEvent(KeyEvent event, int policyFlags) { - EventStreamTransformation next = getNext(); - if (next != null) { - next.onKeyEvent(event, policyFlags); - } - } + public void onKeyEvent(KeyEvent event, int policyFlags); /** * Receives an accessibility event. * * @param event The accessibility event. */ - default void onAccessibilityEvent(AccessibilityEvent event) { - EventStreamTransformation next = getNext(); - if (next != null) { - next.onAccessibilityEvent(event); - } - }; + public void onAccessibilityEvent(AccessibilityEvent event); /** * Sets the next transformation. @@ -105,26 +90,14 @@ interface EventStreamTransformation { public void setNext(EventStreamTransformation next); /** - * Gets the next transformation. - * - * @return The next transformation. - */ - public EventStreamTransformation getNext(); - - /** * Clears internal state associated with events from specific input source. * * @param inputSource The input source class for which transformation state should be cleared. */ - default void clearEvents(int inputSource) { - EventStreamTransformation next = getNext(); - if (next != null) { - next.clearEvents(inputSource); - } - } + public void clearEvents(int inputSource); /** * Destroys this transformation. */ - default void onDestroy() {} + public void onDestroy(); } diff --git a/com/android/server/accessibility/KeyboardInterceptor.java b/com/android/server/accessibility/KeyboardInterceptor.java index 77249452..f00a9540 100644 --- a/com/android/server/accessibility/KeyboardInterceptor.java +++ b/com/android/server/accessibility/KeyboardInterceptor.java @@ -22,12 +22,14 @@ import android.os.SystemClock; import android.util.Pools; import android.util.Slog; import android.view.KeyEvent; +import android.view.MotionEvent; import android.view.WindowManagerPolicy; +import android.view.accessibility.AccessibilityEvent; /** * Intercepts key events and forwards them to accessibility manager service. */ -public class KeyboardInterceptor extends BaseEventStreamTransformation implements Handler.Callback { +public class KeyboardInterceptor implements EventStreamTransformation, Handler.Callback { private static final int MESSAGE_PROCESS_QUEUED_EVENTS = 1; private static final String LOG_TAG = "KeyboardInterceptor"; @@ -35,6 +37,7 @@ public class KeyboardInterceptor extends BaseEventStreamTransformation implement private final WindowManagerPolicy mPolicy; private final Handler mHandler; + private EventStreamTransformation mNext; private KeyEventHolder mEventQueueStart; private KeyEventHolder mEventQueueEnd; @@ -62,6 +65,13 @@ public class KeyboardInterceptor extends BaseEventStreamTransformation implement } @Override + public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) { + if (mNext != null) { + mNext.onMotionEvent(event, rawEvent, policyFlags); + } + } + + @Override public void onKeyEvent(KeyEvent event, int policyFlags) { /* * Certain keys have system-level behavior that affects accessibility services. @@ -80,6 +90,29 @@ public class KeyboardInterceptor extends BaseEventStreamTransformation implement } @Override + public void onAccessibilityEvent(AccessibilityEvent event) { + if (mNext != null) { + mNext.onAccessibilityEvent(event); + } + } + + @Override + public void setNext(EventStreamTransformation next) { + mNext = next; + } + + @Override + public void clearEvents(int inputSource) { + if (mNext != null) { + mNext.clearEvents(inputSource); + } + } + + @Override + public void onDestroy() { + } + + @Override public boolean handleMessage(Message msg) { if (msg.what != MESSAGE_PROCESS_QUEUED_EVENTS) { Slog.e(LOG_TAG, "Unexpected message type"); diff --git a/com/android/server/accessibility/MagnificationController.java b/com/android/server/accessibility/MagnificationController.java index a10b7a20..98b8e6b7 100644 --- a/com/android/server/accessibility/MagnificationController.java +++ b/com/android/server/accessibility/MagnificationController.java @@ -56,7 +56,6 @@ import java.util.Locale; * constraints. */ class MagnificationController implements Handler.Callback { - private static final boolean DEBUG = false; private static final String LOG_TAG = "MagnificationController"; public static final float MIN_SCALE = 1.0f; @@ -510,12 +509,6 @@ class MagnificationController implements Handler.Callback { private boolean setScaleAndCenterLocked(float scale, float centerX, float centerY, boolean animate, int id) { - if (DEBUG) { - Slog.i(LOG_TAG, - "setScaleAndCenterLocked(scale = " + scale + ", centerX = " + centerX - + ", centerY = " + centerY + ", animate = " + animate + ", id = " + id - + ")"); - } final boolean changed = updateMagnificationSpecLocked(scale, centerX, centerY); sendSpecToAnimation(mCurrentMagnificationSpec, animate); if (isMagnifying() && (id != INVALID_ID)) { @@ -542,9 +535,7 @@ class MagnificationController implements Handler.Callback { final float nonNormOffsetX = mCurrentMagnificationSpec.offsetX - offsetX; final float nonNormOffsetY = mCurrentMagnificationSpec.offsetY - offsetY; - if (updateCurrentSpecWithOffsetsLocked(nonNormOffsetX, nonNormOffsetY)) { - onMagnificationChangedLocked(); - } + updateCurrentSpecWithOffsetsLocked(nonNormOffsetX, nonNormOffsetY); if (id != INVALID_ID) { mIdOfLastServiceToMagnify = id; } @@ -642,11 +633,6 @@ class MagnificationController implements Handler.Callback { } private boolean updateCurrentSpecWithOffsetsLocked(float nonNormOffsetX, float nonNormOffsetY) { - if (DEBUG) { - Slog.i(LOG_TAG, - "updateCurrentSpecWithOffsetsLocked(nonNormOffsetX = " + nonNormOffsetX - + ", nonNormOffsetY = " + nonNormOffsetY + ")"); - } boolean changed = false; final float offsetX = MathUtils.constrain(nonNormOffsetX, getMinOffsetXLocked(), 0); if (Float.compare(mCurrentMagnificationSpec.offsetX, offsetX) != 0) { @@ -764,9 +750,6 @@ class MagnificationController implements Handler.Callback { } private void sendSpecToAnimation(MagnificationSpec spec, boolean animate) { - if (DEBUG) { - Slog.i(LOG_TAG, "sendSpecToAnimation(spec = " + spec + ", animate = " + animate + ")"); - } if (Thread.currentThread().getId() == mMainThreadId) { mSpecAnimationBridge.updateSentSpecMainThread(spec, animate); } else { diff --git a/com/android/server/accessibility/MagnificationGestureHandler.java b/com/android/server/accessibility/MagnificationGestureHandler.java index 9b2b4eb7..d6452f87 100644 --- a/com/android/server/accessibility/MagnificationGestureHandler.java +++ b/com/android/server/accessibility/MagnificationGestureHandler.java @@ -42,12 +42,14 @@ import android.util.Slog; import android.util.TypedValue; import android.view.GestureDetector; import android.view.GestureDetector.SimpleOnGestureListener; +import android.view.KeyEvent; import android.view.MotionEvent; import android.view.MotionEvent.PointerCoords; import android.view.MotionEvent.PointerProperties; import android.view.ScaleGestureDetector; import android.view.ScaleGestureDetector.OnScaleGestureListener; import android.view.ViewConfiguration; +import android.view.accessibility.AccessibilityEvent; import com.android.internal.annotations.VisibleForTesting; @@ -100,23 +102,31 @@ import com.android.internal.annotations.VisibleForTesting; * 7. The magnification scale will be persisted in settings and in the cloud. */ @SuppressWarnings("WeakerAccess") -class MagnificationGestureHandler extends BaseEventStreamTransformation { - private static final String LOG_TAG = "MagnificationGestureHandler"; +class MagnificationGestureHandler implements EventStreamTransformation { + private static final String LOG_TAG = "MagnificationEventHandler"; private static final boolean DEBUG_ALL = false; private static final boolean DEBUG_STATE_TRANSITIONS = false || DEBUG_ALL; private static final boolean DEBUG_DETECTING = false || DEBUG_ALL; - private static final boolean DEBUG_PANNING_SCALING = false || DEBUG_ALL; + private static final boolean DEBUG_PANNING = false || DEBUG_ALL; + + /** @see #handleMotionEventStateDelegating */ + @VisibleForTesting static final int STATE_DELEGATING = 1; + /** @see DetectingStateHandler */ + @VisibleForTesting static final int STATE_DETECTING = 2; + /** @see ViewportDraggingStateHandler */ + @VisibleForTesting static final int STATE_VIEWPORT_DRAGGING = 3; + /** @see PanningScalingStateHandler */ + @VisibleForTesting static final int STATE_PANNING_SCALING = 4; private static final float MIN_SCALE = 2.0f; private static final float MAX_SCALE = 5.0f; @VisibleForTesting final MagnificationController mMagnificationController; - @VisibleForTesting final DelegatingState mDelegatingState; - @VisibleForTesting final DetectingState mDetectingState; - @VisibleForTesting final PanningScalingState mPanningScalingState; - @VisibleForTesting final ViewportDraggingState mViewportDraggingState; + @VisibleForTesting final DetectingStateHandler mDetectingStateHandler; + @VisibleForTesting final PanningScalingStateHandler mPanningScalingStateHandler; + @VisibleForTesting final ViewportDraggingStateHandler mViewportDraggingStateHandler; private final ScreenStateReceiver mScreenStateReceiver; @@ -128,12 +138,21 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation { final boolean mDetectTripleTap; /** - * Whether {@link DetectingState#mShortcutTriggered shortcut} is enabled + * Whether {@link #mShortcutTriggered shortcut} is enabled */ final boolean mDetectShortcutTrigger; - @VisibleForTesting State mCurrentState; - @VisibleForTesting State mPreviousState; + EventStreamTransformation mNext; + + @VisibleForTesting int mCurrentState; + @VisibleForTesting int mPreviousState; + + @VisibleForTesting boolean mShortcutTriggered; + + /** + * Time of last {@link MotionEvent#ACTION_DOWN} while in {@link #STATE_DELEGATING} + */ + long mDelegatingStateDownTime; private PointerCoords[] mTempPointerCoords; private PointerProperties[] mTempPointerProperties; @@ -155,10 +174,10 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation { boolean detectShortcutTrigger) { mMagnificationController = magnificationController; - mDelegatingState = new DelegatingState(); - mDetectingState = new DetectingState(context); - mViewportDraggingState = new ViewportDraggingState(); - mPanningScalingState = new PanningScalingState(context); + mDetectingStateHandler = new DetectingStateHandler(context); + mViewportDraggingStateHandler = new ViewportDraggingStateHandler(); + mPanningScalingStateHandler = + new PanningScalingStateHandler(context); mDetectTripleTap = detectTripleTap; mDetectShortcutTrigger = detectShortcutTrigger; @@ -170,29 +189,62 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation { mScreenStateReceiver = null; } - transitionTo(mDetectingState); + transitionTo(STATE_DETECTING); } @Override public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) { - if (DEBUG_ALL) Slog.i(LOG_TAG, "onMotionEvent(" + event + ")"); - if ((!mDetectTripleTap && !mDetectShortcutTrigger) || !event.isFromSource(SOURCE_TOUCHSCREEN)) { dispatchTransformedEvent(event, rawEvent, policyFlags); return; } + // Local copy to avoid dispatching the same event to more than one state handler + // in case mPanningScalingStateHandler changes mCurrentState + int currentState = mCurrentState; + mPanningScalingStateHandler.onMotionEvent(event, rawEvent, policyFlags); + switch (currentState) { + case STATE_DELEGATING: { + handleMotionEventStateDelegating(event, rawEvent, policyFlags); + } + break; + case STATE_DETECTING: { + mDetectingStateHandler.onMotionEvent(event, rawEvent, policyFlags); + } + break; + case STATE_VIEWPORT_DRAGGING: { + mViewportDraggingStateHandler.onMotionEvent(event, rawEvent, policyFlags); + } + break; + case STATE_PANNING_SCALING: { + // mPanningScalingStateHandler handles events only + // if this is the current state since it uses ScaleGestureDetector + // and a GestureDetector which need well formed event stream. + } + break; + default: { + throw new IllegalStateException("Unknown state: " + currentState); + } + } + } - handleEventWith(mCurrentState, event, rawEvent, policyFlags); + @Override + public void onKeyEvent(KeyEvent event, int policyFlags) { + if (mNext != null) { + mNext.onKeyEvent(event, policyFlags); + } } - private void handleEventWith(State stateHandler, - MotionEvent event, MotionEvent rawEvent, int policyFlags) { - // To keep InputEventConsistencyVerifiers within GestureDetectors happy - mPanningScalingState.mScrollGestureDetector.onTouchEvent(event); - mPanningScalingState.mScaleGestureDetector.onTouchEvent(event); + @Override + public void onAccessibilityEvent(AccessibilityEvent event) { + if (mNext != null) { + mNext.onAccessibilityEvent(event); + } + } - stateHandler.onMotionEvent(event, rawEvent, policyFlags); + @Override + public void setNext(EventStreamTransformation next) { + mNext = next; } @Override @@ -201,16 +253,13 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation { clearAndTransitionToStateDetecting(); } - super.clearEvents(inputSource); + if (mNext != null) { + mNext.clearEvents(inputSource); + } } @Override public void onDestroy() { - if (DEBUG_STATE_TRANSITIONS) { - Slog.i(LOG_TAG, "onDestroy(); delayed = " - + MotionEventInfo.toString(mDetectingState.mDelayedEventQueue)); - } - if (mScreenStateReceiver != null) { mScreenStateReceiver.unregister(); } @@ -223,21 +272,59 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation { if (wasMagnifying) { clearAndTransitionToStateDetecting(); } else { - mDetectingState.toggleShortcutTriggered(); + toggleShortcutTriggered(); } } } + private void toggleShortcutTriggered() { + setShortcutTriggered(!mShortcutTriggered); + } + + private void setShortcutTriggered(boolean state) { + if (mShortcutTriggered == state) { + return; + } + + mShortcutTriggered = state; + mMagnificationController.setForceShowMagnifiableBounds(state); + } + void clearAndTransitionToStateDetecting() { - mCurrentState = mDelegatingState; - mDetectingState.clear(); - mViewportDraggingState.clear(); - mPanningScalingState.clear(); + setShortcutTriggered(false); + mCurrentState = STATE_DETECTING; + mDetectingStateHandler.clear(); + mViewportDraggingStateHandler.clear(); + mPanningScalingStateHandler.clear(); + } + + private void handleMotionEventStateDelegating(MotionEvent event, + MotionEvent rawEvent, int policyFlags) { + if (event.getActionMasked() == ACTION_UP) { + transitionTo(STATE_DETECTING); + } + delegateEvent(event, rawEvent, policyFlags); + } + + void delegateEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) { + if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { + mDelegatingStateDownTime = event.getDownTime(); + } + if (mNext != null) { + // We cache some events to see if the user wants to trigger magnification. + // If no magnification is triggered we inject these events with adjusted + // time and down time to prevent subsequent transformations being confused + // by stale events. After the cached events, which always have a down, are + // injected we need to also update the down time of all subsequent non cached + // events. All delegated events cached and non-cached are delivered here. + event.setDownTime(mDelegatingStateDownTime); + dispatchTransformedEvent(event, rawEvent, policyFlags); + } } private void dispatchTransformedEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) { - if (DEBUG_ALL) Slog.i(LOG_TAG, "dispatchTransformedEvent(event = " + event + ")"); + if (mNext == null) return; // Nowhere to dispatch to // If the touchscreen event is within the magnified portion of the screen we have // to change its location to be where the user thinks he is poking the @@ -264,7 +351,7 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation { coords, 0, 0, 1.0f, 1.0f, event.getDeviceId(), 0, event.getSource(), event.getFlags()); } - super.onMotionEvent(event, rawEvent, policyFlags); + mNext.onMotionEvent(event, rawEvent, policyFlags); } private PointerCoords[] getTempPointerCoordsWithMinSize(int size) { @@ -299,10 +386,9 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation { return mTempPointerProperties; } - private void transitionTo(State state) { + private void transitionTo(int state) { if (DEBUG_STATE_TRANSITIONS) { - Slog.i(LOG_TAG, - (State.nameOf(mCurrentState) + " -> " + State.nameOf(state) + Slog.i(LOG_TAG, (stateToString(mCurrentState) + " -> " + stateToString(state) + " at " + asList(copyOfRange(new RuntimeException().getStackTrace(), 1, 5))) .replace(getClass().getName(), "")); } @@ -310,40 +396,40 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation { mCurrentState = state; } - interface State { - void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags); + private static String stateToString(int state) { + switch (state) { + case STATE_DELEGATING: return "STATE_DELEGATING"; + case STATE_DETECTING: return "STATE_DETECTING"; + case STATE_VIEWPORT_DRAGGING: return "STATE_VIEWPORT_DRAGGING"; + case STATE_PANNING_SCALING: return "STATE_PANNING_SCALING"; + case 0: return "0"; + default: throw new IllegalArgumentException("Unknown state: " + state); + } + } - default void clear() {} + private interface MotionEventHandler { - default String name() { - return getClass().getSimpleName(); - } + void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags); - static String nameOf(@Nullable State s) { - return s != null ? s.name() : "null"; - } + void clear(); } /** * This class determines if the user is performing a scale or pan gesture. * - * Unlike when {@link ViewportDraggingState dragging the viewport}, in panning mode the viewport - * moves in the same direction as the fingers, and allows to easily and precisely scale the - * magnification level. - * This makes it the preferred mode for one-off adjustments, due to its precision and ease of - * triggering. + * @see #STATE_PANNING_SCALING */ - final class PanningScalingState extends SimpleOnGestureListener - implements OnScaleGestureListener, State { + final class PanningScalingStateHandler extends SimpleOnGestureListener + implements OnScaleGestureListener, MotionEventHandler { private final ScaleGestureDetector mScaleGestureDetector; - private final GestureDetector mScrollGestureDetector; + private final GestureDetector mGestureDetector; final float mScalingThreshold; float mInitialScaleFactor = -1; boolean mScaling; - public PanningScalingState(Context context) { + public PanningScalingStateHandler(Context context) { final TypedValue scaleValue = new TypedValue(); context.getResources().getValue( com.android.internal.R.dimen.config_screen_magnification_scaling_threshold, @@ -351,27 +437,35 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation { mScalingThreshold = scaleValue.getFloat(); mScaleGestureDetector = new ScaleGestureDetector(context, this); mScaleGestureDetector.setQuickScaleEnabled(false); - mScrollGestureDetector = new GestureDetector(context, this); + mGestureDetector = new GestureDetector(context, this); } @Override public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) { - int action = event.getActionMasked(); + // Dispatches #onScaleBegin, #onScale, #onScaleEnd + mScaleGestureDetector.onTouchEvent(event); + // Dispatches #onScroll + mGestureDetector.onTouchEvent(event); + if (mCurrentState != STATE_PANNING_SCALING) { + return; + } + + int action = event.getActionMasked(); if (action == ACTION_POINTER_UP && event.getPointerCount() == 2 // includes the pointer currently being released - && mPreviousState == mViewportDraggingState) { + && mPreviousState == STATE_VIEWPORT_DRAGGING) { - persistScaleAndTransitionTo(mViewportDraggingState); + persistScaleAndTransitionTo(STATE_VIEWPORT_DRAGGING); } else if (action == ACTION_UP) { - persistScaleAndTransitionTo(mDetectingState); + persistScaleAndTransitionTo(STATE_DETECTING); } } - public void persistScaleAndTransitionTo(State state) { + public void persistScaleAndTransitionTo(int state) { mMagnificationController.persistScale(); clear(); transitionTo(state); @@ -380,16 +474,16 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation { @Override public boolean onScroll(MotionEvent first, MotionEvent second, float distanceX, float distanceY) { - if (mCurrentState != mPanningScalingState) { + if (mCurrentState != STATE_PANNING_SCALING) { return true; } - if (DEBUG_PANNING_SCALING) { + if (DEBUG_PANNING) { Slog.i(LOG_TAG, "Panned content by scrollX: " + distanceX + " scrollY: " + distanceY); } mMagnificationController.offsetMagnifiedRegion(distanceX, distanceY, AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID); - return /* event consumed: */ true; + return true; } @Override @@ -400,8 +494,12 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation { return false; } final float deltaScale = detector.getScaleFactor() - mInitialScaleFactor; - mScaling = abs(deltaScale) > mScalingThreshold; - return mScaling; + if (abs(deltaScale) > mScalingThreshold) { + mScaling = true; + return true; + } else { + return false; + } } final float initialScale = mMagnificationController.getScale(); @@ -425,15 +523,14 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation { final float pivotX = detector.getFocusX(); final float pivotY = detector.getFocusY(); - if (DEBUG_PANNING_SCALING) Slog.i(LOG_TAG, "Scaled content to: " + scale + "x"); mMagnificationController.setScale(scale, pivotX, pivotY, false, AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID); - return /* handled: */ true; + return true; } @Override public boolean onScaleBegin(ScaleGestureDetector detector) { - return /* continue recognizing: */ (mCurrentState == mPanningScalingState); + return (mCurrentState == STATE_PANNING_SCALING); } @Override @@ -449,7 +546,7 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation { @Override public String toString() { - return "PanningScalingState{" + + return "MagnifiedContentInteractionStateHandler{" + "mInitialScaleFactor=" + mInitialScaleFactor + ", mScaling=" + mScaling + '}'; @@ -461,11 +558,9 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation { * determined that the user is performing a single-finger drag of the * magnification viewport. * - * Unlike when {@link PanningScalingState panning}, the viewport moves in the opposite direction - * of the finger, and any part of the screen is reachable without lifting the finger. - * This makes it the preferable mode for tasks like reading text spanning full screen width. + * @see #STATE_VIEWPORT_DRAGGING */ - final class ViewportDraggingState implements State { + final class ViewportDraggingStateHandler implements MotionEventHandler { /** Whether to disable zoom after dragging ends */ boolean mZoomedInBeforeDrag; @@ -477,7 +572,7 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation { switch (action) { case ACTION_POINTER_DOWN: { clear(); - transitionTo(mPanningScalingState); + transitionTo(STATE_PANNING_SCALING); } break; case ACTION_MOVE: { @@ -499,7 +594,7 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation { case ACTION_UP: { if (!mZoomedInBeforeDrag) zoomOff(); clear(); - transitionTo(mDetectingState); + transitionTo(STATE_DETECTING); } break; @@ -518,51 +613,25 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation { @Override public String toString() { - return "ViewportDraggingState{" + + return "ViewportDraggingStateHandler{" + "mZoomedInBeforeDrag=" + mZoomedInBeforeDrag + ", mLastMoveOutsideMagnifiedRegion=" + mLastMoveOutsideMagnifiedRegion + '}'; } } - final class DelegatingState implements State { - /** - * Time of last {@link MotionEvent#ACTION_DOWN} while in {@link DelegatingState} - */ - public long mLastDelegatedDownEventTime; - - @Override - public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) { - if (event.getActionMasked() == ACTION_UP) { - transitionTo(mDetectingState); - } - - if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { - mLastDelegatedDownEventTime = event.getDownTime(); - } - if (getNext() != null) { - // We cache some events to see if the user wants to trigger magnification. - // If no magnification is triggered we inject these events with adjusted - // time and down time to prevent subsequent transformations being confused - // by stale events. After the cached events, which always have a down, are - // injected we need to also update the down time of all subsequent non cached - // events. All delegated events cached and non-cached are delivered here. - event.setDownTime(mLastDelegatedDownEventTime); - dispatchTransformedEvent(event, rawEvent, policyFlags); - } - } - } - /** * This class handles motion events when the event dispatch has not yet * determined what the user is doing. It watches for various tap events. + * + * @see #STATE_DETECTING */ - final class DetectingState implements State, Handler.Callback { + final class DetectingStateHandler implements MotionEventHandler, Handler.Callback { private static final int MESSAGE_ON_TRIPLE_TAP_AND_HOLD = 1; private static final int MESSAGE_TRANSITION_TO_DELEGATING_STATE = 2; - final int mLongTapMinDelay; + final int mLongTapMinDelay = ViewConfiguration.getJumpTapTimeout(); final int mSwipeMinDistance; final int mMultiTapMaxDelay; final int mMultiTapMaxDistance; @@ -573,12 +642,9 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation { private MotionEvent mLastUp; private MotionEvent mPreLastUp; - @VisibleForTesting boolean mShortcutTriggered; - Handler mHandler = new Handler(this); - public DetectingState(Context context) { - mLongTapMinDelay = ViewConfiguration.getLongPressTimeout(); + public DetectingStateHandler(Context context) { mMultiTapMaxDelay = ViewConfiguration.getDoubleTapTimeout() + context.getResources().getInteger( com.android.internal.R.integer.config_screen_magnification_multi_tap_adjustment); @@ -595,7 +661,7 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation { } break; case MESSAGE_TRANSITION_TO_DELEGATING_STATE: { - transitionToDelegatingStateAndClear(); + transitionToDelegatingState(/* andClear */ true); } break; default: { @@ -616,12 +682,12 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation { if (!mMagnificationController.magnificationRegionContains( event.getX(), event.getY())) { - transitionToDelegatingStateAndClear(); + transitionToDelegatingState(/* andClear */ !mShortcutTriggered); } else if (isMultiTapTriggered(2 /* taps */)) { // 3tap and hold - afterLongTapTimeoutTransitionToDraggingState(event); + delayedTransitionToDraggingState(event); } else if (mDetectTripleTap // If magnified, delay an ACTION_DOWN for mMultiTapMaxDelay @@ -629,21 +695,21 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation { // STATE_PANNING_SCALING(triggerable with ACTION_POINTER_DOWN) || mMagnificationController.isMagnifying()) { - afterMultiTapTimeoutTransitionToDelegatingState(); + delayedTransitionToDelegatingState(); } else { // Delegate pending events without delay - transitionToDelegatingStateAndClear(); + transitionToDelegatingState(/* andClear */ true); } } break; case ACTION_POINTER_DOWN: { if (mMagnificationController.isMagnifying()) { - transitionTo(mPanningScalingState); + transitionTo(STATE_PANNING_SCALING); clear(); } else { - transitionToDelegatingStateAndClear(); + transitionToDelegatingState(/* andClear */ true); } } break; @@ -656,7 +722,7 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation { && !isMultiTapTriggered(2 /* taps */)) { // Swipe detected - delegate skipping timeout - transitionToDelegatingStateAndClear(); + transitionToDelegatingState(/* andClear */ true); } } break; @@ -667,7 +733,7 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation { if (!mMagnificationController.magnificationRegionContains( event.getX(), event.getY())) { - transitionToDelegatingStateAndClear(); + transitionToDelegatingState(/* andClear */ !mShortcutTriggered); } else if (isMultiTapTriggered(3 /* taps */)) { @@ -676,11 +742,12 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation { } else if ( // Possible to be false on: 3tap&drag -> scale -> PTR_UP -> UP isFingerDown() - //TODO long tap should never happen here - && ((timeBetween(mLastDown, mLastUp) >= mLongTapMinDelay) - || (distance(mLastDown, mLastUp) >= mSwipeMinDistance))) { + //TODO long tap should never happen here + && (timeBetween(mLastDown, /* mLastUp */ event) >= mLongTapMinDelay) + || distance(mLastDown, /* mLastUp */ event) + >= mSwipeMinDistance) { - transitionToDelegatingStateAndClear(); + transitionToDelegatingState(/* andClear */ true); } } @@ -728,15 +795,15 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation { return MotionEventInfo.countOf(mDelayedEventQueue, ACTION_UP); } - /** -> {@link DelegatingState} */ - public void afterMultiTapTimeoutTransitionToDelegatingState() { + /** -> {@link #STATE_DELEGATING} */ + public void delayedTransitionToDelegatingState() { mHandler.sendEmptyMessageDelayed( MESSAGE_TRANSITION_TO_DELEGATING_STATE, mMultiTapMaxDelay); } - /** -> {@link ViewportDraggingState} */ - public void afterLongTapTimeoutTransitionToDraggingState(MotionEvent event) { + /** -> {@link #STATE_VIEWPORT_DRAGGING} */ + public void delayedTransitionToDraggingState(MotionEvent event) { mHandler.sendMessageDelayed( mHandler.obtainMessage(MESSAGE_ON_TRIPLE_TAP_AND_HOLD, event), ViewConfiguration.getLongPressTimeout()); @@ -779,7 +846,11 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation { MotionEventInfo info = mDelayedEventQueue; mDelayedEventQueue = info.mNext; - handleEventWith(mDelegatingState, info.event, info.rawEvent, info.policyFlags); + // Because MagnifiedInteractionStateHandler requires well-formed event stream + mPanningScalingStateHandler.onMotionEvent( + info.event, info.rawEvent, info.policyFlags); + + delegateEvent(info.event, info.rawEvent, info.policyFlags); info.recycle(); } @@ -797,10 +868,10 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation { mLastUp = null; } - void transitionToDelegatingStateAndClear() { - transitionTo(mDelegatingState); + void transitionToDelegatingState(boolean andClear) { + transitionTo(STATE_DELEGATING); sendDelayedMotionEvents(); - clear(); + if (andClear) clear(); } private void onTripleTap(MotionEvent up) { @@ -824,40 +895,24 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation { if (DEBUG_DETECTING) Slog.i(LOG_TAG, "onTripleTapAndHold()"); clear(); - mViewportDraggingState.mZoomedInBeforeDrag = + mViewportDraggingStateHandler.mZoomedInBeforeDrag = mMagnificationController.isMagnifying(); zoomOn(down.getX(), down.getY()); - transitionTo(mViewportDraggingState); + transitionTo(STATE_VIEWPORT_DRAGGING); } @Override public String toString() { - return "DetectingState{" + + return "DetectingStateHandler{" + "tapCount()=" + tapCount() + - ", mShortcutTriggered=" + mShortcutTriggered + ", mDelayedEventQueue=" + MotionEventInfo.toString(mDelayedEventQueue) + '}'; } - - void toggleShortcutTriggered() { - setShortcutTriggered(!mShortcutTriggered); - } - - void setShortcutTriggered(boolean state) { - if (mShortcutTriggered == state) { - return; - } - - mShortcutTriggered = state; - mMagnificationController.setForceShowMagnifiableBounds(state); - } } private void zoomOn(float centerX, float centerY) { - if (DEBUG_DETECTING) Slog.i(LOG_TAG, "zoomOn(" + centerX + ", " + centerY + ")"); - final float scale = MathUtils.constrain( mMagnificationController.getPersistedScale(), MIN_SCALE, MAX_SCALE); @@ -868,8 +923,6 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation { } private void zoomOff() { - if (DEBUG_DETECTING) Slog.i(LOG_TAG, "zoomOff()"); - mMagnificationController.reset(/* animate */ true); } @@ -882,15 +935,16 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation { @Override public String toString() { - return "MagnificationGesture{" + - "mDetectingState=" + mDetectingState + - ", mDelegatingState=" + mDelegatingState + - ", mMagnifiedInteractionState=" + mPanningScalingState + - ", mViewportDraggingState=" + mViewportDraggingState + + return "MagnificationGestureHandler{" + + "mDetectingStateHandler=" + mDetectingStateHandler + + ", mMagnifiedInteractionStateHandler=" + mPanningScalingStateHandler + + ", mViewportDraggingStateHandler=" + mViewportDraggingStateHandler + ", mDetectTripleTap=" + mDetectTripleTap + ", mDetectShortcutTrigger=" + mDetectShortcutTrigger + - ", mCurrentState=" + State.nameOf(mCurrentState) + - ", mPreviousState=" + State.nameOf(mPreviousState) + + ", mCurrentState=" + stateToString(mCurrentState) + + ", mPreviousState=" + stateToString(mPreviousState) + + ", mShortcutTriggered=" + mShortcutTriggered + + ", mDelegatingStateDownTime=" + mDelegatingStateDownTime + ", mMagnificationController=" + mMagnificationController + '}'; } @@ -997,7 +1051,7 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation { @Override public void onReceive(Context context, Intent intent) { - mGestureHandler.mDetectingState.setShortcutTriggered(false); + mGestureHandler.setShortcutTriggered(false); } } } diff --git a/com/android/server/accessibility/MotionEventInjector.java b/com/android/server/accessibility/MotionEventInjector.java index b6b78129..48041adb 100644 --- a/com/android/server/accessibility/MotionEventInjector.java +++ b/com/android/server/accessibility/MotionEventInjector.java @@ -30,13 +30,13 @@ import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; import android.view.InputDevice; +import android.view.KeyEvent; import android.view.MotionEvent; import android.view.WindowManagerPolicy; - +import android.view.accessibility.AccessibilityEvent; import com.android.internal.os.SomeArgs; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; /** @@ -45,7 +45,7 @@ import java.util.List; * <p> * All methods except {@code injectEvents} must be called only from the main thread. */ -public class MotionEventInjector extends BaseEventStreamTransformation implements Handler.Callback { +public class MotionEventInjector implements EventStreamTransformation, Handler.Callback { private static final String LOG_TAG = "MotionEventInjector"; private static final int MESSAGE_SEND_MOTION_EVENT = 1; private static final int MESSAGE_INJECT_EVENTS = 2; @@ -68,6 +68,7 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement private final Handler mHandler; private final SparseArray<Boolean> mOpenGesturesInProgress = new SparseArray<>(); + private EventStreamTransformation mNext; private IAccessibilityServiceClient mServiceInterfaceForCurrentGesture; private IntArray mSequencesInProgress = new IntArray(5); private boolean mIsDestroyed = false; @@ -116,6 +117,25 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement } @Override + public void onKeyEvent(KeyEvent event, int policyFlags) { + if (mNext != null) { + mNext.onKeyEvent(event, policyFlags); + } + } + + @Override + public void onAccessibilityEvent(AccessibilityEvent event) { + if (mNext != null) { + mNext.onAccessibilityEvent(event); + } + } + + @Override + public void setNext(EventStreamTransformation next) { + mNext = next; + } + + @Override public void clearEvents(int inputSource) { /* * Reset state for motion events passing through so we won't send a cancel event for @@ -167,7 +187,7 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement return; } - if (getNext() == null) { + if (mNext == null) { notifyService(serviceInterface, sequence, false); return; } @@ -242,24 +262,17 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement int continuedPointerId = mStrokeIdToPointerId .get(touchPoint.mContinuedStrokeId, -1); if (continuedPointerId == -1) { - Slog.w(LOG_TAG, "Can't continue gesture due to unknown continued stroke id in " - + touchPoint); return false; } mStrokeIdToPointerId.put(touchPoint.mStrokeId, continuedPointerId); int lastPointIndex = findPointByStrokeId( mLastTouchPoints, mNumLastTouchPoints, touchPoint.mContinuedStrokeId); if (lastPointIndex < 0) { - Slog.w(LOG_TAG, "Can't continue gesture due continued gesture id of " - + touchPoint + " not matching any previous strokes in " - + Arrays.asList(mLastTouchPoints)); return false; } if (mLastTouchPoints[lastPointIndex].mIsEndOfPath || (mLastTouchPoints[lastPointIndex].mX != touchPoint.mX) || (mLastTouchPoints[lastPointIndex].mY != touchPoint.mY)) { - Slog.w(LOG_TAG, "Can't continue gesture due to points mismatch between " - + mLastTouchPoints[lastPointIndex] + " and " + touchPoint); return false; } // Update the last touch point to match the continuation, so the gestures will @@ -279,8 +292,8 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement private void sendMotionEventToNext(MotionEvent event, MotionEvent rawEvent, int policyFlags) { - if (getNext() != null) { - super.onMotionEvent(event, rawEvent, policyFlags); + if (mNext != null) { + mNext.onMotionEvent(event, rawEvent, policyFlags); if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { mOpenGesturesInProgress.put(event.getSource(), true); } @@ -292,7 +305,7 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement } private void cancelAnyGestureInProgress(int source) { - if ((getNext() != null) && mOpenGesturesInProgress.get(source, false)) { + if ((mNext != null) && mOpenGesturesInProgress.get(source, false)) { long now = SystemClock.uptimeMillis(); MotionEvent cancelEvent = obtainMotionEvent(now, now, MotionEvent.ACTION_CANCEL, getLastTouchPoints(), 1); diff --git a/com/android/server/accessibility/TouchExplorer.java b/com/android/server/accessibility/TouchExplorer.java index a32686df..e380f2c6 100644 --- a/com/android/server/accessibility/TouchExplorer.java +++ b/com/android/server/accessibility/TouchExplorer.java @@ -55,8 +55,7 @@ import java.util.List; * * @hide */ -class TouchExplorer extends BaseEventStreamTransformation - implements AccessibilityGestureDetector.Listener { +class TouchExplorer implements EventStreamTransformation, AccessibilityGestureDetector.Listener { private static final boolean DEBUG = false; @@ -132,6 +131,9 @@ class TouchExplorer extends BaseEventStreamTransformation // the two dragging pointers as opposed to use the location of the primary one. private final int mScaledMinPointerDistanceToUseMiddleLocation; + // The handler to which to delegate events. + private EventStreamTransformation mNext; + // Helper class to track received pointers. private final ReceivedPointerTracker mReceivedPointerTracker; @@ -196,7 +198,9 @@ class TouchExplorer extends BaseEventStreamTransformation if (inputSource == InputDevice.SOURCE_TOUCHSCREEN) { clear(); } - super.clearEvents(inputSource); + if (mNext != null) { + mNext.clearEvents(inputSource); + } } @Override @@ -254,9 +258,16 @@ class TouchExplorer extends BaseEventStreamTransformation } @Override + public void setNext(EventStreamTransformation next) { + mNext = next; + } + + @Override public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) { if (!event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN)) { - super.onMotionEvent(event, rawEvent, policyFlags); + if (mNext != null) { + mNext.onMotionEvent(event, rawEvent, policyFlags); + } return; } @@ -300,6 +311,13 @@ class TouchExplorer extends BaseEventStreamTransformation } @Override + public void onKeyEvent(KeyEvent event, int policyFlags) { + if (mNext != null) { + mNext.onKeyEvent(event, policyFlags); + } + } + + @Override public void onAccessibilityEvent(AccessibilityEvent event) { final int eventType = event.getEventType(); @@ -335,7 +353,9 @@ class TouchExplorer extends BaseEventStreamTransformation mLastTouchedWindowId = event.getWindowId(); } break; } - super.onAccessibilityEvent(event); + if (mNext != null) { + mNext.onAccessibilityEvent(event); + } } @Override @@ -949,10 +969,12 @@ class TouchExplorer extends BaseEventStreamTransformation // Make sure that the user will see the event. policyFlags |= WindowManagerPolicy.FLAG_PASS_TO_USER; - // TODO: For now pass null for the raw event since the touch - // explorer is the last event transformation and it does - // not care about the raw event. - super.onMotionEvent(event, null, policyFlags); + if (mNext != null) { + // TODO: For now pass null for the raw event since the touch + // explorer is the last event transformation and it does + // not care about the raw event. + mNext.onMotionEvent(event, null, policyFlags); + } mInjectedPointerTracker.onMotionEvent(event); diff --git a/com/android/server/am/ActivityDisplay.java b/com/android/server/am/ActivityDisplay.java index 6ed05552..8bcbfbef 100644 --- a/com/android/server/am/ActivityDisplay.java +++ b/com/android/server/am/ActivityDisplay.java @@ -16,7 +16,9 @@ package com.android.server.am; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; +import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; +import static android.app.ActivityManager.StackId.INVALID_STACK_ID; +import static android.app.ActivityManager.StackId.getStackIdForWindowingMode; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; @@ -46,14 +48,13 @@ import android.view.Display; import com.android.internal.annotations.VisibleForTesting; import com.android.server.wm.ConfigurationContainer; -import java.io.PrintWriter; import java.util.ArrayList; /** * Exactly one of these classes per Display in the system. Capable of holding zero or more * attached {@link ActivityStack}s. */ -class ActivityDisplay extends ConfigurationContainer<ActivityStack> { +class ActivityDisplay extends ConfigurationContainer { private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityDisplay" : TAG_AM; private static final String TAG_STACK = TAG + POSTFIX_STACK; @@ -67,7 +68,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> { /** All of the stacks on this display. Order matters, topmost stack is in front of all other * stacks, bottommost behind. Accessed directly by ActivityManager package classes */ - private final ArrayList<ActivityStack> mStacks = new ArrayList<>(); + final ArrayList<ActivityStack> mStacks = new ArrayList<>(); /** Array of all UIDs that are present on the display. */ private IntArray mDisplayAccessUIDs = new IntArray(); @@ -79,13 +80,6 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> { private boolean mSleeping; - // Cached reference to some special stacks we tend to get a lot so we don't need to loop - // through the list to find them. - private ActivityStack mHomeStack = null; - private ActivityStack mRecentsStack = null; - private ActivityStack mPinnedStack = null; - private ActivityStack mSplitScreenPrimaryStack = null; - ActivityDisplay(ActivityStackSupervisor supervisor, int displayId) { mSupervisor = supervisor; mDisplayId = displayId; @@ -104,7 +98,6 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> { } if (DEBUG_STACK) Slog.v(TAG_STACK, "addChild: attaching " + stack + " to displayId=" + mDisplayId + " position=" + position); - addStackReferenceIfNeeded(stack); positionChildAt(stack, position); mSupervisor.mService.updateSleepIfNeededLocked(); } @@ -113,7 +106,6 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> { if (DEBUG_STACK) Slog.v(TAG_STACK, "removeChild: detaching " + stack + " from displayId=" + mDisplayId); mStacks.remove(stack); - removeStackReferenceIfNeeded(stack); mSupervisor.mService.updateSleepIfNeededLocked(); } @@ -158,16 +150,6 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> { * @see ConfigurationContainer#isCompatible(int, int) */ <T extends ActivityStack> T getStack(int windowingMode, int activityType) { - if (activityType == ACTIVITY_TYPE_HOME) { - return (T) mHomeStack; - } else if (activityType == ACTIVITY_TYPE_RECENTS) { - return (T) mRecentsStack; - } - if (windowingMode == WINDOWING_MODE_PINNED) { - return (T) mPinnedStack; - } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { - return (T) mSplitScreenPrimaryStack; - } for (int i = mStacks.size() - 1; i >= 0; --i) { final ActivityStack stack = mStacks.get(i); // TODO: Should undefined windowing and activity type be compatible with standard type? @@ -231,14 +213,10 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> { if (windowingMode == WINDOWING_MODE_UNDEFINED) { // TODO: Should be okay to have stacks with with undefined windowing mode long term, but // have to set them to something for now due to logic that depending on them. - windowingMode = getWindowingMode(); // Put in current display's windowing mode - if (windowingMode == WINDOWING_MODE_UNDEFINED) { - // Else fullscreen for now... - windowingMode = WINDOWING_MODE_FULLSCREEN; - } + windowingMode = WINDOWING_MODE_FULLSCREEN; } - final boolean inSplitScreenMode = hasSplitScreenPrimaryStack(); + final boolean inSplitScreenMode = hasSplitScreenStack(); if (!inSplitScreenMode && windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY) { // Switch to fullscreen windowing mode if we are not in split-screen mode and we are @@ -250,7 +228,24 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> { windowingMode = WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; } - final int stackId = mSupervisor.getNextStackId(); + int stackId = INVALID_STACK_ID; + if (mDisplayId == DEFAULT_DISPLAY && (activityType == ACTIVITY_TYPE_STANDARD + || activityType == ACTIVITY_TYPE_UNDEFINED)) { + // TODO: Will be removed once we are no longer using static stack ids. + stackId = getStackIdForWindowingMode(windowingMode); + if (stackId == INVALID_STACK_ID) { + // Whatever...put in fullscreen stack for now. + stackId = FULLSCREEN_WORKSPACE_STACK_ID; + } + final T stack = getStack(stackId); + if (stack != null) { + return stack; + } + } + + if (stackId == INVALID_STACK_ID) { + stackId = mSupervisor.getNextStackId(); + } final T stack = createStackUnchecked(windowingMode, activityType, stackId, onTop); @@ -296,7 +291,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> { if (stack.getWindowingMode() != windowingMode) { continue; } - mSupervisor.removeStack(stack); + mSupervisor.removeStackLocked(stack.mStackId); } } } @@ -311,63 +306,12 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> { for (int i = mStacks.size() - 1; i >= 0; --i) { final ActivityStack stack = mStacks.get(i); if (stack.getActivityType() == activityType) { - mSupervisor.removeStack(stack); + mSupervisor.removeStackLocked(stack.mStackId); } } } } - void onStackWindowingModeChanged(ActivityStack stack) { - removeStackReferenceIfNeeded(stack); - addStackReferenceIfNeeded(stack); - } - - private void addStackReferenceIfNeeded(ActivityStack stack) { - final int activityType = stack.getActivityType(); - final int windowingMode = stack.getWindowingMode(); - - if (activityType == ACTIVITY_TYPE_HOME) { - if (mHomeStack != null && mHomeStack != stack) { - throw new IllegalArgumentException("addStackReferenceIfNeeded: home stack=" - + mHomeStack + " already exist on display=" + this + " stack=" + stack); - } - mHomeStack = stack; - } else if (activityType == ACTIVITY_TYPE_RECENTS) { - if (mRecentsStack != null && mRecentsStack != stack) { - throw new IllegalArgumentException("addStackReferenceIfNeeded: recents stack=" - + mRecentsStack + " already exist on display=" + this + " stack=" + stack); - } - mRecentsStack = stack; - } - if (windowingMode == WINDOWING_MODE_PINNED) { - if (mPinnedStack != null && mPinnedStack != stack) { - throw new IllegalArgumentException("addStackReferenceIfNeeded: pinned stack=" - + mPinnedStack + " already exist on display=" + this - + " stack=" + stack); - } - mPinnedStack = stack; - } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { - if (mSplitScreenPrimaryStack != null && mSplitScreenPrimaryStack != stack) { - throw new IllegalArgumentException("addStackReferenceIfNeeded:" - + " split-screen-primary" + " stack=" + mSplitScreenPrimaryStack - + " already exist on display=" + this + " stack=" + stack); - } - mSplitScreenPrimaryStack = stack; - } - } - - private void removeStackReferenceIfNeeded(ActivityStack stack) { - if (stack == mHomeStack) { - mHomeStack = null; - } else if (stack == mRecentsStack) { - mRecentsStack = null; - } else if (stack == mPinnedStack) { - mPinnedStack = null; - } else if (stack == mSplitScreenPrimaryStack) { - mSplitScreenPrimaryStack = null; - } - } - /** Returns the top visible stack activity type that isn't in the exclude windowing mode. */ int getTopVisibleStackActivityType(int excludeWindowingMode) { for (int i = mStacks.size() - 1; i >= 0; --i) { @@ -382,42 +326,20 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> { return ACTIVITY_TYPE_UNDEFINED; } - /** - * Get the topmost stack on the display. It may be different from focused stack, because - * focus may be on another display. - */ - ActivityStack getTopStack() { - return mStacks.isEmpty() ? null : mStacks.get(mStacks.size() - 1); + ActivityStack getSplitScreenStack() { + return getStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED); } - boolean isTopStack(ActivityStack stack) { - return stack == getTopStack(); - } - - int getIndexOf(ActivityStack stack) { - return mStacks.indexOf(stack); - } - - void onLockTaskPackagesUpdated() { - for (int i = mStacks.size() - 1; i >= 0; --i) { - mStacks.get(i).onLockTaskPackagesUpdated(); - } - } - - ActivityStack getSplitScreenPrimaryStack() { - return mSplitScreenPrimaryStack; - } - - boolean hasSplitScreenPrimaryStack() { - return mSplitScreenPrimaryStack != null; + boolean hasSplitScreenStack() { + return getSplitScreenStack() != null; } PinnedActivityStack getPinnedStack() { - return (PinnedActivityStack) mPinnedStack; + return getStack(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED); } boolean hasPinnedStack() { - return mPinnedStack != null; + return getPinnedStack() != null; } @Override @@ -431,7 +353,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> { } @Override - protected ActivityStack getChildAt(int index) { + protected ConfigurationContainer getChildAt(int index) { return mStacks.get(index); } @@ -479,10 +401,6 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> { mSleeping = asleep; } - public void dump(PrintWriter pw, String prefix) { - pw.println(prefix + "displayId=" + mDisplayId + " mStacks=" + mStacks); - } - public void writeToProto(ProtoOutputStream proto, long fieldId) { final long token = proto.start(fieldId); super.writeToProto(proto, CONFIGURATION_CONTAINER); diff --git a/com/android/server/am/ActivityManagerDebugConfig.java b/com/android/server/am/ActivityManagerDebugConfig.java index ceb2ad62..3a9bf125 100644 --- a/com/android/server/am/ActivityManagerDebugConfig.java +++ b/com/android/server/am/ActivityManagerDebugConfig.java @@ -59,6 +59,7 @@ class ActivityManagerDebugConfig { static final boolean DEBUG_FOCUS = false; static final boolean DEBUG_IDLE = DEBUG_ALL_ACTIVITIES || false; static final boolean DEBUG_IMMERSIVE = DEBUG_ALL || false; + static final boolean DEBUG_LOCKSCREEN = DEBUG_ALL || false; static final boolean DEBUG_LOCKTASK = DEBUG_ALL || false; static final boolean DEBUG_LRU = DEBUG_ALL || false; static final boolean DEBUG_MU = DEBUG_ALL || false; @@ -73,10 +74,10 @@ class ActivityManagerDebugConfig { static final boolean DEBUG_PROVIDER = DEBUG_ALL || false; static final boolean DEBUG_PSS = DEBUG_ALL || false; static final boolean DEBUG_RECENTS = DEBUG_ALL || false; - static final boolean DEBUG_RECENTS_TRIM_TASKS = DEBUG_RECENTS || false; static final boolean DEBUG_RELEASE = DEBUG_ALL_ACTIVITIES || false; static final boolean DEBUG_RESULTS = DEBUG_ALL || false; static final boolean DEBUG_SAVED_STATE = DEBUG_ALL_ACTIVITIES || false; + static final boolean DEBUG_SCREENSHOTS = DEBUG_ALL_ACTIVITIES || false; static final boolean DEBUG_SERVICE = DEBUG_ALL || false; static final boolean DEBUG_FOREGROUND_SERVICE = DEBUG_ALL || false; static final boolean DEBUG_SERVICE_EXECUTING = DEBUG_ALL || false; @@ -84,6 +85,7 @@ class ActivityManagerDebugConfig { static final boolean DEBUG_STATES = DEBUG_ALL_ACTIVITIES || false; static final boolean DEBUG_SWITCH = DEBUG_ALL || false; static final boolean DEBUG_TASKS = DEBUG_ALL || false; + static final boolean DEBUG_THUMBNAILS = DEBUG_ALL || false; static final boolean DEBUG_TRANSITION = DEBUG_ALL || false; static final boolean DEBUG_UID_OBSERVERS = DEBUG_ALL || false; static final boolean DEBUG_URI_PERMISSION = DEBUG_ALL || false; @@ -103,6 +105,7 @@ class ActivityManagerDebugConfig { static final String POSTFIX_FOCUS = (APPEND_CATEGORY_NAME) ? "_Focus" : ""; static final String POSTFIX_IDLE = (APPEND_CATEGORY_NAME) ? "_Idle" : ""; static final String POSTFIX_IMMERSIVE = (APPEND_CATEGORY_NAME) ? "_Immersive" : ""; + static final String POSTFIX_LOCKSCREEN = (APPEND_CATEGORY_NAME) ? "_LockScreen" : ""; static final String POSTFIX_LOCKTASK = (APPEND_CATEGORY_NAME) ? "_LockTask" : ""; static final String POSTFIX_LRU = (APPEND_CATEGORY_NAME) ? "_LRU" : ""; static final String POSTFIX_MU = "_MU"; @@ -119,6 +122,7 @@ class ActivityManagerDebugConfig { static final String POSTFIX_RELEASE = (APPEND_CATEGORY_NAME) ? "_Release" : ""; static final String POSTFIX_RESULTS = (APPEND_CATEGORY_NAME) ? "_Results" : ""; static final String POSTFIX_SAVED_STATE = (APPEND_CATEGORY_NAME) ? "_SavedState" : ""; + static final String POSTFIX_SCREENSHOTS = (APPEND_CATEGORY_NAME) ? "_Screenshots" : ""; static final String POSTFIX_SERVICE = (APPEND_CATEGORY_NAME) ? "_Service" : ""; static final String POSTFIX_SERVICE_EXECUTING = (APPEND_CATEGORY_NAME) ? "_ServiceExecuting" : ""; @@ -126,11 +130,13 @@ class ActivityManagerDebugConfig { static final String POSTFIX_STATES = (APPEND_CATEGORY_NAME) ? "_States" : ""; static final String POSTFIX_SWITCH = (APPEND_CATEGORY_NAME) ? "_Switch" : ""; static final String POSTFIX_TASKS = (APPEND_CATEGORY_NAME) ? "_Tasks" : ""; + static final String POSTFIX_THUMBNAILS = (APPEND_CATEGORY_NAME) ? "_Thumbnails" : ""; static final String POSTFIX_TRANSITION = (APPEND_CATEGORY_NAME) ? "_Transition" : ""; static final String POSTFIX_UID_OBSERVERS = (APPEND_CATEGORY_NAME) ? "_UidObservers" : ""; static final String POSTFIX_URI_PERMISSION = (APPEND_CATEGORY_NAME) ? "_UriPermission" : ""; static final String POSTFIX_USER_LEAVING = (APPEND_CATEGORY_NAME) ? "_UserLeaving" : ""; static final String POSTFIX_VISIBILITY = (APPEND_CATEGORY_NAME) ? "_Visibility" : ""; + static final String POSTFIX_VISIBLE_BEHIND = (APPEND_CATEGORY_NAME) ? "_VisibleBehind" : ""; } diff --git a/com/android/server/am/ActivityManagerService.java b/com/android/server/am/ActivityManagerService.java index f17c9ac3..e6fe6204 100644 --- a/com/android/server/am/ActivityManagerService.java +++ b/com/android/server/am/ActivityManagerService.java @@ -27,10 +27,18 @@ import static android.Manifest.permission.START_TASKS_FROM_RECENTS; import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; import static android.app.ActivityManager.RESIZE_MODE_PRESERVE_WINDOW; +import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; +import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; +import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID; +import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; +import static android.app.ActivityManager.StackId.PINNED_STACK_ID; +import static android.app.ActivityManager.StackId.getWindowingModeForStackId; +import static android.app.ActivityManager.StackId.isStaticStack; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.content.pm.PackageManager.FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS; @@ -49,9 +57,6 @@ import static android.content.res.Configuration.UI_MODE_TYPE_TELEVISION; import static android.net.NetworkPolicyManager.isProcStateAllowedWhileIdleOrPowerSaveMode; import static android.net.NetworkPolicyManager.isProcStateAllowedWhileOnRestrictBackground; import static android.os.Build.VERSION_CODES.N; -import static android.os.IServiceManager.DUMP_PRIORITY_CRITICAL; -import static android.os.IServiceManager.DUMP_PRIORITY_HIGH; -import static android.os.IServiceManager.DUMP_PRIORITY_NORMAL; import static android.os.Process.BLUETOOTH_UID; import static android.os.Process.FIRST_APPLICATION_UID; import static android.os.Process.FIRST_ISOLATED_UID; @@ -132,6 +137,7 @@ import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESSES; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESS_OBSERVERS; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROVIDER; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PSS; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SERVICE; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH; @@ -176,6 +182,7 @@ import static com.android.server.am.TaskRecord.INVALID_TASK_ID; import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK; import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT; import static com.android.server.am.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE; +import static com.android.server.am.proto.ActivityManagerServiceProto.ACTIVITIES; import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_OPEN; import static com.android.server.wm.AppTransition.TRANSIT_NONE; import static com.android.server.wm.AppTransition.TRANSIT_TASK_IN_PLACE; @@ -192,6 +199,7 @@ import android.annotation.UserIdInt; import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManager.RunningTaskInfo; +import android.app.ActivityManager.StackId; import android.app.ActivityManager.StackInfo; import android.app.ActivityManager.TaskSnapshot; import android.app.ActivityManagerInternal; @@ -208,6 +216,7 @@ import android.app.ContentProviderHolder; import android.app.Dialog; import android.app.IActivityController; import android.app.IActivityManager; +import android.app.IAppTask; import android.app.IApplicationThread; import android.app.IInstrumentationWatcher; import android.app.INotificationManager; @@ -395,9 +404,6 @@ import com.android.server.SystemServiceManager; import com.android.server.ThreadPriorityBooster; import com.android.server.Watchdog; import com.android.server.am.ActivityStack.ActivityState; -import com.android.server.am.proto.ActivityManagerServiceProto; -import com.android.server.am.proto.BroadcastProto; -import com.android.server.am.proto.StickyBroadcastProto; import com.android.server.firewall.IntentFirewall; import com.android.server.job.JobSchedulerInternal; import com.android.server.pm.Installer; @@ -733,6 +739,9 @@ public class ActivityManagerService extends IActivityManager.Stub doDump(fd, pw, new String[] {"associations"}); } doDump(fd, pw, new String[] {"processes"}); + doDump(fd, pw, new String[] {"-v", "all"}); + doDump(fd, pw, new String[] {"service", "all"}); + doDump(fd, pw, new String[] {"provider", "all"}); } @Override @@ -744,8 +753,6 @@ public class ActivityManagerService extends IActivityManager.Stub public boolean canShowErrorDialogs() { return mShowDialogs && !mSleeping && !mShuttingDown && !mKeyguardController.isKeyguardShowing(DEFAULT_DISPLAY) - && !mUserController.hasUserRestriction(UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS, - mUserController.getCurrentUserId()) && !(UserManager.isDeviceInDemoMode(mContext) && mUserController.getCurrentUser().isDemo()); } @@ -1710,6 +1717,7 @@ public class ActivityManagerService extends IActivityManager.Stub static final int PUSH_TEMP_WHITELIST_UI_MSG = 68; static final int SERVICE_FOREGROUND_CRASH_MSG = 69; static final int DISPATCH_OOM_ADJ_OBSERVER_MSG = 70; + static final int TOP_APP_KILLED_BY_LMK_MSG = 73; static final int NOTIFY_VR_KEYGUARD_MSG = 74; static final int FIRST_ACTIVITY_STACK_MSG = 100; @@ -1730,6 +1738,9 @@ public class ActivityManagerService extends IActivityManager.Stub */ private boolean mUserIsMonkey; + /** Flag whether the device has a Recents UI */ + boolean mHasRecents; + /** The dimensions of the thumbnails in the Recents UI. */ int mThumbnailWidth; int mThumbnailHeight; @@ -1935,6 +1946,17 @@ public class ActivityManagerService extends IActivityManager.Stub dispatchProcessDied(pid, uid); break; } + case TOP_APP_KILLED_BY_LMK_MSG: { + final String appName = (String) msg.obj; + final AlertDialog d = new BaseErrorDialog(mUiContext); + d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR); + d.setTitle(mUiContext.getText(R.string.top_app_killed_title)); + d.setMessage(mUiContext.getString(R.string.top_app_killed_message, appName)); + d.setButton(DialogInterface.BUTTON_POSITIVE, mUiContext.getText(R.string.close), + obtainMessage(DISMISS_DIALOG_UI_MSG, d)); + d.show(); + break; + } case DISPATCH_UIDS_CHANGED_UI_MSG: { dispatchUidsChanged(); } break; @@ -2089,8 +2111,7 @@ public class ActivityManagerService extends IActivityManager.Stub String text = mContext.getString(R.string.heavy_weight_notification, context.getApplicationInfo().loadLabel(context.getPackageManager())); Notification notification = - new Notification.Builder(context, - SystemNotificationChannels.HEAVY_WEIGHT_APP) + new Notification.Builder(context, SystemNotificationChannels.DEVELOPER) .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb) .setWhen(0) .setOngoing(true) @@ -2124,7 +2145,7 @@ public class ActivityManagerService extends IActivityManager.Stub } try { inm.cancelNotificationWithTag("android", null, - SystemMessage.NOTE_HEAVY_WEIGHT_NOTIFICATION, msg.arg1); + SystemMessage.NOTE_HEAVY_WEIGHT_NOTIFICATION, msg.arg1); } catch (RuntimeException e) { Slog.w(ActivityManagerService.TAG, "Error canceling notification for service", e); @@ -2482,16 +2503,13 @@ public class ActivityManagerService extends IActivityManager.Stub public void setSystemProcess() { try { - ServiceManager.addService(Context.ACTIVITY_SERVICE, this, /* allowIsolated= */ true, - DUMP_PRIORITY_CRITICAL | DUMP_PRIORITY_NORMAL); + ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true); ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats); - ServiceManager.addService("meminfo", new MemBinder(this), /* allowIsolated= */ false, - DUMP_PRIORITY_HIGH | DUMP_PRIORITY_NORMAL); + ServiceManager.addService("meminfo", new MemBinder(this)); ServiceManager.addService("gfxinfo", new GraphicsBinder(this)); ServiceManager.addService("dbinfo", new DbBinder(this)); if (MONITOR_CPU_USAGE) { - ServiceManager.addService("cpuinfo", new CpuBinder(this), - /* allowIsolated= */ false, DUMP_PRIORITY_CRITICAL); + ServiceManager.addService("cpuinfo", new CpuBinder(this)); } ServiceManager.addService("permission", new PermissionController(this)); ServiceManager.addService("processinfo", new ProcessInfoService(this)); @@ -2522,6 +2540,7 @@ public class ActivityManagerService extends IActivityManager.Stub synchronized (this) { mWindowManager = wm; mStackSupervisor.setWindowManager(wm); + mActivityStarter.setWindowManager(wm); mLockTaskController.setWindowManager(wm); } } @@ -2763,9 +2782,8 @@ public class ActivityManagerService extends IActivityManager.Stub mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler); mTaskChangeNotificationController = new TaskChangeNotificationController(this, mStackSupervisor, mHandler); - mActivityStarter = new ActivityStarter(this); + mActivityStarter = new ActivityStarter(this, mStackSupervisor); mRecentTasks = new RecentTasks(this, mStackSupervisor); - mStackSupervisor.setRecentTasks(mRecentTasks); mLockTaskController = new LockTaskController(mContext, mStackSupervisor, mHandler); mProcessCpuThread = new Thread("CpuTracker") { @@ -3223,12 +3241,11 @@ public class ActivityManagerService extends IActivityManager.Stub // stack implementation changes in the future, keep in mind that the use of the fullscreen // stack is a means to move the activity to the main display and a moveActivityToDisplay() // option would be a better choice here. - if (r.requestedVrComponent != null && r.getDisplayId() != DEFAULT_DISPLAY) { + if (r.requestedVrComponent != null && r.getStackId() >= FIRST_DYNAMIC_STACK_ID) { Slog.i(TAG, "Moving " + r.shortComponentName + " from stack " + r.getStackId() + " to main stack for VR"); - final ActivityStack stack = mStackSupervisor.getDefaultDisplay().getOrCreateStack( - WINDOWING_MODE_FULLSCREEN, r.getActivityType(), true /* toTop */); - moveTaskToStack(r.getTask().taskId, stack.mStackId, true /* toTop */); + setTaskWindowingMode(r.getTask().taskId, + WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY, true /* toTop */); } mHandler.sendMessage( mHandler.obtainMessage(VR_MODE_CHANGE_MSG, 0, 0, r)); @@ -5078,12 +5095,11 @@ public class ActivityManagerService extends IActivityManager.Stub } synchronized(this) { - final ProcessRecord proc = mHeavyWeightProcess; - if (proc == null) { + if (mHeavyWeightProcess == null) { return; } - ArrayList<ActivityRecord> activities = new ArrayList<>(proc.activities); + ArrayList<ActivityRecord> activities = new ArrayList<>(mHeavyWeightProcess.activities); for (int i = 0; i < activities.size(); i++) { ActivityRecord r = activities.get(i); if (!r.finishing && r.isInStackLocked()) { @@ -5093,7 +5109,7 @@ public class ActivityManagerService extends IActivityManager.Stub } mHandler.sendMessage(mHandler.obtainMessage(CANCEL_HEAVY_NOTIFICATION_MSG, - proc.userId, 0)); + mHeavyWeightProcess.userId, 0)); mHeavyWeightProcess = null; } } @@ -5412,6 +5428,7 @@ public class ActivityManagerService extends IActivityManager.Stub boolean doLowMem = app.instr == null; boolean doOomAdj = doLowMem; if (!app.killedByAm) { + maybeNotifyTopAppKilled(app); Slog.i(TAG, "Process " + app.processName + " (pid " + pid + ") has died: " + ProcessList.makeOomAdjString(app.setAdj) + ProcessList.makeProcStateString(app.setProcState)); @@ -5445,6 +5462,23 @@ public class ActivityManagerService extends IActivityManager.Stub } } + /** Show system error dialog when a top app is killed by LMK */ + void maybeNotifyTopAppKilled(ProcessRecord app) { + if (!shouldNotifyTopAppKilled(app)) { + return; + } + + Message msg = mHandler.obtainMessage(TOP_APP_KILLED_BY_LMK_MSG); + msg.obj = mContext.getPackageManager().getApplicationLabel(app.info); + mUiHandler.sendMessage(msg); + } + + /** Only show notification when the top app is killed on low ram devices */ + private boolean shouldNotifyTopAppKilled(ProcessRecord app) { + return app.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP && + ActivityManager.isLowRamDeviceStatic(); + } + /** * If a stack trace dump file is configured, dump process stack traces. * @param clearTraces causes the dump file to be erased prior to the new @@ -5929,7 +5963,16 @@ public class ActivityManagerService extends IActivityManager.Stub if (appInfo != null) { forceStopPackageLocked(packageName, appInfo.uid, "clear data"); - mRecentTasks.removeTasksByPackageName(packageName, resolvedUserId); + // Remove all tasks match the cleared application package and user + for (int i = mRecentTasks.size() - 1; i >= 0; i--) { + final TaskRecord tr = mRecentTasks.get(i); + final String taskPackageName = + tr.getBaseIntent().getComponent().getPackageName(); + if (tr.userId != resolvedUserId) continue; + if (!taskPackageName.equals(packageName)) continue; + mStackSupervisor.removeTaskByIdLocked(tr.taskId, false, + REMOVE_FROM_RECENTS); + } } } @@ -6510,7 +6553,7 @@ public class ActivityManagerService extends IActivityManager.Stub } // Clean-up disabled tasks - mRecentTasks.cleanupDisabledPackageTasksLocked(packageName, disabledClasses, userId); + cleanupDisabledPackageTasksLocked(packageName, disabledClasses, userId); // Clean-up disabled services. mServices.bringDownDisabledPackageServicesLocked( @@ -8041,8 +8084,8 @@ public class ActivityManagerService extends IActivityManager.Stub } private boolean isInPictureInPictureMode(ActivityRecord r) { - if (r == null || r.getStack() == null || !r.inPinnedWindowingMode() - || r.getStack().isInStackLocked(r) == null) { + if (r == null || r.getStack() == null || !r.getStack().isPinnedStack() || + r.getStack().isInStackLocked(r) == null) { return false; } @@ -8136,7 +8179,7 @@ public class ActivityManagerService extends IActivityManager.Stub // Only update the saved args from the args that are set r.pictureInPictureArgs.copyOnlySet(params); - if (r.inPinnedWindowingMode()) { + if (r.getStack().getStackId() == PINNED_STACK_ID) { // If the activity is already in picture-in-picture, update the pinned stack now // if it is not already expanding to fullscreen. Otherwise, the arguments will // be used the next time the activity enters PiP @@ -9757,12 +9800,35 @@ public class ActivityManagerService extends IActivityManager.Stub public List<IBinder> getAppTasks(String callingPackage) { int callingUid = Binder.getCallingUid(); long ident = Binder.clearCallingIdentity(); - try { - synchronized(this) { - return mRecentTasks.getAppTasksList(callingUid, callingPackage); + + synchronized(this) { + ArrayList<IBinder> list = new ArrayList<IBinder>(); + try { + if (DEBUG_ALL) Slog.v(TAG, "getAppTasks"); + + final int N = mRecentTasks.size(); + for (int i = 0; i < N; i++) { + TaskRecord tr = mRecentTasks.get(i); + // Skip tasks that do not match the caller. We don't need to verify + // callingPackage, because we are also limiting to callingUid and know + // that will limit to the correct security sandbox. + if (tr.effectiveUid != callingUid) { + continue; + } + Intent intent = tr.getBaseIntent(); + if (intent == null || + !callingPackage.equals(intent.getComponent().getPackageName())) { + continue; + } + ActivityManager.RecentTaskInfo taskInfo = + createRecentTaskInfoFromTaskRecord(tr); + AppTaskImpl taskImpl = new AppTaskImpl(taskInfo.persistentId, callingUid); + list.add(taskImpl.asBinder()); + } + } finally { + Binder.restoreCallingIdentity(ident); } - } finally { - Binder.restoreCallingIdentity(ident); + return list; } } @@ -9785,6 +9851,58 @@ public class ActivityManagerService extends IActivityManager.Stub return list; } + /** + * Creates a new RecentTaskInfo from a TaskRecord. + */ + private ActivityManager.RecentTaskInfo createRecentTaskInfoFromTaskRecord(TaskRecord tr) { + // Update the task description to reflect any changes in the task stack + tr.updateTaskDescription(); + + // Compose the recent task info + ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo(); + rti.id = tr.getTopActivity() == null ? INVALID_TASK_ID : tr.taskId; + rti.persistentId = tr.taskId; + rti.baseIntent = new Intent(tr.getBaseIntent()); + rti.origActivity = tr.origActivity; + rti.realActivity = tr.realActivity; + rti.description = tr.lastDescription; + rti.stackId = tr.getStackId(); + rti.userId = tr.userId; + rti.taskDescription = new ActivityManager.TaskDescription(tr.lastTaskDescription); + rti.firstActiveTime = tr.firstActiveTime; + rti.lastActiveTime = tr.lastActiveTime; + rti.affiliatedTaskId = tr.mAffiliatedTaskId; + rti.affiliatedTaskColor = tr.mAffiliatedTaskColor; + rti.numActivities = 0; + if (tr.mBounds != null) { + rti.bounds = new Rect(tr.mBounds); + } + rti.supportsSplitScreenMultiWindow = tr.supportsSplitScreenWindowingMode(); + rti.resizeMode = tr.mResizeMode; + rti.configuration.setTo(tr.getConfiguration()); + + ActivityRecord base = null; + ActivityRecord top = null; + ActivityRecord tmp; + + for (int i = tr.mActivities.size() - 1; i >= 0; --i) { + tmp = tr.mActivities.get(i); + if (tmp.finishing) { + continue; + } + base = tmp; + if (top == null || (top.state == ActivityState.INITIALIZING)) { + top = base; + } + rti.numActivities++; + } + + rti.baseActivity = (base != null) ? base.intent.getComponent() : null; + rti.topActivity = (top != null) ? top.intent.getComponent() : null; + + return rti; + } + private boolean isGetTasksAllowed(String caller, int callingPid, int callingUid) { boolean allowed = checkPermission(android.Manifest.permission.REAL_GET_TASKS, callingPid, callingUid) == PackageManager.PERMISSION_GRANTED; @@ -9818,15 +9936,118 @@ public class ActivityManagerService extends IActivityManager.Stub final int callingUid = Binder.getCallingUid(); userId = mUserController.handleIncomingUser(Binder.getCallingPid(), callingUid, userId, false, ALLOW_FULL_ONLY, "getRecentTasks", null); - final boolean allowed = isGetTasksAllowed("getRecentTasks", Binder.getCallingPid(), - callingUid); - final boolean detailed = checkCallingPermission( - android.Manifest.permission.GET_DETAILED_TASKS) - == PackageManager.PERMISSION_GRANTED; + final boolean includeProfiles = (flags & ActivityManager.RECENT_INCLUDE_PROFILES) != 0; + final boolean withExcluded = (flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0; synchronized (this) { - return mRecentTasks.getRecentTasks(maxNum, flags, allowed, detailed, userId, + final boolean allowed = isGetTasksAllowed("getRecentTasks", Binder.getCallingPid(), callingUid); + final boolean detailed = checkCallingPermission( + android.Manifest.permission.GET_DETAILED_TASKS) + == PackageManager.PERMISSION_GRANTED; + + if (!isUserRunning(userId, ActivityManager.FLAG_AND_UNLOCKED)) { + Slog.i(TAG, "user " + userId + " is still locked. Cannot load recents"); + return ParceledListSlice.emptyList(); + } + mRecentTasks.loadUserRecentsLocked(userId); + + final int recentsCount = mRecentTasks.size(); + ArrayList<ActivityManager.RecentTaskInfo> res = + new ArrayList<>(maxNum < recentsCount ? maxNum : recentsCount); + + final Set<Integer> includedUsers; + if (includeProfiles) { + includedUsers = mUserController.getProfileIds(userId); + } else { + includedUsers = new HashSet<>(); + } + includedUsers.add(Integer.valueOf(userId)); + + for (int i = 0; i < recentsCount && maxNum > 0; i++) { + TaskRecord tr = mRecentTasks.get(i); + // Only add calling user or related users recent tasks + if (!includedUsers.contains(Integer.valueOf(tr.userId))) { + if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not user: " + tr); + continue; + } + + if (tr.realActivitySuspended) { + if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, activity suspended: " + tr); + continue; + } + + // Return the entry if desired by the caller. We always return + // the first entry, because callers always expect this to be the + // foreground app. We may filter others if the caller has + // not supplied RECENT_WITH_EXCLUDED and there is some reason + // we should exclude the entry. + + if (i == 0 + || withExcluded + || (tr.intent == null) + || ((tr.intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) + == 0)) { + if (!allowed) { + // If the caller doesn't have the GET_TASKS permission, then only + // allow them to see a small subset of tasks -- their own and home. + if (!tr.isActivityTypeHome() && tr.effectiveUid != callingUid) { + if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not allowed: " + tr); + continue; + } + } + final ActivityStack stack = tr.getStack(); + if ((flags & ActivityManager.RECENT_IGNORE_HOME_AND_RECENTS_STACK_TASKS) != 0) { + if (stack != null && stack.isHomeOrRecentsStack()) { + if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, + "Skipping, home or recents stack task: " + tr); + continue; + } + } + if ((flags & ActivityManager.RECENT_INGORE_DOCKED_STACK_TOP_TASK) != 0) { + if (stack != null && stack.isDockedStack() && stack.topTask() == tr) { + if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, + "Skipping, top task in docked stack: " + tr); + continue; + } + } + if ((flags & ActivityManager.RECENT_INGORE_PINNED_STACK_TASKS) != 0) { + if (stack != null && stack.isPinnedStack()) { + if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, + "Skipping, pinned stack task: " + tr); + continue; + } + } + if (tr.autoRemoveRecents && tr.getTopActivity() == null) { + // Don't include auto remove tasks that are finished or finishing. + if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, + "Skipping, auto-remove without activity: " + tr); + continue; + } + if ((flags&ActivityManager.RECENT_IGNORE_UNAVAILABLE) != 0 + && !tr.isAvailable) { + if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, + "Skipping, unavail real act: " + tr); + continue; + } + + if (!tr.mUserSetupComplete) { + // Don't include task launched while user is not done setting-up. + if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, + "Skipping, user setup not complete: " + tr); + continue; + } + + ActivityManager.RecentTaskInfo rti = createRecentTaskInfoFromTaskRecord(tr); + if (!detailed) { + rti.baseIntent.replaceExtras((Bundle)null); + } + + res.add(rti); + maxNum--; + } + } + return new ParceledListSlice<>(res); } } @@ -9898,10 +10119,23 @@ public class ActivityManagerService extends IActivityManager.Stub TaskRecord task = new TaskRecord(this, mStackSupervisor.getNextTaskIdForUserLocked(r.userId), ainfo, intent, description); - if (!mRecentTasks.addToBottom(task)) { + + int trimIdx = mRecentTasks.trimForTaskLocked(task, false); + if (trimIdx >= 0) { + // If this would have caused a trim, then we'll abort because that + // means it would be added at the end of the list but then just removed. return INVALID_TASK_ID; } - r.getStack().addTask(task, !ON_TOP, "addAppTask"); + + final int N = mRecentTasks.size(); + if (N >= (ActivityManager.getMaxRecentTasksStatic()-1)) { + final TaskRecord tr = mRecentTasks.remove(N - 1); + tr.removedFromRecents(); + } + + task.inRecents = true; + mRecentTasks.add(task); + r.getStack().addTask(task, false, "addAppTask"); // TODO: Send the thumbnail to WM to store it. @@ -10117,6 +10351,38 @@ public class ActivityManagerService extends IActivityManager.Stub mWindowManager.executeAppTransition(); } + private void removeTasksByPackageNameLocked(String packageName, int userId) { + // Remove all tasks with activities in the specified package from the list of recent tasks + for (int i = mRecentTasks.size() - 1; i >= 0; i--) { + TaskRecord tr = mRecentTasks.get(i); + if (tr.userId != userId) continue; + + ComponentName cn = tr.intent.getComponent(); + if (cn != null && cn.getPackageName().equals(packageName)) { + // If the package name matches, remove the task. + mStackSupervisor.removeTaskByIdLocked(tr.taskId, true, REMOVE_FROM_RECENTS); + } + } + } + + private void cleanupDisabledPackageTasksLocked(String packageName, Set<String> filterByClasses, + int userId) { + + for (int i = mRecentTasks.size() - 1; i >= 0; i--) { + TaskRecord tr = mRecentTasks.get(i); + if (userId != UserHandle.USER_ALL && tr.userId != userId) { + continue; + } + + ComponentName cn = tr.intent.getComponent(); + final boolean sameComponent = cn != null && cn.getPackageName().equals(packageName) + && (filterByClasses == null || filterByClasses.contains(cn.getClassName())); + if (sameComponent) { + mStackSupervisor.removeTaskByIdLocked(tr.taskId, false, REMOVE_FROM_RECENTS); + } + } + } + @Override public void removeStack(int stackId) { enforceCallingPermission(Manifest.permission.MANAGE_ACTIVITY_STACKS, "removeStack()"); @@ -10124,14 +10390,11 @@ public class ActivityManagerService extends IActivityManager.Stub final long ident = Binder.clearCallingIdentity(); try { final ActivityStack stack = mStackSupervisor.getStack(stackId); - if (stack == null) { - return; - } - if (!stack.isActivityTypeStandardOrUndefined()) { + if (stack != null && !stack.isActivityTypeStandardOrUndefined()) { throw new IllegalArgumentException( "Removing non-standard stack is not allowed."); } - mStackSupervisor.removeStack(stack); + mStackSupervisor.removeStackLocked(stackId); } finally { Binder.restoreCallingIdentity(ident); } @@ -10346,7 +10609,7 @@ public class ActivityManagerService extends IActivityManager.Stub } final ActivityStack stack = r.getStack(); - if (stack == null || !stack.inFreeformWindowingMode()) { + if (stack == null || stack.mStackId != FREEFORM_WORKSPACE_STACK_ID) { throw new IllegalStateException( "exitFreeformMode: You can only go fullscreen from freeform."); } @@ -10414,20 +10677,27 @@ public class ActivityManagerService extends IActivityManager.Stub if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToStack: moving task=" + taskId + " to stackId=" + stackId + " toTop=" + toTop); + if (stackId == DOCKED_STACK_ID) { + mWindowManager.setDockedStackCreateState(DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, + null /* initialBounds */); + } - final ActivityStack stack = mStackSupervisor.getStack(stackId); + ActivityStack stack = mStackSupervisor.getStack(stackId); if (stack == null) { - throw new IllegalStateException( - "moveTaskToStack: No stack for stackId=" + stackId); + if (!isStaticStack(stackId)) { + throw new IllegalStateException( + "moveTaskToStack: No stack for stackId=" + stackId); + } + final ActivityDisplay display = task.getStack().getDisplay(); + final int windowingMode = + getWindowingModeForStackId(stackId, display.hasSplitScreenStack()); + stack = display.getOrCreateStack(windowingMode, + task.getStack().getActivityType(), toTop); } if (!stack.isActivityTypeStandardOrUndefined()) { throw new IllegalArgumentException("moveTaskToStack: Attempt to move task " + taskId + " to stack " + stackId); } - if (stack.inSplitScreenPrimaryWindowingMode()) { - mWindowManager.setDockedStackCreateState( - DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, null /* initialBounds */); - } task.reparent(stack, toTop, REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, !DEFER_RESUME, "moveTaskToStack"); } finally { @@ -10497,9 +10767,9 @@ public class ActivityManagerService extends IActivityManager.Stub try { synchronized (this) { final ActivityStack stack = - mStackSupervisor.getDefaultDisplay().getSplitScreenPrimaryStack(); + mStackSupervisor.getDefaultDisplay().getSplitScreenStack(); if (toTop) { - mStackSupervisor.resizeStackLocked(stack, null /* destBounds */, + mStackSupervisor.resizeStackLocked(stack.mStackId, null /* destBounds */, null /* tempTaskBounds */, null /* tempTaskInsetBounds */, true /* preserveWindows */, true /* allowResizeInDockedMode */, !DEFER_RESUME); @@ -10592,12 +10862,7 @@ public class ActivityManagerService extends IActivityManager.Stub stack.animateResizePinnedStack(null /* sourceHintBounds */, destBounds, animationDuration, false /* fromFullscreen */); } else { - final ActivityStack stack = mStackSupervisor.getStack(stackId); - if (stack == null) { - Slog.w(TAG, "resizeStack: stackId " + stackId + " not found."); - return; - } - mStackSupervisor.resizeStackLocked(stack, destBounds, null /* tempTaskBounds */, + mStackSupervisor.resizeStackLocked(stackId, destBounds, null /* tempTaskBounds */, null /* tempTaskInsetBounds */, preserveWindows, allowResizeInDockedMode, !DEFER_RESUME); } @@ -12673,10 +12938,6 @@ public class ActivityManagerService extends IActivityManager.Stub throw new IllegalArgumentException("Provided bugreport type is not correct, value: " + bugreportType); } - // Always log caller, even if it does not have permission to dump. - String type = extraOptions == null ? "bugreport" : extraOptions; - Slog.i(TAG, type + " requested by UID " + Binder.getCallingUid()); - enforceCallingPermission(android.Manifest.permission.DUMP, "requestBugReport"); if (extraOptions != null) { SystemProperties.set("dumpstate.options", extraOptions); @@ -13884,6 +14145,7 @@ public class ActivityManagerService extends IActivityManager.Stub // Load resources only after the current configuration has been set. final Resources res = mContext.getResources(); + mHasRecents = res.getBoolean(com.android.internal.R.bool.config_hasRecents); mThumbnailWidth = res.getDimensionPixelSize( com.android.internal.R.dimen.thumbnail_width); mThumbnailHeight = res.getDimensionPixelSize( @@ -14842,31 +15104,10 @@ public class ActivityManagerService extends IActivityManager.Stub long origId = Binder.clearCallingIdentity(); if (useProto) { + //TODO: Options when dumping proto final ProtoOutputStream proto = new ProtoOutputStream(fd); - String cmd = opti < args.length ? args[opti] : ""; - opti++; - - if ("activities".equals(cmd) || "a".equals(cmd)) { - // output proto is ActivityStackSupervisorProto - synchronized (this) { - writeActivitiesToProtoLocked(proto); - } - } else if ("broadcasts".equals(cmd) || "b".equals(cmd)) { - // output proto is BroadcastProto - synchronized (this) { - writeBroadcastsToProtoLocked(proto); - } - } else { - // default option, dump everything, output is ActivityManagerServiceProto - synchronized (this) { - long activityToken = proto.start(ActivityManagerServiceProto.ACTIVITIES); - writeActivitiesToProtoLocked(proto); - proto.end(activityToken); - - long broadcastToken = proto.start(ActivityManagerServiceProto.BROADCASTS); - writeBroadcastsToProtoLocked(proto); - proto.end(broadcastToken); - } + synchronized (this) { + writeActivitiesToProtoLocked(proto); } proto.flush(); Binder.restoreCallingIdentity(origId); @@ -14892,9 +15133,7 @@ public class ActivityManagerService extends IActivityManager.Stub } } else if ("recents".equals(cmd) || "r".equals(cmd)) { synchronized (this) { - if (mRecentTasks != null) { - mRecentTasks.dump(pw, true /* dumpAll */, dumpPackage); - } + dumpRecentsLocked(fd, pw, args, opti, true, dumpPackage); } } else if ("broadcasts".equals(cmd) || "b".equals(cmd)) { String[] newArgs; @@ -15115,9 +15354,7 @@ public class ActivityManagerService extends IActivityManager.Stub if (dumpAll) { pw.println("-------------------------------------------------------------------------------"); } - if (mRecentTasks != null) { - mRecentTasks.dump(pw, dumpAll, dumpPackage); - } + dumpRecentsLocked(fd, pw, args, opti, dumpAll, dumpPackage); pw.println(); if (dumpAll) { pw.println("-------------------------------------------------------------------------------"); @@ -15187,9 +15424,7 @@ public class ActivityManagerService extends IActivityManager.Stub if (dumpAll) { pw.println("-------------------------------------------------------------------------------"); } - if (mRecentTasks != null) { - mRecentTasks.dump(pw, dumpAll, dumpPackage); - } + dumpRecentsLocked(fd, pw, args, opti, dumpAll, dumpPackage); pw.println(); if (dumpAll) { pw.println("-------------------------------------------------------------------------------"); @@ -15223,8 +15458,7 @@ public class ActivityManagerService extends IActivityManager.Stub } private void writeActivitiesToProtoLocked(ProtoOutputStream proto) { - // The output proto of "activity --proto activities" is ActivityStackSupervisorProto - mStackSupervisor.writeToProto(proto); + mStackSupervisor.writeToProto(proto, ACTIVITIES); } private void dumpLastANRLocked(PrintWriter pw) { @@ -15276,6 +15510,42 @@ public class ActivityManagerService extends IActivityManager.Stub } } + void dumpRecentsLocked(FileDescriptor fd, PrintWriter pw, String[] args, + int opti, boolean dumpAll, String dumpPackage) { + pw.println("ACTIVITY MANAGER RECENT TASKS (dumpsys activity recents)"); + + boolean printedAnything = false; + + if (mRecentTasks != null && mRecentTasks.size() > 0) { + boolean printedHeader = false; + + final int N = mRecentTasks.size(); + for (int i=0; i<N; i++) { + TaskRecord tr = mRecentTasks.get(i); + if (dumpPackage != null) { + if (tr.realActivity == null || + !dumpPackage.equals(tr.realActivity.getPackageName())) { + continue; + } + } + if (!printedHeader) { + pw.println(" Recent tasks:"); + printedHeader = true; + printedAnything = true; + } + pw.print(" * Recent #"); pw.print(i); pw.print(": "); + pw.println(tr); + if (dumpAll) { + mRecentTasks.get(i).dump(pw, " "); + } + } + } + + if (!printedAnything) { + pw.println(" (nothing)"); + } + } + void dumpAssociationsLocked(FileDescriptor fd, PrintWriter pw, String[] args, int opti, boolean dumpAll, boolean dumpClient, String dumpPackage) { pw.println("ACTIVITY MANAGER ASSOCIATIONS (dumpsys activity associations)"); @@ -16102,40 +16372,6 @@ public class ActivityManagerService extends IActivityManager.Stub } } - void writeBroadcastsToProtoLocked(ProtoOutputStream proto) { - if (mRegisteredReceivers.size() > 0) { - Iterator it = mRegisteredReceivers.values().iterator(); - while (it.hasNext()) { - ReceiverList r = (ReceiverList)it.next(); - r.writeToProto(proto, BroadcastProto.RECEIVER_LIST); - } - } - mReceiverResolver.writeToProto(proto, BroadcastProto.RECEIVER_RESOLVER); - for (BroadcastQueue q : mBroadcastQueues) { - q.writeToProto(proto, BroadcastProto.BROADCAST_QUEUE); - } - for (int user=0; user<mStickyBroadcasts.size(); user++) { - long token = proto.start(BroadcastProto.STICKY_BROADCASTS); - proto.write(StickyBroadcastProto.USER, mStickyBroadcasts.keyAt(user)); - for (Map.Entry<String, ArrayList<Intent>> ent - : mStickyBroadcasts.valueAt(user).entrySet()) { - long actionToken = proto.start(StickyBroadcastProto.ACTIONS); - proto.write(StickyBroadcastProto.StickyAction.NAME, ent.getKey()); - for (Intent intent : ent.getValue()) { - intent.writeToProto(proto, StickyBroadcastProto.StickyAction.INTENTS, - false, true, true, false); - } - proto.end(actionToken); - } - proto.end(token); - } - - long handlerToken = proto.start(BroadcastProto.HANDLER); - proto.write(BroadcastProto.MainHandler.HANDLER, mHandler.toString()); - mHandler.getLooper().writeToProto(proto, BroadcastProto.MainHandler.LOOPER); - proto.end(handlerToken); - } - void dumpBroadcastsLocked(FileDescriptor fd, PrintWriter pw, String[] args, int opti, boolean dumpAll, String dumpPackage) { boolean needSep = false; @@ -19124,7 +19360,7 @@ public class ActivityManagerService extends IActivityManager.Stub // Remove all permissions granted from/to this package removeUriPermissionsForPackageLocked(ssp, userId, true); - mRecentTasks.removeTasksByPackageName(ssp, userId); + removeTasksByPackageNameLocked(ssp, userId); mServices.forceStopPackageLocked(ssp, userId); @@ -20461,10 +20697,9 @@ public class ActivityManagerService extends IActivityManager.Stub /** Helper method that requests bounds from WM and applies them to stack. */ private void resizeStackWithBoundsFromWindowManager(int stackId, boolean deferResume) { final Rect newStackBounds = new Rect(); - final ActivityStack stack = mStackSupervisor.getStack(stackId); - stack.getBoundsForNewConfiguration(newStackBounds); + mStackSupervisor.getStack(stackId).getBoundsForNewConfiguration(newStackBounds); mStackSupervisor.resizeStackLocked( - stack, !newStackBounds.isEmpty() ? newStackBounds : null /* bounds */, + stackId, !newStackBounds.isEmpty() ? newStackBounds : null /* bounds */, null /* tempTaskBounds */, null /* tempTaskInsetBounds */, false /* preserveWindows */, false /* allowResizeInDockedMode */, deferResume); } @@ -24132,6 +24367,125 @@ public class ActivityManagerService extends IActivityManager.Stub } /** + * An implementation of IAppTask, that allows an app to manage its own tasks via + * {@link android.app.ActivityManager.AppTask}. We keep track of the callingUid to ensure that + * only the process that calls getAppTasks() can call the AppTask methods. + */ + class AppTaskImpl extends IAppTask.Stub { + private int mTaskId; + private int mCallingUid; + + public AppTaskImpl(int taskId, int callingUid) { + mTaskId = taskId; + mCallingUid = callingUid; + } + + private void checkCaller() { + if (mCallingUid != Binder.getCallingUid()) { + throw new SecurityException("Caller " + mCallingUid + + " does not match caller of getAppTasks(): " + Binder.getCallingUid()); + } + } + + @Override + public void finishAndRemoveTask() { + checkCaller(); + + synchronized (ActivityManagerService.this) { + long origId = Binder.clearCallingIdentity(); + try { + // We remove the task from recents to preserve backwards + if (!mStackSupervisor.removeTaskByIdLocked(mTaskId, false, + REMOVE_FROM_RECENTS)) { + throw new IllegalArgumentException("Unable to find task ID " + mTaskId); + } + } finally { + Binder.restoreCallingIdentity(origId); + } + } + } + + @Override + public ActivityManager.RecentTaskInfo getTaskInfo() { + checkCaller(); + + synchronized (ActivityManagerService.this) { + long origId = Binder.clearCallingIdentity(); + try { + TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(mTaskId); + if (tr == null) { + throw new IllegalArgumentException("Unable to find task ID " + mTaskId); + } + return createRecentTaskInfoFromTaskRecord(tr); + } finally { + Binder.restoreCallingIdentity(origId); + } + } + } + + @Override + public void moveToFront() { + checkCaller(); + // Will bring task to front if it already has a root activity. + final long origId = Binder.clearCallingIdentity(); + try { + synchronized (this) { + mStackSupervisor.startActivityFromRecentsInner(mTaskId, null); + } + } finally { + Binder.restoreCallingIdentity(origId); + } + } + + @Override + public int startActivity(IBinder whoThread, String callingPackage, + Intent intent, String resolvedType, Bundle bOptions) { + checkCaller(); + + int callingUser = UserHandle.getCallingUserId(); + TaskRecord tr; + IApplicationThread appThread; + synchronized (ActivityManagerService.this) { + tr = mStackSupervisor.anyTaskForIdLocked(mTaskId); + if (tr == null) { + throw new IllegalArgumentException("Unable to find task ID " + mTaskId); + } + appThread = IApplicationThread.Stub.asInterface(whoThread); + if (appThread == null) { + throw new IllegalArgumentException("Bad app thread " + appThread); + } + } + return mActivityStarter.startActivityMayWait(appThread, -1, callingPackage, intent, + resolvedType, null, null, null, null, 0, 0, null, null, + null, bOptions, false, callingUser, tr, "AppTaskImpl"); + } + + @Override + public void setExcludeFromRecents(boolean exclude) { + checkCaller(); + + synchronized (ActivityManagerService.this) { + long origId = Binder.clearCallingIdentity(); + try { + TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(mTaskId); + if (tr == null) { + throw new IllegalArgumentException("Unable to find task ID " + mTaskId); + } + Intent intent = tr.getBaseIntent(); + if (exclude) { + intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + } else { + intent.setFlags(intent.getFlags() + & ~Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + } + } finally { + Binder.restoreCallingIdentity(origId); + } + } + } + } + + /** * Kill processes for the user with id userId and that depend on the package named packageName */ @Override diff --git a/com/android/server/am/ActivityManagerShellCommand.java b/com/android/server/am/ActivityManagerShellCommand.java index f03d2d53..4c934232 100644 --- a/com/android/server/am/ActivityManagerShellCommand.java +++ b/com/android/server/am/ActivityManagerShellCommand.java @@ -73,8 +73,10 @@ import java.util.List; import static android.app.ActivityManager.RESIZE_MODE_SYSTEM; import static android.app.ActivityManager.RESIZE_MODE_USER; +import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; +import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.Display.INVALID_DISPLAY; @@ -84,6 +86,15 @@ final class ActivityManagerShellCommand extends ShellCommand { public static final String NO_CLASS_ERROR_CODE = "Error type 3"; private static final String SHELL_PACKAGE_NAME = "com.android.shell"; + // Is the object moving in a positive direction? + private static final boolean MOVING_FORWARD = true; + // Is the object moving in the horizontal plan? + private static final boolean MOVING_HORIZONTALLY = true; + // Is the object current point great then its target point? + private static final boolean GREATER_THAN_TARGET = true; + // Amount we reduce the stack size by when testing a task re-size. + private static final int STACK_BOUNDS_INSET = 10; + // IPC interface to activity manager -- don't need to do additional security checks. final IActivityManager mInterface; @@ -1933,6 +1944,8 @@ final class ActivityManagerShellCommand extends ShellCommand { return runStackInfo(pw); case "move-top-activity-to-pinned-stack": return runMoveTopActivityToPinnedStack(pw); + case "size-docked-stack-test": + return runStackSizeDockedStackTest(pw); case "remove": return runStackRemove(pw); default: @@ -2130,6 +2143,89 @@ final class ActivityManagerShellCommand extends ShellCommand { return 0; } + int runStackSizeDockedStackTest(PrintWriter pw) throws RemoteException { + final PrintWriter err = getErrPrintWriter(); + final int stepSize = Integer.parseInt(getNextArgRequired()); + final String side = getNextArgRequired(); + final String delayStr = getNextArg(); + final int delayMs = (delayStr != null) ? Integer.parseInt(delayStr) : 0; + + ActivityManager.StackInfo info = mInterface.getStackInfo( + WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED); + if (info == null) { + err.println("Docked stack doesn't exist"); + return -1; + } + if (info.bounds == null) { + err.println("Docked stack doesn't have a bounds"); + return -1; + } + Rect bounds = info.bounds; + + final boolean horizontalGrowth = "l".equals(side) || "r".equals(side); + final int changeSize = (horizontalGrowth ? bounds.width() : bounds.height()) / 2; + int currentPoint; + switch (side) { + case "l": + currentPoint = bounds.left; + break; + case "r": + currentPoint = bounds.right; + break; + case "t": + currentPoint = bounds.top; + break; + case "b": + currentPoint = bounds.bottom; + break; + default: + err.println("Unknown growth side: " + side); + return -1; + } + + final int startPoint = currentPoint; + final int minPoint = currentPoint - changeSize; + final int maxPoint = currentPoint + changeSize; + + int maxChange; + pw.println("Shrinking docked stack side=" + side); + pw.flush(); + while (currentPoint > minPoint) { + maxChange = Math.min(stepSize, currentPoint - minPoint); + currentPoint -= maxChange; + setBoundsSide(bounds, side, currentPoint); + int res = resizeStack(DOCKED_STACK_ID, bounds, delayMs); + if (res < 0) { + return res; + } + } + + pw.println("Growing docked stack side=" + side); + pw.flush(); + while (currentPoint < maxPoint) { + maxChange = Math.min(stepSize, maxPoint - currentPoint); + currentPoint += maxChange; + setBoundsSide(bounds, side, currentPoint); + int res = resizeStack(DOCKED_STACK_ID, bounds, delayMs); + if (res < 0) { + return res; + } + } + + pw.println("Back to Original size side=" + side); + pw.flush(); + while (currentPoint > startPoint) { + maxChange = Math.min(stepSize, currentPoint - startPoint); + currentPoint -= maxChange; + setBoundsSide(bounds, side, currentPoint); + int res = resizeStack(DOCKED_STACK_ID, bounds, delayMs); + if (res < 0) { + return res; + } + } + return 0; + } + void setBoundsSide(Rect bounds, String side, int value) { switch (side) { case "l": @@ -2591,6 +2687,10 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println(" Change docked stack to <LEFT,TOP,RIGHT,BOTTOM>"); pw.println(" and supplying temporary different task bounds indicated by"); pw.println(" <TASK_LEFT,TOP,RIGHT,BOTTOM>"); + pw.println(" size-docked-stack-test: <STEP_SIZE> <l|t|r|b> [DELAY_MS]"); + pw.println(" Test command for sizing docked stack by"); + pw.println(" <STEP_SIZE> increments from the side <l>eft, <t>op, <r>ight, or <b>ottom"); + pw.println(" applying the optional [DELAY_MS] between each step."); pw.println(" move-top-activity-to-pinned-stack: <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>"); pw.println(" Moves the top activity from"); pw.println(" <STACK_ID> to the pinned stack using <LEFT,TOP,RIGHT,BOTTOM> for the"); diff --git a/com/android/server/am/ActivityMetricsLogger.java b/com/android/server/am/ActivityMetricsLogger.java index 93c0f772..fdcb8c69 100644 --- a/com/android/server/am/ActivityMetricsLogger.java +++ b/com/android/server/am/ActivityMetricsLogger.java @@ -5,7 +5,6 @@ import static android.app.ActivityManager.START_TASK_TO_FRONT; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.app.ActivityManagerInternal.APP_TRANSITION_TIMEOUT; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; -import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; @@ -128,7 +127,7 @@ class ActivityMetricsLogger { case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY: mWindowState = WINDOW_STATE_SIDE_BY_SIDE; break; - case WINDOWING_MODE_FREEFORM: + case WINDOW_STATE_FREEFORM: mWindowState = WINDOW_STATE_FREEFORM; break; default: diff --git a/com/android/server/am/ActivityRecord.java b/com/android/server/am/ActivityRecord.java index 2c72a4db..7b0b942a 100644 --- a/com/android/server/am/ActivityRecord.java +++ b/com/android/server/am/ActivityRecord.java @@ -17,7 +17,9 @@ package com.android.server.am; import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; +import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; +import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.app.ActivityManager.TaskDescription.ATTR_TASKDESCRIPTION_PREFIX; import static android.app.ActivityOptions.ANIM_CLIP_REVEAL; import static android.app.ActivityOptions.ANIM_CUSTOM; @@ -58,10 +60,6 @@ import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP; -import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS; -import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT; -import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED; -import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER; import static android.content.pm.ActivityInfo.PERSIST_ACROSS_REBOOTS; import static android.content.pm.ActivityInfo.PERSIST_ROOT_ONLY; import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE; @@ -286,7 +284,6 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo int configChangeFlags; // which config values have changed private boolean keysPaused; // has key dispatching been paused for it? int launchMode; // the launch mode activity attribute. - int lockTaskLaunchMode; // the lockTaskMode manifest attribute, subject to override boolean visible; // does this activity's window need to be shown? boolean visibleIgnoringKeyguard; // is this activity visible, ignoring the fact that Keyguard // might hide this activity? @@ -423,13 +420,9 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo if (iconFilename != null || taskDescription.getLabel() != null || taskDescription.getPrimaryColor() != 0) { pw.print(prefix); pw.print("taskDescription:"); + pw.print(" iconFilename="); pw.print(taskDescription.getIconFilename()); pw.print(" label=\""); pw.print(taskDescription.getLabel()); pw.print("\""); - pw.print(" icon="); pw.print(taskDescription.getInMemoryIcon() != null - ? taskDescription.getInMemoryIcon().getByteCount() + " bytes" - : "null"); - pw.print(" iconResource="); pw.print(taskDescription.getIconResource()); - pw.print(" iconFilename="); pw.print(taskDescription.getIconFilename()); pw.print(" primaryColor="); pw.println(Integer.toHexString(taskDescription.getPrimaryColor())); pw.print(prefix + " backgroundColor="); @@ -439,6 +432,9 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo pw.print(prefix + " navigationBarColor="); pw.println(Integer.toHexString(taskDescription.getNavigationBarColor())); } + if (iconFilename == null && taskDescription.getIcon() != null) { + pw.print(prefix); pw.println("taskDescription contains Bitmap"); + } } if (results != null) { pw.print(prefix); pw.print("results="); pw.println(results); @@ -665,7 +661,8 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo return; } - final boolean inPictureInPictureMode = inPinnedWindowingMode() && targetStackBounds != null; + final boolean inPictureInPictureMode = (task.getStackId() == PINNED_STACK_ID) && + (targetStackBounds != null); if (inPictureInPictureMode != mLastReportedPictureInPictureMode || forceUpdate) { // Picture-in-picture mode changes also trigger a multi-window mode change as well, so // update that here in order @@ -687,6 +684,10 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo } } + boolean isFreeform() { + return task != null && task.getStackId() == FREEFORM_WORKSPACE_STACK_ID; + } + @Override protected int getChildCount() { // {@link ActivityRecord} is a leaf node and has no children. @@ -830,6 +831,23 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo hasBeenLaunched = false; mStackSupervisor = supervisor; + mRotationAnimationHint = aInfo.rotationAnimation; + + if (options != null) { + pendingOptions = options; + mLaunchTaskBehind = pendingOptions.getLaunchTaskBehind(); + + final int rotationAnimation = pendingOptions.getRotationAnimationHint(); + // Only override manifest supplied option if set. + if (rotationAnimation >= 0) { + mRotationAnimationHint = rotationAnimation; + } + PendingIntent usageReport = pendingOptions.getUsageTimeReport(); + if (usageReport != null) { + appTimeTracker = new AppTimeTracker(usageReport); + } + } + // This starts out true, since the initial state of an activity is that we have everything, // and we shouldn't never consider it lacking in state to be removed if it dies. haveState = true; @@ -896,32 +914,6 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo mShowWhenLocked = (aInfo.flags & FLAG_SHOW_WHEN_LOCKED) != 0; mTurnScreenOn = (aInfo.flags & FLAG_TURN_SCREEN_ON) != 0; - - mRotationAnimationHint = aInfo.rotationAnimation; - lockTaskLaunchMode = aInfo.lockTaskLaunchMode; - if (appInfo.isPrivilegedApp() && (lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_ALWAYS - || lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_NEVER)) { - lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_DEFAULT; - } - - if (options != null) { - pendingOptions = options; - mLaunchTaskBehind = options.getLaunchTaskBehind(); - - final int rotationAnimation = pendingOptions.getRotationAnimationHint(); - // Only override manifest supplied option if set. - if (rotationAnimation >= 0) { - mRotationAnimationHint = rotationAnimation; - } - final PendingIntent usageReport = pendingOptions.getUsageTimeReport(); - if (usageReport != null) { - appTimeTracker = new AppTimeTracker(usageReport); - } - final boolean useLockTask = pendingOptions.getLockTaskMode(); - if (useLockTask && lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_DEFAULT) { - lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED; - } - } } AppWindowContainerController getWindowContainerController() { @@ -956,7 +948,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo // update the initial multi-window modes so that the callbacks are scheduled correctly when // the user leaves that mode. mLastReportedMultiWindowMode = !task.mFullscreen; - mLastReportedPictureInPictureMode = inPinnedWindowingMode(); + mLastReportedPictureInPictureMode = (task.getStackId() == PINNED_STACK_ID); } void removeWindowContainer() { @@ -1559,7 +1551,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo // On devices that support leanback only (Android TV), Recents activity can only be // visible if the home stack is the focused stack or we are in split-screen mode. final ActivityDisplay display = getDisplay(); - boolean hasSplitScreenStack = display != null && display.hasSplitScreenPrimaryStack(); + boolean hasSplitScreenStack = display != null && display.hasSplitScreenStack(); isVisible = hasSplitScreenStack || mStackSupervisor.isFocusedStack(getStack()); } @@ -2747,8 +2739,6 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo void setShowWhenLocked(boolean showWhenLocked) { mShowWhenLocked = showWhenLocked; - mStackSupervisor.ensureActivitiesVisibleLocked(null, 0 /* configChanges */, - false /* preserveWindows */); } /** diff --git a/com/android/server/am/ActivityStack.java b/com/android/server/am/ActivityStack.java index f0811dda..1940ca2b 100644 --- a/com/android/server/am/ActivityStack.java +++ b/com/android/server/am/ActivityStack.java @@ -16,25 +16,27 @@ package com.android.server.am; +import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; +import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; +import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; +import static android.app.ActivityManager.StackId.INVALID_STACK_ID; +import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; -import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; -import static android.app.WindowConfiguration.activityTypeToString; -import static android.app.WindowConfiguration.windowingModeToString; import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT; import static android.content.pm.ActivityInfo.FLAG_RESUME_WHILE_PAUSING; import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD; -import static android.view.Display.INVALID_DISPLAY; +import static android.view.Display.INVALID_DISPLAY; import static com.android.server.am.ActivityDisplay.POSITION_BOTTOM; import static com.android.server.am.ActivityDisplay.POSITION_TOP; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ADD_REMOVE; @@ -98,6 +100,7 @@ import static java.lang.Integer.MAX_VALUE; import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManager.RunningTaskInfo; +import android.app.ActivityManager.StackId; import android.app.ActivityOptions; import android.app.AppGlobals; import android.app.IActivityController; @@ -107,7 +110,6 @@ import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.res.Configuration; -import android.graphics.Point; import android.graphics.Rect; import android.net.Uri; import android.os.Binder; @@ -190,6 +192,10 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // finished destroying itself. private static final int DESTROY_TIMEOUT = 10 * 1000; + // How long until we reset a task when the user returns to it. Currently + // disabled. + private static final long ACTIVITY_INACTIVE_RESET_TIME = 0; + // Set to false to disable the preview that is shown while a new activity // is being started. private static final boolean SHOW_APP_STARTING_PREVIEW = true; @@ -346,11 +352,12 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai private final SparseArray<Rect> mTmpBounds = new SparseArray<>(); private final SparseArray<Rect> mTmpInsetBounds = new SparseArray<>(); private final Rect mTmpRect2 = new Rect(); - private final Point mTmpSize = new Point(); /** Run all ActivityStacks through this */ protected final ActivityStackSupervisor mStackSupervisor; + private final LaunchingTaskPositioner mTaskPositioner; + private boolean mTopActivityOccludesKeyguard; private ActivityRecord mTopDismissingKeyguardActivity; @@ -453,6 +460,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai mWindowManager = mService.mWindowManager; mStackId = stackId; mCurrentUser = mService.mUserController.getCurrentUserId(); + mTaskPositioner = mStackId == FREEFORM_WORKSPACE_STACK_ID + ? new LaunchingTaskPositioner() : null; mTmpRect2.setEmpty(); setWindowingMode(windowingMode); setActivityType(activityType); @@ -470,16 +479,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai return mWindowContainerController; } - @Override - public void onConfigurationChanged(Configuration newParentConfig) { - final int prevWindowingMode = getWindowingMode(); - super.onConfigurationChanged(newParentConfig); - final ActivityDisplay display = getDisplay(); - if (display != null && prevWindowingMode != getWindowingMode()) { - display.onStackWindowingModeChanged(this); - } - } - /** Adds the stack to specified display and calls WindowManager to do the same. */ void reparent(ActivityDisplay activityDisplay, boolean onTop) { removeFromDisplay(); @@ -503,11 +502,14 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai mDisplayId = activityDisplay.mDisplayId; mBounds = bounds != null ? new Rect(bounds) : null; mFullscreen = mBounds == null; - + if (mTaskPositioner != null) { + mTaskPositioner.setDisplay(activityDisplay.mDisplay); + mTaskPositioner.configure(mBounds); + } onParentChanged(); activityDisplay.addChild(this, onTop ? POSITION_TOP : POSITION_BOTTOM); - if (inSplitScreenPrimaryWindowingMode()) { + if (mStackId == DOCKED_STACK_ID) { // If we created a docked stack we want to resize it so it resizes all other stacks // in the system. mStackSupervisor.resizeDockedStackLocked( @@ -531,6 +533,9 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai display.removeChild(this); } mDisplayId = INVALID_DISPLAY; + if (mTaskPositioner != null) { + mTaskPositioner.reset(); + } } /** Removes the stack completely. Also calls WindowManager to do the same on its side. */ @@ -634,6 +639,9 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai void setBounds(Rect bounds) { mBounds = mFullscreen ? null : new Rect(bounds); + if (mTaskPositioner != null) { + mTaskPositioner.configure(bounds); + } } ActivityRecord topRunningActivityLocked() { @@ -810,6 +818,14 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai return isActivityTypeHome() || isActivityTypeRecents(); } + final boolean isDockedStack() { + return mStackId == DOCKED_STACK_ID; + } + + final boolean isPinnedStack() { + return mStackId == PINNED_STACK_ID; + } + final boolean isOnHomeDisplay() { return mDisplayId == DEFAULT_DISPLAY; } @@ -1489,9 +1505,9 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai * needed. A stack is considered translucent if it don't contain a visible or * starting (about to be visible) activity that is fullscreen (opaque). * @param starting The currently starting activity or null if there is none. - * @param stackBehind The stack directly behind this one. + * @param stackBehindId The id of the stack directly behind this one. */ - private boolean isStackTranslucent(ActivityRecord starting, ActivityStack stackBehind) { + private boolean isStackTranslucent(ActivityRecord starting, int stackBehindId) { for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { final TaskRecord task = mTaskHistory.get(taskNdx); final ArrayList<ActivityRecord> activities = task.mActivities; @@ -1516,6 +1532,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai return false; } + final ActivityStack stackBehind = mStackSupervisor.getStack(stackBehindId); final boolean stackBehindHomeOrRecent = stackBehind != null && stackBehind.isHomeOrRecentsStack(); if (!isHomeOrRecentsStack() && r.frontOfTask && task.isOverHomeStack() @@ -1536,10 +1553,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai && !mForceHidden; } - boolean isTopStackOnDisplay() { - return getDisplay().isTopStack(this); - } - /** * Returns true if the stack should be visible. * @@ -1550,15 +1563,23 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai return false; } - final ActivityDisplay display = getDisplay(); - if (isTopStackOnDisplay() || mStackSupervisor.isFocusedStack(this)) { + if (mStackSupervisor.isFrontStackOnDisplay(this) || mStackSupervisor.isFocusedStack(this)) { return true; } - final int stackIndex = display.getIndexOf(this); + final ActivityDisplay display = getDisplay(); + final ArrayList<ActivityStack> displayStacks = display.mStacks; + final int stackIndex = displayStacks.indexOf(this); + + if (stackIndex == displayStacks.size() - 1) { + Slog.wtf(TAG, + "Stack=" + this + " isn't front stack but is at the top of the stack list"); + return false; + } // Check position and visibility of this stack relative to the front stack on its display. - final ActivityStack topStack = getDisplay().getTopStack(); + final ActivityStack topStack = getTopStackOnDisplay(); + final int topStackId = topStack.mStackId; final int windowingMode = getWindowingMode(); final int activityType = getActivityType(); @@ -1566,7 +1587,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // If the assistant stack is focused and translucent, then the docked stack is always // visible if (topStack.isActivityTypeAssistant()) { - return topStack.isStackTranslucent(starting, this); + return topStack.isStackTranslucent(starting, DOCKED_STACK_ID); } return true; } @@ -1575,31 +1596,34 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // A case would be if recents stack exists but has no tasks and is below the docked stack // and home stack is below recents if (activityType == ACTIVITY_TYPE_HOME) { - final ActivityStack splitScreenStack = display.getSplitScreenPrimaryStack(); - int dockedStackIndex = display.getIndexOf(splitScreenStack); + final ActivityStack splitScreenStack = display.getStack( + WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED); + int dockedStackIndex = displayStacks.indexOf(splitScreenStack); if (dockedStackIndex > stackIndex && stackIndex != dockedStackIndex - 1) { return false; } } // Find the first stack behind front stack that actually got something visible. - int stackBehindTopIndex = display.getIndexOf(topStack) - 1; + int stackBehindTopIndex = displayStacks.indexOf(topStack) - 1; while (stackBehindTopIndex >= 0 && - display.getChildAt(stackBehindTopIndex).topRunningActivityLocked() == null) { + displayStacks.get(stackBehindTopIndex).topRunningActivityLocked() == null) { stackBehindTopIndex--; } final ActivityStack stackBehindTop = (stackBehindTopIndex >= 0) - ? display.getChildAt(stackBehindTopIndex) : null; + ? displayStacks.get(stackBehindTopIndex) : null; + int stackBehindTopId = INVALID_STACK_ID; int stackBehindTopWindowingMode = WINDOWING_MODE_UNDEFINED; int stackBehindTopActivityType = ACTIVITY_TYPE_UNDEFINED; if (stackBehindTop != null) { + stackBehindTopId = stackBehindTop.mStackId; stackBehindTopWindowingMode = stackBehindTop.getWindowingMode(); stackBehindTopActivityType = stackBehindTop.getActivityType(); } final boolean alwaysOnTop = topStack.getWindowConfiguration().isAlwaysOnTop(); if (topStack.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY || alwaysOnTop) { - if (this == stackBehindTop) { + if (stackIndex == stackBehindTopIndex) { // Stacks directly behind the docked or pinned stack are always visible. return true; } else if (alwaysOnTop && stackIndex == stackBehindTopIndex - 1) { @@ -1608,13 +1632,14 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai if (stackBehindTopWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { return true; } else if (stackBehindTopActivityType == ACTIVITY_TYPE_ASSISTANT) { - return stackBehindTop.isStackTranslucent(starting, this); + return displayStacks.get(stackBehindTopIndex).isStackTranslucent( + starting, mStackId); } } } if (topStack.isBackdropToTranslucentActivity() - && topStack.isStackTranslucent(starting, stackBehindTop)) { + && topStack.isStackTranslucent(starting, stackBehindTopId)) { // Stacks behind the fullscreen or assistant stack with a translucent activity are // always visible so they can act as a backdrop to the translucent activity. // For example, dialog activities @@ -1632,15 +1657,14 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai } } - if (isOnHomeDisplay()) { - // Visibility of any stack on default display should have been determined by the - // conditions above. + if (StackId.isStaticStack(mStackId) + || isHomeOrRecentsStack() || isActivityTypeAssistant()) { + // Visibility of any static stack should have been determined by the conditions above. return false; } - final int stackCount = display.getChildCount(); - for (int i = stackIndex + 1; i < stackCount; i++) { - final ActivityStack stack = display.getChildAt(i); + for (int i = stackIndex + 1; i < displayStacks.size(); i++) { + final ActivityStack stack = displayStacks.get(i); if (!stack.mFullscreen && !stack.hasFullscreenTask()) { continue; @@ -1651,7 +1675,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai return false; } - if (!stack.isStackTranslucent(starting, null /* stackBehind */)) { + if (!stack.isStackTranslucent(starting, INVALID_STACK_ID)) { return false; } } @@ -1777,8 +1801,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai makeInvisible(r); } } - final int windowingMode = getWindowingMode(); - if (windowingMode == WINDOWING_MODE_FREEFORM) { + if (mStackId == FREEFORM_WORKSPACE_STACK_ID) { // The visibility of tasks and the activities they contain in freeform stack are // determined individually unlike other stacks where the visibility or fullscreen // status of an activity in a previous task affects other. @@ -1793,8 +1816,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // show activities in the next application stack behind them vs. another // task in the home stack like recents. behindFullscreenActivity = true; - } else if (windowingMode == WINDOWING_MODE_FULLSCREEN - || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) { + } else if (mStackId == FULLSCREEN_WORKSPACE_STACK_ID) { if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Skipping after task=" + task + " returning to non-application type=" + task.getTaskToReturnTo()); // Once we reach a fullscreen stack task that has a running activity and should @@ -1830,32 +1852,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai } /** - * Returns true if this stack should be resized to match the bounds specified by - * {@link ActivityOptions#setLaunchBounds} when launching an activity into the stack. - */ - boolean resizeStackWithLaunchBounds() { - return inPinnedWindowingMode(); - } - - /** - * Returns true if we try to maintain focus in the current stack when the top activity finishes. - */ - private boolean keepFocusInStackIfPossible() { - final int windowingMode = getWindowingMode(); - return windowingMode == WINDOWING_MODE_FREEFORM - || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY - || windowingMode == WINDOWING_MODE_PINNED; - } - - /** - * Returns true if the top task in the task is allowed to return home when finished and - * there are other tasks in the stack. - */ - boolean allowTopTaskToReturnHome() { - return !inPinnedWindowingMode(); - } - - /** * @return the top most visible activity that wants to dismiss Keyguard */ ActivityRecord getTopDismissingKeyguardActivity() { @@ -1871,7 +1867,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai */ boolean checkKeyguardVisibility(ActivityRecord r, boolean shouldBeVisible, boolean isTop) { - final boolean isInPinnedStack = r.inPinnedWindowingMode(); + final boolean isInPinnedStack = r.getStack().getStackId() == PINNED_STACK_ID; final boolean keyguardShowing = mStackSupervisor.mKeyguardController.isKeyguardShowing( mDisplayId != INVALID_DISPLAY ? mDisplayId : DEFAULT_DISPLAY); final boolean keyguardLocked = mStackSupervisor.mKeyguardController.isKeyguardLocked(); @@ -2169,7 +2165,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai mResumedActivity = r; r.state = ActivityState.RESUMED; mService.setResumedActivityUncheckLocked(r, reason); - mStackSupervisor.mRecentTasks.add(r.getTask()); + mStackSupervisor.addRecentActivity(r); } private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) { @@ -2576,8 +2572,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai Slog.i(TAG, "Restarting because process died: " + next); if (!next.hasBeenLaunched) { next.hasBeenLaunched = true; - } else if (SHOW_APP_STARTING_PREVIEW && lastStack != null - && lastStack.isTopStackOnDisplay()) { + } else if (SHOW_APP_STARTING_PREVIEW && lastStack != null && + mStackSupervisor.isFrontStackOnDisplay(lastStack)) { next.showStartingWindow(null /* prev */, false /* newTask */, false /* taskSwitch */); } @@ -2621,7 +2617,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai private boolean resumeTopActivityInNextFocusableStack(ActivityRecord prev, ActivityOptions options, String reason) { - if (adjustFocusToNextFocusableStackLocked(reason)) { + if ((!mFullscreen || !isOnHomeDisplay()) && adjustFocusToNextFocusableStackLocked(reason)) { // Try to move focus to the next visible stack with a running activity if this // stack is not covering the entire screen or is on a secondary display (with no home // stack). @@ -2750,8 +2746,9 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // make underlying task focused when this one will be finished. int returnToType = isLastTaskOverHome ? task.getTaskToReturnTo() : ACTIVITY_TYPE_STANDARD; - if (fromHomeOrRecents && allowTopTaskToReturnHome()) { - returnToType = topTask == null ? ACTIVITY_TYPE_HOME : topTask.getActivityType(); + if (fromHomeOrRecents && StackId.allowTopTaskToReturnHome(mStackId)) { + returnToType = topTask == null + ? ACTIVITY_TYPE_HOME : topTask.getActivityType(); } task.setTaskToReturnTo(returnToType); } @@ -2904,7 +2901,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // Ensure the caller has requested not to trigger auto-enter PiP return false; } - if (pipCandidate == null || pipCandidate.inPinnedWindowingMode()) { + if (pipCandidate == null || pipCandidate.getStackId() == PINNED_STACK_ID) { // Ensure that we do not trigger entering PiP an activity on the pinned stack return false; } @@ -3189,8 +3186,15 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai final ActivityRecord resetTaskIfNeededLocked(ActivityRecord taskTop, ActivityRecord newActivity) { - final boolean forceReset = + boolean forceReset = (newActivity.info.flags & ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0; + if (ACTIVITY_INACTIVE_RESET_TIME > 0 + && taskTop.getTask().getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) { + if ((newActivity.info.flags & ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) { + forceReset = true; + } + } + final TaskRecord task = taskTop.getTask(); /** False until we evaluate the TaskRecord associated with taskTop. Switches to true @@ -3287,7 +3291,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai final String myReason = reason + " adjustFocus"; if (next != r) { - if (next != null && keepFocusInStackIfPossible() && isFocusable()) { + if (next != null && StackId.keepFocusInStackIfPossible(mStackId) && isFocusable()) { // For freeform, docked, and pinned stacks we always keep the focus within the // stack as long as there is a running activity. return; @@ -3753,7 +3757,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai if (mode == FINISH_IMMEDIATELY || (prevState == ActivityState.PAUSED - && (mode == FINISH_AFTER_PAUSE || inPinnedWindowingMode())) + && (mode == FINISH_AFTER_PAUSE || mStackId == PINNED_STACK_ID)) || finishingActivityInNonFocusedStack || prevState == STOPPING || prevState == STOPPED @@ -4432,7 +4436,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai AppTimeTracker timeTracker, String reason) { if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "moveTaskToFront: " + tr); - final ActivityStack topStack = getDisplay().getTopStack(); + final ActivityStack topStack = getTopStackOnDisplay(); final ActivityRecord topActivity = topStack != null ? topStack.topActivity() : null; final int numTasks = mTaskHistory.size(); final int index = mTaskHistory.indexOf(tr); @@ -4460,9 +4464,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // Don't refocus if invisible to current user final ActivityRecord top = tr.getTopActivity(); if (top == null || !top.okToShowLocked()) { - if (top != null) { - mStackSupervisor.mRecentTasks.add(top.getTask()); - } + mStackSupervisor.addRecentActivity(top); ActivityOptions.abort(options); return; } @@ -4522,7 +4524,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // If we have a watcher, preflight the move before committing to it. First check // for *other* available tasks, but if none are available, then try again allowing the // current task to be selected. - if (isTopStackOnDisplay() && mService.mController != null) { + if (mStackSupervisor.isFrontStackOnDisplay(this) && mService.mController != null) { ActivityRecord next = topRunningActivityLocked(null, taskId); if (next == null) { next = topRunningActivityLocked(null, 0); @@ -4569,8 +4571,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai mWindowContainerController.positionChildAtBottom(tr.getWindowContainerController()); } - if (inPinnedWindowingMode()) { - mStackSupervisor.removeStack(this); + if (mStackId == PINNED_STACK_ID) { + mStackSupervisor.removeStackLocked(PINNED_STACK_ID); return true; } @@ -4602,6 +4604,15 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai return true; } + /** + * Get the topmost stack on the current display. It may be different from focused stack, because + * focus may be on another display. + */ + private ActivityStack getTopStackOnDisplay() { + final ArrayList<ActivityStack> stacks = getDisplay().mStacks; + return stacks.isEmpty() ? null : stacks.get(stacks.size() - 1); + } + static void logStartActivity(int tag, ActivityRecord r, TaskRecord task) { final Uri data = r.intent.getData(); final String strData = data != null ? data.toSafeString() : null; @@ -4676,7 +4687,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai for (int i = mTaskHistory.size() - 1; i >= 0; i--) { final TaskRecord task = mTaskHistory.get(i); if (task.isResizeable()) { - if (inFreeformWindowingMode()) { + if (mStackId == FREEFORM_WORKSPACE_STACK_ID) { // For freeform stack we don't adjust the size of the tasks to match that // of the stack, but we do try to make sure the tasks are still contained // with the bounds of the stack. @@ -4878,7 +4889,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai if (focusedStack && topTask) { // Give the latest time to ensure foreground task can be sorted // at the first, because lastActiveTime of creating task is 0. - ci.lastActiveTime = SystemClock.elapsedRealtime(); + ci.lastActiveTime = System.currentTimeMillis(); topTask = false; } @@ -5058,7 +5069,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai if (task.autoRemoveFromRecents() || isVoiceSession) { // Task creator asked to remove this when done, or this task was a voice // interaction, so it should not remain on the recent tasks list. - mStackSupervisor.mRecentTasks.remove(task); + mStackSupervisor.removeTaskFromRecents(task); } task.removeWindowContainer(); @@ -5086,7 +5097,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai task.setStack(null); // Notify if a task from the pinned stack is being removed (or moved depending on the mode) - if (inPinnedWindowingMode()) { + if (mStackId == PINNED_STACK_ID) { mService.mTaskChangeNotificationController.notifyActivityUnpinned(); } } @@ -5109,12 +5120,10 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai } boolean layoutTaskInStack(TaskRecord task, ActivityInfo.WindowLayout windowLayout) { - if (!task.inFreeformWindowingMode()) { + if (mTaskPositioner == null) { return false; } - mStackSupervisor.getLaunchingTaskPositioner() - .updateDefaultBounds(task, mTaskHistory, windowLayout); - + mTaskPositioner.updateDefaultBounds(task, mTaskHistory, windowLayout); return true; } @@ -5239,12 +5248,10 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai @Override public String toString() { return "ActivityStack{" + Integer.toHexString(System.identityHashCode(this)) - + " stackId=" + mStackId + " type=" + activityTypeToString(getActivityType()) - + " mode=" + windowingModeToString(getWindowingMode()) + ", " - + mTaskHistory.size() + " tasks}"; + + " stackId=" + mStackId + ", " + mTaskHistory.size() + " tasks}"; } - void onLockTaskPackagesUpdated() { + void onLockTaskPackagesUpdatedLocked() { for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { mTaskHistory.get(taskNdx).setLockTaskAuth(); } diff --git a/com/android/server/am/ActivityStackSupervisor.java b/com/android/server/am/ActivityStackSupervisor.java index 5c91e3cc..da2827a6 100644 --- a/com/android/server/am/ActivityStackSupervisor.java +++ b/com/android/server/am/ActivityStackSupervisor.java @@ -21,7 +21,11 @@ import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; import static android.Manifest.permission.START_ANY_ACTIVITY; import static android.Manifest.permission.START_TASKS_FROM_RECENTS; import static android.app.ActivityManager.START_TASK_TO_FRONT; +import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; +import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID; +import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; +import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY; import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SPLIT_SCREEN; import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; @@ -31,13 +35,10 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; -import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; -import static android.app.WindowConfiguration.activityTypeToString; -import static android.app.WindowConfiguration.windowingModeToString; import static android.content.pm.PackageManager.PERMISSION_DENIED; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.PowerManager.PARTIAL_WAKE_LOCK; @@ -46,7 +47,6 @@ import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; import static android.view.Display.TYPE_VIRTUAL; - import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_PICTURE_IN_PICTURE_EXPANDED_TO_FULLSCREEN; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS; @@ -86,13 +86,12 @@ import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV; import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT; import static com.android.server.am.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE; import static com.android.server.am.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT; -import static com.android.server.am.proto.ActivityStackSupervisorProto.CONFIGURATION_CONTAINER; import static com.android.server.am.proto.ActivityStackSupervisorProto.DISPLAYS; import static com.android.server.am.proto.ActivityStackSupervisorProto.FOCUSED_STACK_ID; import static com.android.server.am.proto.ActivityStackSupervisorProto.KEYGUARD_CONTROLLER; import static com.android.server.am.proto.ActivityStackSupervisorProto.RESUMED_ACTIVITY; +import static com.android.server.am.proto.ActivityStackSupervisorProto.CONFIGURATION_CONTAINER; import static com.android.server.wm.AppTransition.TRANSIT_DOCK_TASK_FROM_RECENTS; - import static java.lang.Integer.MAX_VALUE; import android.Manifest; @@ -103,6 +102,7 @@ import android.annotation.UserIdInt; import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManager.RunningTaskInfo; +import android.app.ActivityManager.StackId; import android.app.ActivityManager.StackInfo; import android.app.ActivityManagerInternal.SleepToken; import android.app.ActivityOptions; @@ -176,8 +176,7 @@ import java.util.Iterator; import java.util.List; import java.util.Set; -public class ActivityStackSupervisor extends ConfigurationContainer implements DisplayListener, - RecentTasks.Callbacks { +public class ActivityStackSupervisor extends ConfigurationContainer implements DisplayListener { private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStackSupervisor" : TAG_AM; private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS; private static final String TAG_IDLE = TAG + POSTFIX_IDLE; @@ -287,7 +286,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D final ActivityManagerService mService; - RecentTasks mRecentTasks; + private RecentTasks mRecentTasks; final ActivityStackSupervisorHandler mHandler; @@ -295,10 +294,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D WindowManagerService mWindowManager; DisplayManager mDisplayManager; - LaunchingTaskPositioner mTaskPositioner = new LaunchingTaskPositioner(); - /** Counter for next free stack ID to use for dynamic activity stacks. */ - private int mNextFreeStackId = 0; + private int mNextFreeStackId = FIRST_DYNAMIC_STACK_ID; /** * Maps the task identifier that activities are currently being started in to the userId of the @@ -579,7 +576,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D void setRecentTasks(RecentTasks recentTasks) { mRecentTasks = recentTasks; - mRecentTasks.registerCallback(this); } /** @@ -631,6 +627,15 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return stack != null && stack == mFocusedStack; } + /** The top most stack on its display. */ + boolean isFrontStackOnDisplay(ActivityStack stack) { + return isFrontOfStackList(stack, stack.getDisplay().mStacks); + } + + private boolean isFrontOfStackList(ActivityStack stack, List<ActivityStack> stackList) { + return stack == stackList.get((stackList.size() - 1)); + } + /** NOTE: Should only be called from {@link ActivityStack#moveToFront} */ void setFocusStackUnchecked(String reason, ActivityStack focusCandidate) { if (!focusCandidate.isFocusable()) { @@ -726,9 +731,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D int numDisplays = mActivityDisplays.size(); for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { - final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); + ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + ActivityStack stack = stacks.get(stackNdx); final TaskRecord task = stack.taskForIdLocked(id); if (task != null) { return task; @@ -744,7 +749,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // Otherwise, check the recent tasks and return if we find it there and we are not restoring // the task from recents if (DEBUG_RECENTS) Slog.v(TAG_RECENTS, "Looking for task id=" + id + " in recents"); - final TaskRecord task = mRecentTasks.getTask(id); + final TaskRecord task = mRecentTasks.taskForIdLocked(id); if (task == null) { if (DEBUG_RECENTS) { @@ -771,10 +776,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D ActivityRecord isInAnyStackLocked(IBinder token) { int numDisplays = mActivityDisplays.size(); for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { - final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - final ActivityRecord r = stack.isInStackLocked(token); + ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityRecord r = stacks.get(stackNdx).isInStackLocked(token); if (r != null) { return r; } @@ -812,21 +816,18 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D void lockAllProfileTasks(@UserIdInt int userId) { mWindowManager.deferSurfaceLayout(); try { - for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - final List<TaskRecord> tasks = stack.getAllTasks(); - for (int taskNdx = tasks.size() - 1; taskNdx >= 0; taskNdx--) { - final TaskRecord task = tasks.get(taskNdx); - - // Check the task for a top activity belonging to userId, or returning a - // result to an activity belonging to userId. Example case: a document - // picker for personal files, opened by a work app, should still get locked. - if (taskTopActivityIsUser(task, userId)) { - mService.mTaskChangeNotificationController.notifyTaskProfileLocked( - task.taskId, userId); - } + final List<ActivityStack> stacks = getStacks(); + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; stackNdx--) { + final List<TaskRecord> tasks = stacks.get(stackNdx).getAllTasks(); + for (int taskNdx = tasks.size() - 1; taskNdx >= 0; taskNdx--) { + final TaskRecord task = tasks.get(taskNdx); + + // Check the task for a top activity belonging to userId, or returning a result + // to an activity belonging to userId. Example case: a document picker for + // personal files, opened by a work app, should still get locked. + if (taskTopActivityIsUser(task, userId)) { + mService.mTaskChangeNotificationController.notifyTaskProfileLocked( + task.taskId, userId); } } } @@ -857,7 +858,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // [u*MAX_TASK_IDS_PER_USER, (u+1)*MAX_TASK_IDS_PER_USER-1], so if MAX_TASK_IDS_PER_USER // was 10, user 0 could only have taskIds 0 to 9, user 1: 10 to 19, user 2: 20 to 29, so on. int candidateTaskId = nextTaskIdForUser(currentTaskId, userId); - while (mRecentTasks.containsTaskId(candidateTaskId, userId) + while (mRecentTasks.taskIdTakenForUserLocked(candidateTaskId, userId) || anyTaskForIdLocked( candidateTaskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS) != null) { candidateTaskId = nextTaskIdForUser(candidateTaskId, userId); @@ -892,9 +893,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D final String processName = app.processName; boolean didSomething = false; for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); + ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); if (!isFocusedStack(stack)) { continue; } @@ -927,9 +928,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D boolean allResumedActivitiesIdle() { for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); + ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); if (!isFocusedStack(stack) || stack.numActivities() == 0) { continue; } @@ -948,9 +949,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D boolean allResumedActivitiesComplete() { for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); + ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); if (isFocusedStack(stack)) { final ActivityRecord r = stack.mResumedActivity; if (r != null && r.state != RESUMED) { @@ -967,12 +968,12 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return true; } - private boolean allResumedActivitiesVisible() { + boolean allResumedActivitiesVisible() { boolean foundResumed = false; for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); + ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); final ActivityRecord r = stack.mResumedActivity; if (r != null) { if (!r.nowVisible || mActivitiesWaitingForVisibleActivity.contains(r)) { @@ -996,9 +997,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D boolean pauseBackStacks(boolean userLeaving, ActivityRecord resuming, boolean dontWait) { boolean someActivityPaused = false; for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); + ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); if (!isFocusedStack(stack) && stack.mResumedActivity != null) { if (DEBUG_STATES) Slog.d(TAG_STATES, "pauseBackStacks: stack=" + stack + " mResumedActivity=" + stack.mResumedActivity); @@ -1013,9 +1014,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D boolean allPausedActivitiesComplete() { boolean pausing = true; for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); + ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); final ActivityRecord r = stack.mPausingActivity; if (r != null && r.state != PAUSED && r.state != STOPPED && r.state != STOPPING) { if (DEBUG_STATES) { @@ -1033,10 +1034,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D void cancelInitializingActivities() { for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - stack.cancelInitializingActivities(); + ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + stacks.get(stackNdx).cancelInitializingActivities(); } } } @@ -1134,10 +1134,13 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D for (int i = mTmpOrderedDisplayIds.size() - 1; i >= 0; --i) { final int displayId = mTmpOrderedDisplayIds.get(i); - final ActivityDisplay display = mActivityDisplays.get(displayId); - for (int j = display.getChildCount() - 1; j >= 0; --j) { - final ActivityStack stack = display.getChildAt(j); - if (stack != focusedStack && stack.isTopStackOnDisplay() && stack.isFocusable()) { + final List<ActivityStack> stacks = mActivityDisplays.get(displayId).mStacks; + if (stacks == null) { + continue; + } + for (int j = stacks.size() - 1; j >= 0; --j) { + final ActivityStack stack = stacks.get(j); + if (stack != focusedStack && isFrontStackOnDisplay(stack) && stack.isFocusable()) { r = stack.topRunningActivityLocked(); if (r != null) { return r; @@ -1153,9 +1156,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D ArrayList<ArrayList<RunningTaskInfo>> runningTaskLists = new ArrayList<>(); final int numDisplays = mActivityDisplays.size(); for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { - final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); + ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); ArrayList<RunningTaskInfo> stackTaskList = new ArrayList<>(); runningTaskLists.add(stackTaskList); stack.getTasksLocked(stackTaskList, callingUid, allowed); @@ -1604,16 +1607,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D Slog.w(TAG, msg); throw new SecurityException(msg); } - // Check if someone tries to launch an unwhitelisted activity into LockTask mode. - final boolean lockTaskMode = options.getLockTaskMode(); - if (lockTaskMode && !mService.mLockTaskController.isPackageWhitelisted( - UserHandle.getUserId(callingUid), aInfo.packageName)) { - final String msg = "Permission Denial: starting " + intent.toString() - + " from " + callerApp + " (pid=" + callingPid - + ", uid=" + callingUid + ") with lockTaskMode=true"; - Slog.w(TAG, msg); - throw new SecurityException(msg); - } } return true; @@ -1935,10 +1928,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D boolean handleAppDiedLocked(ProcessRecord app) { boolean hasVisibleActivities = false; for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - hasVisibleActivities |= stack.handleAppDiedLocked(app); + final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + hasVisibleActivities |= stacks.get(stackNdx).handleAppDiedLocked(app); } } return hasVisibleActivities; @@ -1946,10 +1938,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D void closeSystemDialogsLocked() { for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - stack.closeSystemDialogsLocked(); + final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + stacks.get(stackNdx).closeSystemDialogsLocked(); } } } @@ -1975,9 +1966,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D boolean doit, boolean evenPersistent, int userId) { boolean didSomething = false; for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); + final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); if (stack.finishDisabledPackageActivitiesLocked( packageName, filterByClasses, doit, evenPersistent, userId)) { didSomething = true; @@ -1997,9 +1988,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // hosted by the process that is actually still the foreground. ProcessRecord fgApp = null; for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); + final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); if (isFocusedStack(stack)) { if (stack.mResumedActivity != null) { fgApp = stack.mResumedActivity.app; @@ -2049,10 +2040,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D void updateActivityApplicationInfoLocked(ApplicationInfo aInfo) { for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - stack.updateActivityApplicationInfoLocked(aInfo); + final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + stacks.get(stackNdx).updateActivityApplicationInfoLocked(aInfo); } } } @@ -2061,10 +2051,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D TaskRecord finishedTask = null; ActivityStack focusedStack = getFocusedStack(); for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); - final int numStacks = display.getChildCount(); + final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + final int numStacks = stacks.size(); for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); + final ActivityStack stack = stacks.get(stackNdx); TaskRecord t = stack.finishTopRunningActivityLocked(app, reason); if (stack == focusedStack || finishedTask == null) { finishedTask = t; @@ -2076,10 +2066,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D void finishVoiceTask(IVoiceInteractionSession session) { for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); - final int numStacks = display.getChildCount(); + final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + final int numStacks = stacks.size(); for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); + final ActivityStack stack = stacks.get(stackNdx); stack.finishVoiceTask(session); } } @@ -2115,8 +2105,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // moveTaskToStackUncheckedLocked() should already placed the task on top, // still need moveTaskToFrontLocked() below for any transition settings. } - if (stack.resizeStackWithLaunchBounds()) { - resizeStackLocked(stack, bounds, null /* tempTaskBounds */, + if (StackId.resizeStackWithLaunchBounds(stack.mStackId)) { + resizeStackLocked(stack.mStackId, bounds, null /* tempTaskBounds */, null /* tempTaskInsetBounds */, !PRESERVE_WINDOWS, true /* allowResizeInDockedMode */, !DEFER_RESUME); } else { @@ -2135,7 +2125,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D "findTaskToMoveToFront: moved to front of stack=" + currentStack); handleNonResizableTaskIfNeeded(task, WINDOWING_MODE_UNDEFINED, DEFAULT_DISPLAY, - currentStack, forceNonResizeable); + currentStack.mStackId, forceNonResizeable); } boolean canUseActivityOptionsLaunchBounds(ActivityOptions options) { @@ -2149,10 +2139,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D || mService.mSupportsFreeformWindowManagement; } - LaunchingTaskPositioner getLaunchingTaskPositioner() { - return mTaskPositioner; - } - protected <T extends ActivityStack> T getStack(int stackId) { for (int i = mActivityDisplays.size() - 1; i >= 0; --i) { final T stack = mActivityDisplays.valueAt(i).getStack(stackId); @@ -2330,8 +2316,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } final ActivityDisplay display = getActivityDisplayOrCreateLocked(displayId); if (display != null) { - for (int i = display.getChildCount() - 1; i >= 0; --i) { - stack = (T) display.getChildAt(i); + for (int i = display.mStacks.size() - 1; i >= 0; --i) { + stack = (T) display.mStacks.get(i); if (stack.isCompatible(windowingMode, activityType)) { return stack; } @@ -2399,8 +2385,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } // Return the topmost valid stack on the display. - for (int i = activityDisplay.getChildCount() - 1; i >= 0; --i) { - final ActivityStack stack = activityDisplay.getChildAt(i); + for (int i = activityDisplay.mStacks.size() - 1; i >= 0; --i) { + final ActivityStack stack = activityDisplay.mStacks.get(i); if (isValidLaunchStack(stack, displayId, r)) { return stack; } @@ -2431,13 +2417,25 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY: return r.supportsSplitScreenWindowingMode(); } - if (!stack.isOnHomeDisplay()) { + if (StackId.isDynamicStack(stack.mStackId)) { return r.canBeLaunchedOnDisplay(displayId); } Slog.e(TAG, "isValidLaunchStack: Unexpected stack=" + stack); return false; } + ArrayList<ActivityStack> getStacks() { + ArrayList<ActivityStack> allStacks = new ArrayList<>(); + for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { + allStacks.addAll(mActivityDisplays.valueAt(displayNdx).mStacks); + } + return allStacks; + } + + ArrayList<ActivityStack> getStacksOnDefaultDisplay() { + return mActivityDisplays.valueAt(DEFAULT_DISPLAY).mStacks; + } + /** * Get next focusable stack in the system. This will search across displays and stacks * in last-focused order for a focusable and visible stack, different from the target stack. @@ -2452,9 +2450,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D for (int i = mTmpOrderedDisplayIds.size() - 1; i >= 0; --i) { final int displayId = mTmpOrderedDisplayIds.get(i); // If a display is registered in WM, it must also be available in AM. - final ActivityDisplay display = getActivityDisplayOrCreateLocked(displayId); - for (int j = display.getChildCount() - 1; j >= 0; --j) { - final ActivityStack stack = display.getChildAt(j); + @SuppressWarnings("ConstantConditions") + final List<ActivityStack> stacks = getActivityDisplayOrCreateLocked(displayId).mStacks; + for (int j = stacks.size() - 1; j >= 0; --j) { + final ActivityStack stack = stacks.get(j); if (stack != currentFocus && stack.isFocusable() && stack.shouldBeVisible(null)) { return stack; @@ -2512,17 +2511,20 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return null; } - void resizeStackLocked(ActivityStack stack, Rect bounds, Rect tempTaskBounds, - Rect tempTaskInsetBounds, boolean preserveWindows, boolean allowResizeInDockedMode, - boolean deferResume) { - - if (stack.inSplitScreenPrimaryWindowingMode()) { + void resizeStackLocked(int stackId, Rect bounds, Rect tempTaskBounds, Rect tempTaskInsetBounds, + boolean preserveWindows, boolean allowResizeInDockedMode, boolean deferResume) { + if (stackId == DOCKED_STACK_ID) { resizeDockedStackLocked(bounds, tempTaskBounds, tempTaskInsetBounds, null, null, preserveWindows, deferResume); return; } + final ActivityStack stack = getStack(stackId); + if (stack == null) { + Slog.w(TAG, "resizeStack: stackId " + stackId + " not found."); + return; + } - final boolean splitScreenActive = getDefaultDisplay().hasSplitScreenPrimaryStack(); + final boolean splitScreenActive = getDefaultDisplay().hasSplitScreenStack(); if (!allowResizeInDockedMode && !stack.getWindowConfiguration().tasksAreFloating() && splitScreenActive) { // If the docked stack exists, don't resize non-floating stacks independently of the @@ -2530,7 +2532,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return; } - Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeStack_" + stack.mStackId); + Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeStack_" + stackId); mWindowManager.deferSurfaceLayout(); try { if (stack.supportsSplitScreenWindowingMode()) { @@ -2582,7 +2584,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D /** * TODO: This should just change the windowing mode and resize vs. actually moving task around. - * Can do that once we are no longer using static stack ids. + * Can do that once we are no longer using static stack ids. Specially when + * {@link ActivityManager.StackId#FULLSCREEN_WORKSPACE_STACK_ID} is removed. */ private void moveTasksToFullscreenStackInSurfaceTransaction(ActivityStack fromStack, int toDisplayId, boolean onTop) { @@ -2597,12 +2600,13 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // We are moving all tasks from the docked stack to the fullscreen stack, // which is dismissing the docked stack, so resize all other stacks to // fullscreen here already so we don't end up with resize trashing. - for (int i = toDisplay.getChildCount() - 1; i >= 0; --i) { - final ActivityStack otherStack = toDisplay.getChildAt(i); + final ArrayList<ActivityStack> displayStacks = toDisplay.mStacks; + for (int i = displayStacks.size() - 1; i >= 0; --i) { + final ActivityStack otherStack = displayStacks.get(i); if (!otherStack.inSplitScreenSecondaryWindowingMode()) { continue; } - resizeStackLocked(otherStack, null, null, null, PRESERVE_WINDOWS, + resizeStackLocked(otherStack.mStackId, null, null, null, PRESERVE_WINDOWS, true /* allowResizeInDockedMode */, DEFER_RESUME); } @@ -2693,7 +2697,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return; } - final ActivityStack stack = getDefaultDisplay().getSplitScreenPrimaryStack(); + final ActivityStack stack = getDefaultDisplay().getStack( + WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED); if (stack == null) { Slog.w(TAG, "resizeDockedStackLocked: docked stack not found"); return; @@ -2722,10 +2727,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // static stacks need to be adjusted so they don't overlap with the docked stack. // We get the bounds to use from window manager which has been adjusted for any // screen controls and is also the same for all stacks. - final ActivityDisplay display = getDefaultDisplay(); + final ArrayList<ActivityStack> stacks = getStacksOnDefaultDisplay(); final Rect otherTaskRect = new Rect(); - for (int i = display.getChildCount() - 1; i >= 0; --i) { - final ActivityStack current = display.getChildAt(i); + for (int i = stacks.size() - 1; i >= 0; --i) { + final ActivityStack current = stacks.get(i); if (current.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { continue; } @@ -2739,7 +2744,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D tempRect /* outStackBounds */, otherTaskRect /* outTempTaskBounds */, true /* ignoreVisibility */); - resizeStackLocked(current, !tempRect.isEmpty() ? tempRect : null, + resizeStackLocked(current.mStackId, !tempRect.isEmpty() ? tempRect : null, !otherTaskRect.isEmpty() ? otherTaskRect : tempOtherTaskBounds, tempOtherTaskInsetBounds, preserveWindows, true /* allowResizeInDockedMode */, deferResume); @@ -2757,7 +2762,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D void resizePinnedStackLocked(Rect pinnedBounds, Rect tempPinnedTaskBounds) { // TODO(multi-display): Pinned stack display should be passed in. - final PinnedActivityStack stack = getDefaultDisplay().getPinnedStack(); + final PinnedActivityStack stack = getDefaultDisplay().getStack( + WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED); if (stack == null) { Slog.w(TAG, "resizePinnedStackLocked: pinned stack not found"); return; @@ -2795,7 +2801,12 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } } - private void removeStackInSurfaceTransaction(ActivityStack stack) { + private void removeStackInSurfaceTransaction(int stackId) { + final ActivityStack stack = getStack(stackId); + if (stack == null) { + return; + } + final ArrayList<TaskRecord> tasks = stack.getAllTasks(); if (stack.getWindowingMode() == WINDOWING_MODE_PINNED) { /** @@ -2825,12 +2836,12 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } /** - * Removes the stack associated with the given {@param stack}. If the {@param stack} is the + * Removes the stack associated with the given {@param stackId}. If the {@param stackId} is the * pinned stack, then its tasks are not explicitly removed when the stack is destroyed, but * instead moved back onto the fullscreen stack. */ - void removeStack(ActivityStack stack) { - mWindowManager.inSurfaceTransaction(() -> removeStackInSurfaceTransaction(stack)); + void removeStackLocked(int stackId) { + mWindowManager.inSurfaceTransaction(() -> removeStackInSurfaceTransaction(stackId)); } /** @@ -2881,9 +2892,23 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return false; } + void addRecentActivity(ActivityRecord r) { + if (r == null) { + return; + } + final TaskRecord task = r.getTask(); + mRecentTasks.addLocked(task); + task.touchActiveTime(); + } + + void removeTaskFromRecents(TaskRecord task) { + mRecentTasks.remove(task); + task.removedFromRecents(); + } + void cleanUpRemovedTaskLocked(TaskRecord tr, boolean killProcess, boolean removeFromRecents) { if (removeFromRecents) { - mRecentTasks.remove(tr); + removeTaskFromRecents(tr); } ComponentName component = tr.getBaseIntent().getComponent(); if (component == null) { @@ -2954,7 +2979,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D int getNextStackId() { while (true) { - if (getStack(mNextFreeStackId) == null) { + if (mNextFreeStackId >= FIRST_DYNAMIC_STACK_ID + && getStack(mNextFreeStackId) == null) { break; } mNextFreeStackId++; @@ -2963,8 +2989,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } /** - * Called to restore the state of the task into the stack that it's supposed to go into. - * + * Restores a recent task to a stack * @param task The recent task to be restored. * @param aOptions The activity options to use for restoration. * @return true if the task has been restored successfully. @@ -2995,22 +3020,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return true; } - @Override - public void onRecentTaskAdded(TaskRecord task) { - task.touchActiveTime(); - } - - @Override - public void onRecentTaskRemoved(TaskRecord task, boolean wasTrimmed) { - if (wasTrimmed) { - // Task was trimmed from the recent tasks list -- remove the active task record as well - // since the user won't really be able to go back to it - removeTaskByIdLocked(task.taskId, false /* killProcess */, - false /* removeFromRecents */); - } - task.removedFromRecents(); - } - /** * Move stack with all its existing content to specified display. * @param stackId Id of stack to move. @@ -3151,7 +3160,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // Resize the pinned stack to match the current size of the task the activity we are // going to be moving is currently contained in. We do this to have the right starting // animation bounds for the pinned stack to the desired bounds the caller wants. - resizeStackLocked(stack, task.mBounds, null /* tempTaskBounds */, + resizeStackLocked(PINNED_STACK_ID, task.mBounds, null /* tempTaskBounds */, null /* tempTaskInsetBounds */, !PRESERVE_WINDOWS, true /* allowResizeInDockedMode */, !DEFER_RESUME); @@ -3248,9 +3257,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D ActivityRecord affinityMatch = null; if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + r); for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); + final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); if (!r.hasCompatibleActivityType(stack)) { if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping stack: (mismatch activity/stack) " + stack); @@ -3283,13 +3292,12 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } ActivityRecord findActivityLocked(Intent intent, ActivityInfo info, - boolean compareIntentFilters) { + boolean compareIntentFilters) { for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - final ActivityRecord ar = stack.findActivityLocked( - intent, info, compareIntentFilters); + final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityRecord ar = stacks.get(stackNdx) + .findActivityLocked(intent, info, compareIntentFilters); if (ar != null) { return ar; } @@ -3383,8 +3391,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } // Set the sleeping state of the stacks on the display. - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); + final ArrayList<ActivityStack> stacks = display.mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); if (displayShouldSleep) { stack.goToSleepIfPossible(false /* shuttingDown */); } else { @@ -3446,13 +3455,12 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D private boolean putStacksToSleepLocked(boolean allowDelay, boolean shuttingDown) { boolean allSleep = true; for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); + final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { if (allowDelay) { - allSleep &= stack.goToSleepIfPossible(shuttingDown); + allSleep &= stacks.get(stackNdx).goToSleepIfPossible(shuttingDown); } else { - stack.goToSleep(); + stacks.get(stackNdx).goToSleep(); } } } @@ -3477,10 +3485,11 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D void handleAppCrashLocked(ProcessRecord app) { for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - stack.handleAppCrashLocked(app); + final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + int stackNdx = stacks.size() - 1; + while (stackNdx >= 0) { + stacks.get(stackNdx).handleAppCrashLocked(app); + stackNdx--; } } } @@ -3491,7 +3500,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D final ActivityStack stack = task.getStack(); r.mLaunchTaskBehind = false; - mRecentTasks.add(task); + mRecentTasks.addLocked(task); mService.mTaskChangeNotificationController.notifyTaskStackChanged(); r.setVisibility(false); @@ -3513,9 +3522,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D try { // First the front stacks. In case any are not fullscreen and are in front of home. for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); + final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + final int topStackNdx = stacks.size() - 1; + for (int stackNdx = topStackNdx; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); stack.ensureActivitiesVisibleLocked(starting, configChanges, preserveWindows); } } @@ -3526,9 +3536,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D void addStartingWindowsForVisibleActivities(boolean taskSwitch) { for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); + final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + final int topStackNdx = stacks.size() - 1; + for (int stackNdx = topStackNdx; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); stack.addStartingWindowsForVisibleActivities(taskSwitch); } } @@ -3544,20 +3555,20 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } mTaskLayersChanged = false; for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); displayNdx++) { - final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); + final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; int baseLayer = 0; - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - baseLayer += stack.rankTaskLayers(baseLayer); + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + baseLayer += stacks.get(stackNdx).rankTaskLayers(baseLayer); } } } void clearOtherAppTimeTrackers(AppTimeTracker except) { for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); + final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + final int topStackNdx = stacks.size() - 1; + for (int stackNdx = topStackNdx; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); stack.clearOtherAppTimeTrackers(except); } } @@ -3565,9 +3576,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D void scheduleDestroyAllActivities(ProcessRecord app, String reason) { for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); + final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + final int numStacks = stacks.size(); + for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); stack.scheduleDestroyActivities(app, reason); } } @@ -3619,11 +3631,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // let's iterate through the tasks and release the oldest one. final int numDisplays = mActivityDisplays.size(); for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { - final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); - final int stackCount = display.getChildCount(); + final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; // Step through all stacks starting from behind, to hit the oldest things first. - for (int stackNdx = 0; stackNdx < stackCount; stackNdx++) { - final ActivityStack stack = display.getChildAt(stackNdx); + for (int stackNdx = 0; stackNdx < stacks.size(); stackNdx++) { + final ActivityStack stack = stacks.get(stackNdx); // Try to release activities in this stack; if we manage to, we are done. if (stack.releaseSomeActivitiesLocked(app, tasks, reason) > 0) { return; @@ -3635,14 +3646,14 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D boolean switchUserLocked(int userId, UserState uss) { final int focusStackId = mFocusedStack.getStackId(); // We dismiss the docked stack whenever we switch users. - final ActivityStack dockedStack = getDefaultDisplay().getSplitScreenPrimaryStack(); + final ActivityStack dockedStack = getDefaultDisplay().getSplitScreenStack(); if (dockedStack != null) { moveTasksToFullscreenStackLocked(dockedStack, mFocusedStack == dockedStack); } // Also dismiss the pinned stack whenever we switch users. Removing the pinned stack will // also cause all tasks to be moved to the fullscreen stack at a position that is // appropriate. - removeStacksInWindowingModes(WINDOWING_MODE_PINNED); + removeStackLocked(PINNED_STACK_ID); mUserStackInFront.put(mCurrentUser, focusStackId); final int restoreStackId = mUserStackInFront.get(userId, mHomeStack.mStackId); @@ -3650,9 +3661,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D mStartingUsers.add(uss); for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); + final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); stack.switchUserLocked(userId); TaskRecord task = stack.topTask(); if (task != null) { @@ -3750,9 +3761,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D void validateTopActivitiesLocked() { for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); + final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); final ActivityRecord r = stack.topRunningActivityLocked(); final ActivityState state = r == null ? DESTROYED : r.state; if (isFocusedStack(stack)) { @@ -3787,7 +3798,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D pw.print(prefix); pw.println("mUserStackInFront=" + mUserStackInFront); for (int i = mActivityDisplays.size() - 1; i >= 0; --i) { final ActivityDisplay display = mActivityDisplays.valueAt(i); - display.dump(pw, prefix); + pw.println(prefix + "displayId=" + display.mDisplayId + " mStacks=" + display.mStacks); } if (!mWaitingForActivityVisible.isEmpty()) { pw.print(prefix); pw.println("mWaitingForActivityVisible="); @@ -3800,7 +3811,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D mService.mLockTaskController.dump(pw, prefix); } - public void writeToProto(ProtoOutputStream proto) { + public void writeToProto(ProtoOutputStream proto, long fieldId) { + final long token = proto.start(fieldId); super.writeToProto(proto, CONFIGURATION_CONTAINER); for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); ++displayNdx) { ActivityDisplay activityDisplay = mActivityDisplays.valueAt(displayNdx); @@ -3816,6 +3828,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } else { proto.write(FOCUSED_STACK_ID, INVALID_STACK_ID); } + proto.end(token); } /** @@ -3844,9 +3857,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D ArrayList<ActivityRecord> activities = new ArrayList<>(); int numDisplays = mActivityDisplays.size(); for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { - final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); + ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + ActivityStack stack = stacks.get(stackNdx); if (!dumpVisibleStacksOnly || stack.shouldBeVisible(null)) { activities.addAll(stack.getDumpActivitiesLocked(name)); } @@ -3879,13 +3892,11 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D ActivityDisplay activityDisplay = mActivityDisplays.valueAt(displayNdx); pw.print("Display #"); pw.print(activityDisplay.mDisplayId); pw.println(" (activities from top to bottom):"); - final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); + ArrayList<ActivityStack> stacks = activityDisplay.mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); pw.println(); - pw.println(" Stack #" + stack.mStackId - + ": type=" + activityTypeToString(stack.getActivityType()) - + " mode=" + windowingModeToString(stack.getWindowingMode())); + pw.println(" Stack #" + stack.mStackId + ":"); pw.println(" mFullscreen=" + stack.mFullscreen); pw.println(" isSleeping=" + stack.shouldSleepActivities()); pw.println(" mBounds=" + stack.mBounds); @@ -4129,29 +4140,30 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } synchronized (mService) { - final ActivityDisplay activityDisplay = mActivityDisplays.get(displayId); - if (activityDisplay == null) { - return; - } - final boolean destroyContentOnRemoval - = activityDisplay.shouldDestroyContentOnRemove(); - while (activityDisplay.getChildCount() > 0) { - final ActivityStack stack = activityDisplay.getChildAt(0); - if (destroyContentOnRemoval) { - moveStackToDisplayLocked(stack.mStackId, DEFAULT_DISPLAY, false /* onTop */); - stack.finishAllActivitiesLocked(true /* immediately */); - } else { - // Moving all tasks to fullscreen stack, because it's guaranteed to be - // a valid launch stack for all activities. This way the task history from - // external display will be preserved on primary after move. - moveTasksToFullscreenStackLocked(stack, true /* onTop */); + ActivityDisplay activityDisplay = mActivityDisplays.get(displayId); + if (activityDisplay != null) { + final boolean destroyContentOnRemoval + = activityDisplay.shouldDestroyContentOnRemove(); + final ArrayList<ActivityStack> stacks = activityDisplay.mStacks; + while (!stacks.isEmpty()) { + final ActivityStack stack = stacks.get(0); + if (destroyContentOnRemoval) { + moveStackToDisplayLocked(stack.mStackId, DEFAULT_DISPLAY, + false /* onTop */); + stack.finishAllActivitiesLocked(true /* immediately */); + } else { + // Moving all tasks to fullscreen stack, because it's guaranteed to be + // a valid launch stack for all activities. This way the task history from + // external display will be preserved on primary after move. + moveTasksToFullscreenStackLocked(stack, true /* onTop */); + } } - } - releaseSleepTokens(activityDisplay); + releaseSleepTokens(activityDisplay); - mActivityDisplays.remove(displayId); - mWindowManager.onDisplayRemoved(displayId); + mActivityDisplays.remove(displayId); + mWindowManager.onDisplayRemoved(displayId); + } } } @@ -4223,7 +4235,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D info.userId = stack.mCurrentUser; info.visible = stack.shouldBeVisible(null); // A stack might be not attached to a display. - info.position = display != null ? display.getIndexOf(stack) : 0; + info.position = display != null ? display.mStacks.indexOf(stack) : 0; info.configuration.setTo(stack.getConfiguration()); ArrayList<TaskRecord> tasks = stack.getAllTasks(); @@ -4269,25 +4281,25 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D ArrayList<StackInfo> getAllStackInfosLocked() { ArrayList<StackInfo> list = new ArrayList<>(); for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); ++displayNdx) { - final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - list.add(getStackInfo(stack)); + ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; + for (int ndx = stacks.size() - 1; ndx >= 0; --ndx) { + list.add(getStackInfo(stacks.get(ndx))); } } return list; } void handleNonResizableTaskIfNeeded(TaskRecord task, int preferredWindowingMode, - int preferredDisplayId, ActivityStack actualStack) { + int preferredDisplayId, int actualStackId) { handleNonResizableTaskIfNeeded(task, preferredWindowingMode, preferredDisplayId, - actualStack, false /* forceNonResizable */); + actualStackId, false /* forceNonResizable */); } void handleNonResizableTaskIfNeeded(TaskRecord task, int preferredWindowingMode, - int preferredDisplayId, ActivityStack actualStack, boolean forceNonResizable) { + int preferredDisplayId, int actualStackId, boolean forceNonResizable) { final boolean isSecondaryDisplayPreferred = (preferredDisplayId != DEFAULT_DISPLAY && preferredDisplayId != INVALID_DISPLAY); + final ActivityStack actualStack = getStack(actualStackId); final boolean inSplitScreenMode = actualStack != null && actualStack.inSplitScreenWindowingMode(); if (((!inSplitScreenMode && preferredWindowingMode != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) @@ -4303,8 +4315,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // The task landed on an inappropriate display somehow, move it to the default // display. // TODO(multi-display): Find proper stack for the task on the default display. - mService.setTaskWindowingMode(task.taskId, - WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY, true /* toTop */); + mService.moveTaskToStack(task.taskId, FULLSCREEN_WORKSPACE_STACK_ID, + true /* toTop */); launchOnSecondaryDisplayFailed = true; } else { // The task might have landed on a display different from requested. @@ -4334,9 +4346,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // Dismiss docked stack. If task appeared to be in docked stack but is not resizable - // we need to move it to top of fullscreen stack, otherwise it will be covered. - final ActivityStack dockedStack = task.getStack().getDisplay().getSplitScreenPrimaryStack(); + final ActivityStack dockedStack = task.getStack().getDisplay().getSplitScreenStack(); if (dockedStack != null) { - moveTasksToFullscreenStackLocked(dockedStack, actualStack == dockedStack); + moveTasksToFullscreenStackLocked(dockedStack, + actualStackId == dockedStack.getStackId()); } } else if (topActivity != null && topActivity.isNonResizableOrForcedResizable() && !topActivity.noDisplay) { @@ -4389,7 +4402,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D void scheduleUpdatePictureInPictureModeIfNeeded(TaskRecord task, ActivityStack prevStack) { final ActivityStack stack = task.getStack(); if (prevStack == null || prevStack == stack - || (!prevStack.inPinnedWindowingMode() && !stack.inPinnedWindowingMode())) { + || (prevStack.mStackId != PINNED_STACK_ID && stack.mStackId != PINNED_STACK_ID)) { return; } @@ -4548,13 +4561,14 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D if (display == null) { return null; } - for (int i = display.getChildCount() - 1; i >= 0; i--) { - if (display.getChildAt(i) == stack && i > 0) { - return display.getChildAt(i - 1); + final ArrayList<ActivityStack> stacks = display.mStacks; + for (int i = stacks.size() - 1; i >= 0; i--) { + if (stacks.get(i) == stack && i > 0) { + return stacks.get(i - 1); } } throw new IllegalStateException("Failed to find a stack behind stack=" + stack - + " in=" + display); + + " in=" + stacks); } /** @@ -4667,8 +4681,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D for (int i = mActivityDisplays.size() - 1; i >= 0; i--) { final ActivityDisplay display = mActivityDisplays.valueAt(i); // Traverse all stacks on a display. - for (int j = display.getChildCount() - 1; j >= 0; --j) { - final ActivityStack stack = display.getChildAt(j); + for (int j = display.mStacks.size() - 1; j >= 0; j--) { + final ActivityStack stack = display.mStacks.get(j); // Get top activity from a visible stack and add it to the list. if (stack.shouldBeVisible(null /* starting */)) { final ActivityRecord top = stack.topActivity(); diff --git a/com/android/server/am/ActivityStarter.java b/com/android/server/am/ActivityStarter.java index 6f74d851..d444c663 100644 --- a/com/android/server/am/ActivityStarter.java +++ b/com/android/server/am/ActivityStarter.java @@ -26,9 +26,15 @@ import static android.app.ActivityManager.START_RETURN_INTENT_TO_CALLER; import static android.app.ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION; import static android.app.ActivityManager.START_SUCCESS; import static android.app.ActivityManager.START_TASK_TO_FRONT; +import static android.app.ActivityManager.StackId; +import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; +import static android.app.ActivityManager.StackId.INVALID_STACK_ID; +import static android.app.ActivityManager.StackId.PINNED_STACK_ID; +import static android.app.ActivityManager.StackId.isDynamicStack; import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; @@ -115,6 +121,7 @@ import com.android.internal.app.HeavyWeightSwitcherActivity; import com.android.internal.app.IVoiceInteractor; import com.android.server.am.ActivityStackSupervisor.PendingActivityLaunch; import com.android.server.pm.InstantAppResolver; +import com.android.server.wm.WindowManagerService; import java.io.PrintWriter; import java.text.DateFormat; @@ -133,11 +140,11 @@ class ActivityStarter { private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS; private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION; private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING; - private static final int INVALID_LAUNCH_MODE = -1; private final ActivityManagerService mService; private final ActivityStackSupervisor mSupervisor; private final ActivityStartInterceptor mInterceptor; + private WindowManagerService mWindowManager; final ArrayList<PendingActivityLaunch> mPendingActivityLaunches = new ArrayList<>(); @@ -147,7 +154,9 @@ class ActivityStarter { private int mCallingUid; private ActivityOptions mOptions; - private int mLaunchMode; + private boolean mLaunchSingleTop; + private boolean mLaunchSingleInstance; + private boolean mLaunchSingleTask; private boolean mLaunchTaskBehind; private int mLaunchFlags; @@ -157,7 +166,6 @@ class ActivityStarter { private boolean mDoResume; private int mStartFlags; private ActivityRecord mSourceRecord; - // The display to launch the activity onto, barring any strong reason to do otherwise. private int mPreferredDisplayId; @@ -187,6 +195,8 @@ class ActivityStarter { private IVoiceInteractionSession mVoiceSession; private IVoiceInteractor mVoiceInteractor; + private boolean mUsingVr2dDisplay; + // Last home activity record we attempted to start private final ActivityRecord[] mLastHomeActivityStartRecord = new ActivityRecord[1]; // The result of the last home activity we attempted to start. @@ -206,9 +216,11 @@ class ActivityStarter { mCallingUid = -1; mOptions = null; + mLaunchSingleTop = false; + mLaunchSingleInstance = false; + mLaunchSingleTask = false; mLaunchTaskBehind = false; mLaunchFlags = 0; - mLaunchMode = INVALID_LAUNCH_MODE; mLaunchBounds = null; @@ -236,13 +248,16 @@ class ActivityStarter { mVoiceSession = null; mVoiceInteractor = null; + mUsingVr2dDisplay = false; + mIntentDelivered = false; } - ActivityStarter(ActivityManagerService service) { + ActivityStarter(ActivityManagerService service, ActivityStackSupervisor supervisor) { mService = service; - mSupervisor = mService.mStackSupervisor; + mSupervisor = supervisor; mInterceptor = new ActivityStartInterceptor(mService, mSupervisor); + mUsingVr2dDisplay = false; } int startActivityLocked(IApplicationThread caller, Intent intent, Intent ephemeralIntent, @@ -595,41 +610,38 @@ class ActivityStarter { mSupervisor.reportTaskToFrontNoLaunch(mStartActivity); } - ActivityStack startedActivityStack = null; + int startedActivityStackId = INVALID_STACK_ID; final ActivityStack currentStack = r.getStack(); if (currentStack != null) { - startedActivityStack = currentStack; + startedActivityStackId = currentStack.mStackId; } else if (mTargetStack != null) { - startedActivityStack = targetStack; + startedActivityStackId = targetStack.mStackId; } - if (startedActivityStack == null) { - return; - } - - if (startedActivityStack.inSplitScreenPrimaryWindowingMode()) { - final ActivityStack homeStack = mSupervisor.mHomeStack; + if (startedActivityStackId == DOCKED_STACK_ID) { + final ActivityStack homeStack = mSupervisor.getDefaultDisplay().getStack( + WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME); final boolean homeStackVisible = homeStack != null && homeStack.isVisible(); if (homeStackVisible) { // We launch an activity while being in home stack, which means either launcher or // recents into docked stack. We don't want the launched activity to be alone in a // docked stack, so we want to immediately launch recents too. if (DEBUG_RECENTS) Slog.d(TAG, "Scheduling recents launch."); - mService.mWindowManager.showRecentApps(true /* fromHome */); + mWindowManager.showRecentApps(true /* fromHome */); } return; } boolean clearedTask = (mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK) && (mReuseTask != null); - if (startedActivityStack.inPinnedWindowingMode() - && (result == START_TASK_TO_FRONT || result == START_DELIVERED_TO_TOP - || clearedTask)) { + if (startedActivityStackId == PINNED_STACK_ID && (result == START_TASK_TO_FRONT + || result == START_DELIVERED_TO_TOP || clearedTask)) { // The activity was already running in the pinned stack so it wasn't started, but either // brought to the front or the new intent was delivered to it since it was already in // front. Notify anyone interested in this piece of information. mService.mTaskChangeNotificationController.notifyPinnedActivityRestartAttempt( clearedTask); + return; } } @@ -1050,7 +1062,7 @@ class ActivityStarter { // operations. if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0 || isDocumentLaunchesIntoExisting(mLaunchFlags) - || isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) { + || mLaunchSingleInstance || mLaunchSingleTask) { final TaskRecord task = reusedActivity.getTask(); // In this situation we want to remove all activities from the task up to the one @@ -1133,7 +1145,7 @@ class ActivityStarter { && top.userId == mStartActivity.userId && top.app != null && top.app.thread != null && ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0 - || isLaunchModeOneOf(LAUNCH_SINGLE_TOP, LAUNCH_SINGLE_TASK)); + || mLaunchSingleTop || mLaunchSingleTask); if (dontStart) { // For paranoia, make sure we have correctly resumed the top activity. topStack.mLastPausedActivity = null; @@ -1152,7 +1164,7 @@ class ActivityStarter { // Don't use mStartActivity.task to show the toast. We're not starting a new activity // but reusing 'top'. Fields in mStartActivity may not be fully initialized. mSupervisor.handleNonResizableTaskIfNeeded(top.getTask(), preferredWindowingMode, - preferredLaunchDisplayId, topStack); + preferredLaunchDisplayId, topStack.mStackId); return START_DELIVERED_TO_TOP; } @@ -1215,7 +1227,7 @@ class ActivityStarter { mTargetStack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); // Go ahead and tell window manager to execute app transition for this activity // since the app transition will not be triggered through the resume channel. - mService.mWindowManager.executeAppTransition(); + mWindowManager.executeAppTransition(); } else { // If the target stack was not previously focusable (previous top running activity // on that stack was not visible) then any prior calls to move the stack to the @@ -1228,13 +1240,13 @@ class ActivityStarter { mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity, mOptions); } - } else if (mStartActivity != null) { - mSupervisor.mRecentTasks.add(mStartActivity.getTask()); + } else { + mSupervisor.addRecentActivity(mStartActivity); } mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack); mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(), preferredWindowingMode, - preferredLaunchDisplayId, mTargetStack); + preferredLaunchDisplayId, mTargetStack.mStackId); return START_SUCCESS; } @@ -1256,13 +1268,13 @@ class ActivityStarter { mLaunchBounds = getOverrideBounds(r, options, inTask); - mLaunchMode = r.launchMode; - + mLaunchSingleTop = r.launchMode == LAUNCH_SINGLE_TOP; + mLaunchSingleInstance = r.launchMode == LAUNCH_SINGLE_INSTANCE; + mLaunchSingleTask = r.launchMode == LAUNCH_SINGLE_TASK; mLaunchFlags = adjustLaunchFlagsToDocumentMode( - r, LAUNCH_SINGLE_INSTANCE == mLaunchMode, - LAUNCH_SINGLE_TASK == mLaunchMode, mIntent.getFlags()); + r, mLaunchSingleInstance, mLaunchSingleTask, mIntent.getFlags()); mLaunchTaskBehind = r.mLaunchTaskBehind - && !isLaunchModeOneOf(LAUNCH_SINGLE_TASK, LAUNCH_SINGLE_INSTANCE) + && !mLaunchSingleTask && !mLaunchSingleInstance && (mLaunchFlags & FLAG_ACTIVITY_NEW_DOCUMENT) != 0; sendNewTaskResultRequestIfNeeded(); @@ -1372,7 +1384,7 @@ class ActivityStarter { // If this task is empty, then we are adding the first activity -- it // determines the root, and must be launching as a NEW_TASK. - if (isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) { + if (mLaunchSingleInstance || mLaunchSingleTask) { if (!baseIntent.getComponent().equals(mStartActivity.intent.getComponent())) { ActivityOptions.abort(mOptions); throw new IllegalArgumentException("Trying to launch singleInstance/Task " @@ -1415,7 +1427,7 @@ class ActivityStarter { // in any task/stack, however it could launch other activities like ResolverActivity, // and we want those to stay in the original task. if ((mStartActivity.isResolverActivity() || mStartActivity.noDisplay) && mSourceRecord != null - && mSourceRecord.inFreeformWindowingMode()) { + && mSourceRecord.isFreeform()) { mAddingToTask = true; } } @@ -1434,7 +1446,7 @@ class ActivityStarter { // instance... this new activity it is starting must go on its // own task. mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK; - } else if (isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) { + } else if (mLaunchSingleInstance || mLaunchSingleTask) { // The activity being started is a single instance... it always // gets launched into its own task. mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK; @@ -1485,7 +1497,7 @@ class ActivityStarter { // launch this as a new task behind the current one. boolean putIntoExistingTask = ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0 && (mLaunchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0) - || isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK); + || mLaunchSingleInstance || mLaunchSingleTask; // If bring to front is requested, and no result is requested and we have not been given // an explicit task to launch in to, and we can find a task that was started with this // same component, then instead of launching bring that one to the front. @@ -1495,7 +1507,7 @@ class ActivityStarter { final TaskRecord task = mSupervisor.anyTaskForIdLocked(mOptions.getLaunchTaskId()); intentActivity = task != null ? task.getTopActivity() : null; } else if (putIntoExistingTask) { - if (LAUNCH_SINGLE_INSTANCE == mLaunchMode) { + if (mLaunchSingleInstance) { // There can be one and only one instance of single instance activity in the // history, and it is always in its own unique task, so we do a special search. intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info, @@ -1504,7 +1516,7 @@ class ActivityStarter { // For the launch adjacent case we only want to put the activity in an existing // task if the activity already exists in the history. intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info, - !(LAUNCH_SINGLE_TASK == mLaunchMode)); + !mLaunchSingleTask); } else { // Otherwise find the best task to put the activity in. intentActivity = mSupervisor.findTaskLocked(mStartActivity, mPreferredDisplayId); @@ -1533,6 +1545,7 @@ class ActivityStarter { if (DEBUG_STACK) { Slog.d(TAG, "getSourceDisplayId :" + displayId); } + mUsingVr2dDisplay = true; return displayId; } @@ -1654,7 +1667,7 @@ class ActivityStarter { } mSupervisor.handleNonResizableTaskIfNeeded(intentActivity.getTask(), - WINDOWING_MODE_UNDEFINED, DEFAULT_DISPLAY, mTargetStack); + WINDOWING_MODE_UNDEFINED, DEFAULT_DISPLAY, mTargetStack.mStackId); // If the caller has requested that the target task be reset, then do so. if ((mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) { @@ -1706,7 +1719,7 @@ class ActivityStarter { // mTaskToReturnTo values and we don't want to overwrite them accidentally. mMovedOtherTask = true; } else if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0 - || isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) { + || mLaunchSingleInstance || mLaunchSingleTask) { ActivityRecord top = intentActivity.getTask().performClearTaskLocked(mStartActivity, mLaunchFlags); if (top == null) { @@ -1735,8 +1748,7 @@ class ActivityStarter { // so we take that as a request to bring the task to the foreground. If the top // activity in the task is the root activity, deliver this new intent to it if it // desires. - if (((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0 - || LAUNCH_SINGLE_TOP == mLaunchMode) + if (((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0 || mLaunchSingleTop) && intentActivity.realActivity.equals(mStartActivity.realActivity)) { if (intentActivity.frontOfTask) { intentActivity.getTask().setIntent(mStartActivity); @@ -1940,7 +1952,7 @@ class ActivityStarter { if (top != null && top.realActivity.equals(mStartActivity.realActivity) && top.userId == mStartActivity.userId) { if ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0 - || isLaunchModeOneOf(LAUNCH_SINGLE_TOP, LAUNCH_SINGLE_TASK)) { + || mLaunchSingleTop || mLaunchSingleTask) { mTargetStack.moveTaskToFrontLocked(mInTask, mNoAnimation, mOptions, mStartActivity.appTimeTracker, "inTaskToFront"); if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) { @@ -1989,9 +2001,9 @@ class ActivityStarter { return; } - final ActivityStack stack = task.getStack(); - if (stack != null && stack.resizeStackWithLaunchBounds()) { - mService.resizeStack(stack.mStackId, bounds, true, !PRESERVE_WINDOWS, ANIMATE, -1); + final int stackId = task.getStackId(); + if (StackId.resizeStackWithLaunchBounds(stackId)) { + mService.resizeStack(stackId, bounds, true, !PRESERVE_WINDOWS, ANIMATE, -1); } else { task.updateOverrideConfiguration(bounds); } @@ -2103,10 +2115,11 @@ class ActivityStarter { } if (stack == null) { // We first try to put the task in the first dynamic stack on home display. - final ActivityDisplay display = mSupervisor.getDefaultDisplay(); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - stack = display.getChildAt(stackNdx); - if (!stack.isOnHomeDisplay()) { + final ArrayList<ActivityStack> homeDisplayStacks = + mSupervisor.getStacksOnDefaultDisplay(); + for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) { + stack = homeDisplayStacks.get(stackNdx); + if (isDynamicStack(stack.mStackId)) { if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, "computeStackFocus: Setting focused stack=" + stack); return stack; @@ -2125,6 +2138,7 @@ class ActivityStarter { private boolean canLaunchIntoFocusedStack(ActivityRecord r, boolean newTask) { final ActivityStack focusedStack = mSupervisor.mFocusedStack; final boolean canUseFocusedStack; + final int focusedStackId = mSupervisor.mFocusedStack.mStackId; if (focusedStack.isActivityTypeAssistant()) { canUseFocusedStack = r.isActivityTypeAssistant(); } else { @@ -2147,7 +2161,7 @@ class ActivityStarter { default: // Dynamic stacks behave similarly to the fullscreen stack and can contain any // resizeable task. - canUseFocusedStack = !focusedStack.isOnHomeDisplay() + canUseFocusedStack = isDynamicStack(focusedStackId) && r.canBeLaunchedOnDisplay(focusedStack.mDisplayId); } } @@ -2163,8 +2177,7 @@ class ActivityStarter { return mReuseTask.getStack(); } - final int vrDisplayId = mPreferredDisplayId == mService.mVr2dDisplayId - ? mPreferredDisplayId : INVALID_DISPLAY; + final int vrDisplayId = mUsingVr2dDisplay ? mPreferredDisplayId : INVALID_DISPLAY; final ActivityStack launchStack = mSupervisor.getLaunchStack(r, aOptions, task, ON_TOP, vrDisplayId); @@ -2192,7 +2205,7 @@ class ActivityStarter { return mSupervisor.mFocusedStack; } - if (parentStack != null && parentStack.inSplitScreenPrimaryWindowingMode()) { + if (parentStack != null && parentStack.isDockedStack()) { // If parent was in docked stack, the natural place to launch another activity // will be fullscreen, so it can appear alongside the docked window. final int activityType = mSupervisor.resolveActivityType(r, mOptions, task); @@ -2202,8 +2215,8 @@ class ActivityStarter { // If the parent is not in the docked stack, we check if there is docked window // and if yes, we will launch into that stack. If not, we just put the new // activity into parent's stack, because we can't find a better place. - final ActivityStack dockedStack = - mSupervisor.getDefaultDisplay().getSplitScreenPrimaryStack(); + final ActivityStack dockedStack = mSupervisor.getDefaultDisplay().getStack( + WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED); if (dockedStack != null && !dockedStack.shouldBeVisible(r)) { // There is a docked stack, but it isn't visible, so we can't launch into that. return null; @@ -2223,8 +2236,8 @@ class ActivityStarter { return newBounds; } - private boolean isLaunchModeOneOf(int mode1, int mode2) { - return mode1 == mLaunchMode || mode2 == mLaunchMode; + void setWindowManager(WindowManagerService wm) { + mWindowManager = wm; } static boolean isDocumentLaunchesIntoExisting(int flags) { @@ -2305,11 +2318,11 @@ class ActivityStarter { } pw.print(prefix); pw.print("mLaunchSingleTop="); - pw.print(LAUNCH_SINGLE_TOP == mLaunchMode); + pw.print(mLaunchSingleTop); pw.print(" mLaunchSingleInstance="); - pw.print(LAUNCH_SINGLE_INSTANCE == mLaunchMode); + pw.print(mLaunchSingleInstance); pw.print(" mLaunchSingleTask="); - pw.println(LAUNCH_SINGLE_TASK == mLaunchMode); + pw.println(mLaunchSingleTask); pw.print(prefix); pw.print("mLaunchFlags=0x"); pw.print(Integer.toHexString(mLaunchFlags)); diff --git a/com/android/server/am/AppTaskImpl.java b/com/android/server/am/AppTaskImpl.java deleted file mode 100644 index a4e2e70e..00000000 --- a/com/android/server/am/AppTaskImpl.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (C) 2017 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.am; - -import static com.android.server.am.ActivityStackSupervisor.REMOVE_FROM_RECENTS; - -import android.app.ActivityManager; -import android.app.IAppTask; -import android.app.IApplicationThread; -import android.content.Intent; -import android.os.Binder; -import android.os.Bundle; -import android.os.IBinder; -import android.os.UserHandle; - -/** - * An implementation of IAppTask, that allows an app to manage its own tasks via - * {@link android.app.ActivityManager.AppTask}. We keep track of the callingUid to ensure that - * only the process that calls getAppTasks() can call the AppTask methods. - */ -class AppTaskImpl extends IAppTask.Stub { - private ActivityManagerService mService; - - private int mTaskId; - private int mCallingUid; - - public AppTaskImpl(ActivityManagerService service, int taskId, int callingUid) { - mService = service; - mTaskId = taskId; - mCallingUid = callingUid; - } - - private void checkCaller() { - if (mCallingUid != Binder.getCallingUid()) { - throw new SecurityException("Caller " + mCallingUid - + " does not match caller of getAppTasks(): " + Binder.getCallingUid()); - } - } - - @Override - public void finishAndRemoveTask() { - checkCaller(); - - synchronized (mService) { - long origId = Binder.clearCallingIdentity(); - try { - // We remove the task from recents to preserve backwards - if (!mService.mStackSupervisor.removeTaskByIdLocked(mTaskId, false, - REMOVE_FROM_RECENTS)) { - throw new IllegalArgumentException("Unable to find task ID " + mTaskId); - } - } finally { - Binder.restoreCallingIdentity(origId); - } - } - } - - @Override - public ActivityManager.RecentTaskInfo getTaskInfo() { - checkCaller(); - - synchronized (mService) { - long origId = Binder.clearCallingIdentity(); - try { - TaskRecord tr = mService.mStackSupervisor.anyTaskForIdLocked(mTaskId); - if (tr == null) { - throw new IllegalArgumentException("Unable to find task ID " + mTaskId); - } - return RecentTasks.createRecentTaskInfo(tr); - } finally { - Binder.restoreCallingIdentity(origId); - } - } - } - - @Override - public void moveToFront() { - checkCaller(); - // Will bring task to front if it already has a root activity. - final long origId = Binder.clearCallingIdentity(); - try { - synchronized (this) { - mService.mStackSupervisor.startActivityFromRecentsInner(mTaskId, null); - } - } finally { - Binder.restoreCallingIdentity(origId); - } - } - - @Override - public int startActivity(IBinder whoThread, String callingPackage, - Intent intent, String resolvedType, Bundle bOptions) { - checkCaller(); - - int callingUser = UserHandle.getCallingUserId(); - TaskRecord tr; - IApplicationThread appThread; - synchronized (mService) { - tr = mService.mStackSupervisor.anyTaskForIdLocked(mTaskId); - if (tr == null) { - throw new IllegalArgumentException("Unable to find task ID " + mTaskId); - } - appThread = IApplicationThread.Stub.asInterface(whoThread); - if (appThread == null) { - throw new IllegalArgumentException("Bad app thread " + appThread); - } - } - return mService.mActivityStarter.startActivityMayWait(appThread, -1, callingPackage, - intent, resolvedType, null, null, null, null, 0, 0, null, null, - null, bOptions, false, callingUser, tr, "AppTaskImpl"); - } - - @Override - public void setExcludeFromRecents(boolean exclude) { - checkCaller(); - - synchronized (mService) { - long origId = Binder.clearCallingIdentity(); - try { - TaskRecord tr = mService.mStackSupervisor.anyTaskForIdLocked(mTaskId); - if (tr == null) { - throw new IllegalArgumentException("Unable to find task ID " + mTaskId); - } - Intent intent = tr.getBaseIntent(); - if (exclude) { - intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - } else { - intent.setFlags(intent.getFlags() - & ~Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - } - } finally { - Binder.restoreCallingIdentity(origId); - } - } - } -}
\ No newline at end of file diff --git a/com/android/server/am/BatteryStatsService.java b/com/android/server/am/BatteryStatsService.java index 68ed9aec..7c9cd00e 100644 --- a/com/android/server/am/BatteryStatsService.java +++ b/com/android/server/am/BatteryStatsService.java @@ -297,12 +297,26 @@ public final class BatteryStatsService extends IBatteryStats.Stub void noteProcessStart(String name, int uid) { synchronized (mStats) { mStats.noteProcessStartLocked(name, uid); + + // TODO: remove this once we figure out properly where and how + // PROCESS_EVENT = 1112 + // KEY_STATE = 1 + // KEY_PACKAGE_NAME: 1002 + // KEY_UID: 2 + StatsLog.writeArray(1112, 1, 1, 1002, name, 2, uid); } } void noteProcessCrash(String name, int uid) { synchronized (mStats) { mStats.noteProcessCrashLocked(name, uid); + + // TODO: remove this once we figure out properly where and how + // PROCESS_EVENT = 1112 + // KEY_STATE = 1 + // KEY_PACKAGE_NAME: 1002 + // KEY_UID: 2 + StatsLog.writeArray(1112, 1, 2, 1002, name, 2, uid); } } @@ -320,9 +334,6 @@ public final class BatteryStatsService extends IBatteryStats.Stub void noteUidProcessState(int uid, int state) { synchronized (mStats) { - // TODO: remove this once we figure out properly where and how - StatsLog.write(StatsLog.PROCESS_STATE_CHANGED, uid, state); - mStats.noteUidProcessStateLocked(uid, state); } } @@ -537,10 +548,12 @@ public final class BatteryStatsService extends IBatteryStats.Stub enforceCallingPermission(); if (DBG) Slog.d(TAG, "begin noteScreenState"); synchronized (mStats) { - // TODO: remove this once we figure out properly where and how - StatsLog.write(StatsLog.SCREEN_STATE_CHANGED, state); - mStats.noteScreenStateLocked(state); + // TODO: remove this once we figure out properly where and how + // SCREEN_EVENT = 2 + // KEY_STATE: 1 + // State value: state. We can change this to our own def later. + StatsLog.writeArray(2, 1, state); } if (DBG) Slog.d(TAG, "end noteScreenState"); } diff --git a/com/android/server/am/BroadcastFilter.java b/com/android/server/am/BroadcastFilter.java index 7ff227f5..f96b06fa 100644 --- a/com/android/server/am/BroadcastFilter.java +++ b/com/android/server/am/BroadcastFilter.java @@ -19,9 +19,6 @@ package com.android.server.am; import android.content.IntentFilter; import android.util.PrintWriterPrinter; import android.util.Printer; -import android.util.proto.ProtoOutputStream; - -import com.android.server.am.proto.BroadcastFilterProto; import java.io.PrintWriter; @@ -47,38 +44,27 @@ final class BroadcastFilter extends IntentFilter { instantApp = _instantApp; visibleToInstantApp = _visibleToInstantApp; } - - public void writeToProto(ProtoOutputStream proto, long fieldId) { - long token = proto.start(fieldId); - super.writeToProto(proto, BroadcastFilterProto.INTENT_FILTER); - if (requiredPermission != null) { - proto.write(BroadcastFilterProto.REQUIRED_PERMISSION, requiredPermission); - } - proto.write(BroadcastFilterProto.HEX_HASH, Integer.toHexString(System.identityHashCode(this))); - proto.write(BroadcastFilterProto.OWNING_USER_ID, owningUserId); - proto.end(token); - } - + public void dump(PrintWriter pw, String prefix) { dumpInReceiverList(pw, new PrintWriterPrinter(pw), prefix); receiverList.dumpLocal(pw, prefix); } - + public void dumpBrief(PrintWriter pw, String prefix) { dumpBroadcastFilterState(pw, prefix); } - + public void dumpInReceiverList(PrintWriter pw, Printer pr, String prefix) { super.dump(pr, prefix); dumpBroadcastFilterState(pw, prefix); } - + void dumpBroadcastFilterState(PrintWriter pw, String prefix) { if (requiredPermission != null) { pw.print(prefix); pw.print("requiredPermission="); pw.println(requiredPermission); } } - + public String toString() { StringBuilder sb = new StringBuilder(); sb.append("BroadcastFilter{"); diff --git a/com/android/server/am/BroadcastQueue.java b/com/android/server/am/BroadcastQueue.java index c62cc38b..d8354549 100644 --- a/com/android/server/am/BroadcastQueue.java +++ b/com/android/server/am/BroadcastQueue.java @@ -51,12 +51,9 @@ import android.os.UserHandle; import android.util.EventLog; import android.util.Slog; import android.util.TimeUtils; -import android.util.proto.ProtoOutputStream; import static com.android.server.am.ActivityManagerDebugConfig.*; -import com.android.server.am.proto.BroadcastQueueProto; - /** * BROADCASTS * @@ -1588,55 +1585,6 @@ public final class BroadcastQueue { && (mPendingBroadcast == null); } - void writeToProto(ProtoOutputStream proto, long fieldId) { - long token = proto.start(fieldId); - proto.write(BroadcastQueueProto.QUEUE_NAME, mQueueName); - int N; - N = mParallelBroadcasts.size(); - for (int i = N - 1; i >= 0; i--) { - mParallelBroadcasts.get(i).writeToProto(proto, BroadcastQueueProto.PARALLEL_BROADCASTS); - } - N = mOrderedBroadcasts.size(); - for (int i = N - 1; i >= 0; i--) { - mOrderedBroadcasts.get(i).writeToProto(proto, BroadcastQueueProto.ORDERED_BROADCASTS); - } - if (mPendingBroadcast != null) { - mPendingBroadcast.writeToProto(proto, BroadcastQueueProto.PENDING_BROADCAST); - } - - int lastIndex = mHistoryNext; - int ringIndex = lastIndex; - do { - // increasing index = more recent entry, and we want to print the most - // recent first and work backwards, so we roll through the ring backwards. - ringIndex = ringAdvance(ringIndex, -1, MAX_BROADCAST_HISTORY); - BroadcastRecord r = mBroadcastHistory[ringIndex]; - if (r != null) { - r.writeToProto(proto, BroadcastQueueProto.HISTORICAL_BROADCASTS); - } - } while (ringIndex != lastIndex); - - lastIndex = ringIndex = mSummaryHistoryNext; - do { - ringIndex = ringAdvance(ringIndex, -1, MAX_BROADCAST_SUMMARY_HISTORY); - Intent intent = mBroadcastSummaryHistory[ringIndex]; - if (intent == null) { - continue; - } - long summaryToken = proto.start(BroadcastQueueProto.HISTORICAL_BROADCASTS_SUMMARY); - intent.writeToProto(proto, BroadcastQueueProto.BroadcastSummary.INTENT, - false, true, true, false); - proto.write(BroadcastQueueProto.BroadcastSummary.ENQUEUE_CLOCK_TIME_MS, - mSummaryHistoryEnqueueTime[ringIndex]); - proto.write(BroadcastQueueProto.BroadcastSummary.DISPATCH_CLOCK_TIME_MS, - mSummaryHistoryDispatchTime[ringIndex]); - proto.write(BroadcastQueueProto.BroadcastSummary.FINISH_CLOCK_TIME_MS, - mSummaryHistoryFinishTime[ringIndex]); - proto.end(summaryToken); - } while (ringIndex != lastIndex); - proto.end(token); - } - final boolean dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args, int opti, boolean dumpAll, String dumpPackage, boolean needSep) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); diff --git a/com/android/server/am/BroadcastRecord.java b/com/android/server/am/BroadcastRecord.java index 5b3b2a8e..6bc0744f 100644 --- a/com/android/server/am/BroadcastRecord.java +++ b/com/android/server/am/BroadcastRecord.java @@ -30,9 +30,6 @@ import android.os.SystemClock; import android.os.UserHandle; import android.util.PrintWriterPrinter; import android.util.TimeUtils; -import android.util.proto.ProtoOutputStream; - -import com.android.server.am.proto.BroadcastRecordProto; import java.io.PrintWriter; import java.text.SimpleDateFormat; @@ -334,17 +331,9 @@ final class BroadcastRecord extends Binder { return didSomething; } - @Override public String toString() { return "BroadcastRecord{" + Integer.toHexString(System.identityHashCode(this)) + " u" + userId + " " + intent.getAction() + "}"; } - - public void writeToProto(ProtoOutputStream proto, long fieldId) { - long token = proto.start(fieldId); - proto.write(BroadcastRecordProto.USER_ID, userId); - proto.write(BroadcastRecordProto.INTENT_ACTION, intent.getAction()); - proto.end(token); - } } diff --git a/com/android/server/am/KeyguardController.java b/com/android/server/am/KeyguardController.java index c3fed171..5c48f90d 100644 --- a/com/android/server/am/KeyguardController.java +++ b/com/android/server/am/KeyguardController.java @@ -16,6 +16,7 @@ package com.android.server.am; +import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; @@ -46,6 +47,7 @@ import com.android.internal.policy.IKeyguardDismissCallback; import com.android.server.wm.WindowManagerService; import java.io.PrintWriter; +import java.util.ArrayList; /** * Controls Keyguard occluding, dismissing and transitions depending on what kind of activities are @@ -236,9 +238,9 @@ class KeyguardController { final ActivityRecord lastDismissingKeyguardActivity = mDismissingKeyguardActivity; mOccluded = false; mDismissingKeyguardActivity = null; - final ActivityDisplay display = mStackSupervisor.getDefaultDisplay(); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); + final ArrayList<ActivityStack> stacks = mStackSupervisor.getStacksOnDefaultDisplay(); + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); // Only the focused stack top activity may control occluded state if (mStackSupervisor.isFocusedStack(stack)) { @@ -340,7 +342,7 @@ class KeyguardController { // show on top of the lock screen. In this can we want to dismiss the docked // stack since it will be complicated/risky to try to put the activity on top // of the lock screen in the right fullscreen configuration. - final ActivityStack stack = mStackSupervisor.getDefaultDisplay().getSplitScreenPrimaryStack(); + final ActivityStack stack = mStackSupervisor.getDefaultDisplay().getSplitScreenStack(); if (stack == null) { return; } diff --git a/com/android/server/am/LaunchingTaskPositioner.java b/com/android/server/am/LaunchingTaskPositioner.java index 0dc73e98..d6523418 100644 --- a/com/android/server/am/LaunchingTaskPositioner.java +++ b/com/android/server/am/LaunchingTaskPositioner.java @@ -24,8 +24,8 @@ import android.content.pm.ActivityInfo; import android.graphics.Point; import android.graphics.Rect; import android.util.Slog; +import android.view.Display; import android.view.Gravity; -import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; @@ -64,11 +64,43 @@ class LaunchingTaskPositioner { private static final int SHIFT_POLICY_HORIZONTAL_RIGHT = 2; private static final int SHIFT_POLICY_HORIZONTAL_LEFT = 3; + private boolean mDefaultStartBoundsConfigurationSet = false; private final Rect mAvailableRect = new Rect(); private final Rect mTmpProposal = new Rect(); private final Rect mTmpOriginal = new Rect(); - private final Point mDisplaySize = new Point(); + private int mDefaultFreeformStartX; + private int mDefaultFreeformStartY; + private int mDefaultFreeformWidth; + private int mDefaultFreeformHeight; + private int mDefaultFreeformStepHorizontal; + private int mDefaultFreeformStepVertical; + private int mDisplayWidth; + private int mDisplayHeight; + + void setDisplay(Display display) { + Point size = new Point(); + display.getSize(size); + mDisplayWidth = size.x; + mDisplayHeight = size.y; + } + + void configure(Rect stackBounds) { + if (stackBounds == null) { + mAvailableRect.set(0, 0, mDisplayWidth, mDisplayHeight); + } else { + mAvailableRect.set(stackBounds); + } + int width = mAvailableRect.width(); + int height = mAvailableRect.height(); + mDefaultFreeformStartX = mAvailableRect.left + width / MARGIN_SIZE_DENOMINATOR; + mDefaultFreeformStartY = mAvailableRect.top + height / MARGIN_SIZE_DENOMINATOR; + mDefaultFreeformWidth = width / WINDOW_SIZE_DENOMINATOR; + mDefaultFreeformHeight = height / WINDOW_SIZE_DENOMINATOR; + mDefaultFreeformStepHorizontal = Math.max(width / STEP_DENOMINATOR, MINIMAL_STEP); + mDefaultFreeformStepVertical = Math.max(height / STEP_DENOMINATOR, MINIMAL_STEP); + mDefaultStartBoundsConfigurationSet = true; + } /** * Tries to set task's bound in a way that it won't collide with any other task. By colliding @@ -82,154 +114,104 @@ class LaunchingTaskPositioner { */ void updateDefaultBounds(TaskRecord task, ArrayList<TaskRecord> tasks, @Nullable ActivityInfo.WindowLayout windowLayout) { - updateAvailableRect(task, mAvailableRect); - + if (!mDefaultStartBoundsConfigurationSet) { + return; + } if (windowLayout == null) { - positionCenter(task, tasks, mAvailableRect, getFreeformWidth(mAvailableRect), - getFreeformHeight(mAvailableRect)); + positionCenter(task, tasks, mDefaultFreeformWidth, mDefaultFreeformHeight); return; } - int width = getFinalWidth(windowLayout, mAvailableRect); - int height = getFinalHeight(windowLayout, mAvailableRect); + int width = getFinalWidth(windowLayout); + int height = getFinalHeight(windowLayout); int verticalGravity = windowLayout.gravity & Gravity.VERTICAL_GRAVITY_MASK; int horizontalGravity = windowLayout.gravity & Gravity.HORIZONTAL_GRAVITY_MASK; if (verticalGravity == Gravity.TOP) { if (horizontalGravity == Gravity.RIGHT) { - positionTopRight(task, tasks, mAvailableRect, width, height); + positionTopRight(task, tasks, width, height); } else { - positionTopLeft(task, tasks, mAvailableRect, width, height); + positionTopLeft(task, tasks, width, height); } } else if (verticalGravity == Gravity.BOTTOM) { if (horizontalGravity == Gravity.RIGHT) { - positionBottomRight(task, tasks, mAvailableRect, width, height); + positionBottomRight(task, tasks, width, height); } else { - positionBottomLeft(task, tasks, mAvailableRect, width, height); + positionBottomLeft(task, tasks, width, height); } } else { // Some fancy gravity setting that we don't support yet. We just put the activity in the // center. Slog.w(TAG, "Received unsupported gravity: " + windowLayout.gravity + ", positioning in the center instead."); - positionCenter(task, tasks, mAvailableRect, width, height); + positionCenter(task, tasks, width, height); } } - private void updateAvailableRect(TaskRecord task, Rect availableRect) { - final Rect stackBounds = task.getStack().mBounds; - - if (stackBounds != null) { - availableRect.set(stackBounds); - } else { - task.getStack().getDisplay().mDisplay.getSize(mDisplaySize); - availableRect.set(0, 0, mDisplaySize.x, mDisplaySize.y); - } - } - - @VisibleForTesting - static int getFreeformStartLeft(Rect bounds) { - return bounds.left + bounds.width() / MARGIN_SIZE_DENOMINATOR; - } - - @VisibleForTesting - static int getFreeformStartTop(Rect bounds) { - return bounds.top + bounds.height() / MARGIN_SIZE_DENOMINATOR; - } - - @VisibleForTesting - static int getFreeformWidth(Rect bounds) { - return bounds.width() / WINDOW_SIZE_DENOMINATOR; - } - - @VisibleForTesting - static int getFreeformHeight(Rect bounds) { - return bounds.height() / WINDOW_SIZE_DENOMINATOR; - } - - @VisibleForTesting - static int getHorizontalStep(Rect bounds) { - return Math.max(bounds.width() / STEP_DENOMINATOR, MINIMAL_STEP); - } - - @VisibleForTesting - static int getVerticalStep(Rect bounds) { - return Math.max(bounds.height() / STEP_DENOMINATOR, MINIMAL_STEP); - } - - - - private int getFinalWidth(ActivityInfo.WindowLayout windowLayout, Rect availableRect) { - int width = getFreeformWidth(availableRect); + private int getFinalWidth(ActivityInfo.WindowLayout windowLayout) { + int width = mDefaultFreeformWidth; if (windowLayout.width > 0) { width = windowLayout.width; } if (windowLayout.widthFraction > 0) { - width = (int) (availableRect.width() * windowLayout.widthFraction); + width = (int) (mAvailableRect.width() * windowLayout.widthFraction); } return width; } - private int getFinalHeight(ActivityInfo.WindowLayout windowLayout, Rect availableRect) { - int height = getFreeformHeight(availableRect); + private int getFinalHeight(ActivityInfo.WindowLayout windowLayout) { + int height = mDefaultFreeformHeight; if (windowLayout.height > 0) { height = windowLayout.height; } if (windowLayout.heightFraction > 0) { - height = (int) (availableRect.height() * windowLayout.heightFraction); + height = (int) (mAvailableRect.height() * windowLayout.heightFraction); } return height; } - private void positionBottomLeft(TaskRecord task, ArrayList<TaskRecord> tasks, - Rect availableRect, int width, int height) { - mTmpProposal.set(availableRect.left, availableRect.bottom - height, - availableRect.left + width, availableRect.bottom); - position(task, tasks, availableRect, mTmpProposal, !ALLOW_RESTART, - SHIFT_POLICY_HORIZONTAL_RIGHT); + private void positionBottomLeft(TaskRecord task, ArrayList<TaskRecord> tasks, int width, + int height) { + mTmpProposal.set(mAvailableRect.left, mAvailableRect.bottom - height, + mAvailableRect.left + width, mAvailableRect.bottom); + position(task, tasks, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_RIGHT); } - private void positionBottomRight(TaskRecord task, ArrayList<TaskRecord> tasks, - Rect availableRect, int width, int height) { - mTmpProposal.set(availableRect.right - width, availableRect.bottom - height, - availableRect.right, availableRect.bottom); - position(task, tasks, availableRect, mTmpProposal, !ALLOW_RESTART, - SHIFT_POLICY_HORIZONTAL_LEFT); + private void positionBottomRight(TaskRecord task, ArrayList<TaskRecord> tasks, int width, + int height) { + mTmpProposal.set(mAvailableRect.right - width, mAvailableRect.bottom - height, + mAvailableRect.right, mAvailableRect.bottom); + position(task, tasks, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_LEFT); } - private void positionTopLeft(TaskRecord task, ArrayList<TaskRecord> tasks, - Rect availableRect, int width, int height) { - mTmpProposal.set(availableRect.left, availableRect.top, - availableRect.left + width, availableRect.top + height); - position(task, tasks, availableRect, mTmpProposal, !ALLOW_RESTART, - SHIFT_POLICY_HORIZONTAL_RIGHT); + private void positionTopLeft(TaskRecord task, ArrayList<TaskRecord> tasks, int width, + int height) { + mTmpProposal.set(mAvailableRect.left, mAvailableRect.top, + mAvailableRect.left + width, mAvailableRect.top + height); + position(task, tasks, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_RIGHT); } - private void positionTopRight(TaskRecord task, ArrayList<TaskRecord> tasks, - Rect availableRect, int width, int height) { - mTmpProposal.set(availableRect.right - width, availableRect.top, - availableRect.right, availableRect.top + height); - position(task, tasks, availableRect, mTmpProposal, !ALLOW_RESTART, - SHIFT_POLICY_HORIZONTAL_LEFT); + private void positionTopRight(TaskRecord task, ArrayList<TaskRecord> tasks, int width, + int height) { + mTmpProposal.set(mAvailableRect.right - width, mAvailableRect.top, + mAvailableRect.right, mAvailableRect.top + height); + position(task, tasks, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_LEFT); } - private void positionCenter(TaskRecord task, ArrayList<TaskRecord> tasks, - Rect availableRect, int width, int height) { - final int defaultFreeformLeft = getFreeformStartLeft(availableRect); - final int defaultFreeformTop = getFreeformStartTop(availableRect); - mTmpProposal.set(defaultFreeformLeft, defaultFreeformTop, - defaultFreeformLeft + width, defaultFreeformTop + height); - position(task, tasks, availableRect, mTmpProposal, ALLOW_RESTART, - SHIFT_POLICY_DIAGONAL_DOWN); + private void positionCenter(TaskRecord task, ArrayList<TaskRecord> tasks, int width, + int height) { + mTmpProposal.set(mDefaultFreeformStartX, mDefaultFreeformStartY, + mDefaultFreeformStartX + width, mDefaultFreeformStartY + height); + position(task, tasks, mTmpProposal, ALLOW_RESTART, SHIFT_POLICY_DIAGONAL_DOWN); } - private void position(TaskRecord task, ArrayList<TaskRecord> tasks, Rect availableRect, - Rect proposal, boolean allowRestart, int shiftPolicy) { + private void position(TaskRecord task, ArrayList<TaskRecord> tasks, Rect proposal, + boolean allowRestart, int shiftPolicy) { mTmpOriginal.set(proposal); boolean restarted = false; while (boundsConflict(proposal, tasks)) { // Unfortunately there is already a task at that spot, so we need to look for some // other place. - shiftStartingPoint(proposal, availableRect, shiftPolicy); - if (shiftedTooFar(proposal, availableRect, shiftPolicy)) { + shiftStartingPoint(proposal, shiftPolicy); + if (shiftedToFar(proposal, shiftPolicy)) { // We don't want the task to go outside of the stack, because it won't look // nice. Depending on the starting point we either restart, or immediately give up. if (!allowRestart) { @@ -238,13 +220,13 @@ class LaunchingTaskPositioner { } // We must have started not from the top. Let's restart from there because there // might be some space there. - proposal.set(availableRect.left, availableRect.top, - availableRect.left + proposal.width(), - availableRect.top + proposal.height()); + proposal.set(mAvailableRect.left, mAvailableRect.top, + mAvailableRect.left + proposal.width(), + mAvailableRect.top + proposal.height()); restarted = true; } - if (restarted && (proposal.left > getFreeformStartLeft(availableRect) - || proposal.top > getFreeformStartTop(availableRect))) { + if (restarted && (proposal.left > mDefaultFreeformStartX + || proposal.top > mDefaultFreeformStartY)) { // If we restarted and crossed the initial position, let's not struggle anymore. // The user already must have ton of tasks visible, we can just smack the new // one in the center. @@ -255,30 +237,27 @@ class LaunchingTaskPositioner { task.updateOverrideConfiguration(proposal); } - private boolean shiftedTooFar(Rect start, Rect availableRect, int shiftPolicy) { + private boolean shiftedToFar(Rect start, int shiftPolicy) { switch (shiftPolicy) { case SHIFT_POLICY_HORIZONTAL_LEFT: - return start.left < availableRect.left; + return start.left < mAvailableRect.left; case SHIFT_POLICY_HORIZONTAL_RIGHT: - return start.right > availableRect.right; + return start.right > mAvailableRect.right; default: // SHIFT_POLICY_DIAGONAL_DOWN - return start.right > availableRect.right || start.bottom > availableRect.bottom; + return start.right > mAvailableRect.right || start.bottom > mAvailableRect.bottom; } } - private void shiftStartingPoint(Rect posposal, Rect availableRect, int shiftPolicy) { - final int defaultFreeformStepHorizontal = getHorizontalStep(availableRect); - final int defaultFreeformStepVertical = getVerticalStep(availableRect); - + private void shiftStartingPoint(Rect posposal, int shiftPolicy) { switch (shiftPolicy) { case SHIFT_POLICY_HORIZONTAL_LEFT: - posposal.offset(-defaultFreeformStepHorizontal, 0); + posposal.offset(-mDefaultFreeformStepHorizontal, 0); break; case SHIFT_POLICY_HORIZONTAL_RIGHT: - posposal.offset(defaultFreeformStepHorizontal, 0); + posposal.offset(mDefaultFreeformStepHorizontal, 0); break; default: // SHIFT_POLICY_DIAGONAL_DOWN: - posposal.offset(defaultFreeformStepHorizontal, defaultFreeformStepVertical); + posposal.offset(mDefaultFreeformStepHorizontal, mDefaultFreeformStepVertical); break; } } @@ -317,4 +296,8 @@ class LaunchingTaskPositioner { return Math.abs(first.right - second.right) < BOUNDS_CONFLICT_MIN_DISTANCE && Math.abs(first.bottom - second.bottom) < BOUNDS_CONFLICT_MIN_DISTANCE; } + + void reset() { + mDefaultStartBoundsConfigurationSet = false; + } } diff --git a/com/android/server/am/LockTaskController.java b/com/android/server/am/LockTaskController.java index 940f9051..72b5de88 100644 --- a/com/android/server/am/LockTaskController.java +++ b/com/android/server/am/LockTaskController.java @@ -19,6 +19,7 @@ package com.android.server.am; import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED; import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED; +import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.app.StatusBarManager.DISABLE_BACK; import static android.app.StatusBarManager.DISABLE_HOME; import static android.app.StatusBarManager.DISABLE_MASK; @@ -58,6 +59,7 @@ import android.provider.Settings; import android.util.Slog; import android.util.SparseArray; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.widget.LockPatternUtils; @@ -431,7 +433,7 @@ public class LockTaskController { mWindowManager.executeAppTransition(); } else if (lockTaskModeState != LOCK_TASK_MODE_NONE) { mSupervisor.handleNonResizableTaskIfNeeded(task, WINDOWING_MODE_UNDEFINED, - DEFAULT_DISPLAY, task.getStack(), true /* forceNonResizable */); + DEFAULT_DISPLAY, task.getStackId(), true /* forceNonResizable */); } } @@ -492,7 +494,11 @@ public class LockTaskController { } for (int displayNdx = mSupervisor.getChildCount() - 1; displayNdx >= 0; --displayNdx) { - mSupervisor.getChildAt(displayNdx).onLockTaskPackagesUpdated(); + ArrayList<ActivityStack> stacks = mSupervisor.getChildAt(displayNdx).mStacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + stack.onLockTaskPackagesUpdatedLocked(); + } } final ActivityRecord r = mSupervisor.topRunningActivityLocked(); diff --git a/com/android/server/am/ProcessRecord.java b/com/android/server/am/ProcessRecord.java index e8477231..0e318d9c 100644 --- a/com/android/server/am/ProcessRecord.java +++ b/com/android/server/am/ProcessRecord.java @@ -27,7 +27,6 @@ import android.util.Slog; import com.android.internal.app.procstats.ProcessStats; import com.android.internal.app.procstats.ProcessState; import com.android.internal.os.BatteryStatsImpl; -import com.android.server.am.proto.ProcessRecordProto; import android.app.ActivityManager; import android.app.Dialog; @@ -45,7 +44,6 @@ import android.os.Trace; import android.os.UserHandle; import android.util.ArrayMap; import android.util.TimeUtils; -import android.util.proto.ProtoOutputStream; import java.io.PrintWriter; import java.util.ArrayList; @@ -623,22 +621,6 @@ final class ProcessRecord { } } - public void writeToProto(ProtoOutputStream proto, long fieldId) { - long token = proto.start(fieldId); - proto.write(ProcessRecordProto.PID, pid); - proto.write(ProcessRecordProto.PROCESS_NAME, processName); - if (info.uid < Process.FIRST_APPLICATION_UID) { - proto.write(ProcessRecordProto.UID, uid); - } else { - proto.write(ProcessRecordProto.USER_ID, userId); - proto.write(ProcessRecordProto.APP_ID, UserHandle.getAppId(info.uid)); - if (uid != info.uid) { - proto.write(ProcessRecordProto.ISOLATED_APP_ID, UserHandle.getAppId(uid)); - } - } - proto.end(token); - } - public String toShortString() { if (shortStringName != null) { return shortStringName; diff --git a/com/android/server/am/ReceiverList.java b/com/android/server/am/ReceiverList.java index a9890631..6ade7361 100644 --- a/com/android/server/am/ReceiverList.java +++ b/com/android/server/am/ReceiverList.java @@ -21,8 +21,6 @@ import android.os.Binder; import android.os.IBinder; import android.util.PrintWriterPrinter; import android.util.Printer; -import android.util.proto.ProtoOutputStream; -import com.android.server.am.proto.ReceiverListProto; import java.io.PrintWriter; import java.util.ArrayList; @@ -43,7 +41,7 @@ final class ReceiverList extends ArrayList<BroadcastFilter> boolean linkedToDeath = false; String stringName; - + ReceiverList(ActivityManagerService _owner, ProcessRecord _app, int _pid, int _uid, int _userId, IIntentReceiver _receiver) { owner = _owner; @@ -61,31 +59,12 @@ final class ReceiverList extends ArrayList<BroadcastFilter> public int hashCode() { return System.identityHashCode(this); } - + public void binderDied() { linkedToDeath = false; owner.unregisterReceiver(receiver); } - - void writeToProto(ProtoOutputStream proto, long fieldId) { - long token = proto.start(fieldId); - app.writeToProto(proto, ReceiverListProto.APP); - proto.write(ReceiverListProto.PID, pid); - proto.write(ReceiverListProto.UID, uid); - proto.write(ReceiverListProto.USER, userId); - if (curBroadcast != null) { - curBroadcast.writeToProto(proto, ReceiverListProto.CURRENT); - } - proto.write(ReceiverListProto.LINKED_TO_DEATH, linkedToDeath); - final int N = size(); - for (int i=0; i<N; i++) { - BroadcastFilter bf = get(i); - bf.writeToProto(proto, ReceiverListProto.FILTERS); - } - proto.write(ReceiverListProto.HEX_HASH, Integer.toHexString(System.identityHashCode(this))); - proto.end(token); - } - + void dumpLocal(PrintWriter pw, String prefix) { pw.print(prefix); pw.print("app="); pw.print(app != null ? app.toShortString() : null); pw.print(" pid="); pw.print(pid); pw.print(" uid="); pw.print(uid); @@ -95,7 +74,7 @@ final class ReceiverList extends ArrayList<BroadcastFilter> pw.print(" linkedToDeath="); pw.println(linkedToDeath); } } - + void dump(PrintWriter pw, String prefix) { Printer pr = new PrintWriterPrinter(pw); dumpLocal(pw, prefix); @@ -110,7 +89,7 @@ final class ReceiverList extends ArrayList<BroadcastFilter> bf.dumpInReceiverList(pw, pr, p2); } } - + public String toString() { if (stringName != null) { return stringName; diff --git a/com/android/server/am/RecentTasks.java b/com/android/server/am/RecentTasks.java index 78274bdc..365c5b1d 100644 --- a/com/android/server/am/RecentTasks.java +++ b/com/android/server/am/RecentTasks.java @@ -16,25 +16,15 @@ package com.android.server.am; -import static android.app.ActivityManager.FLAG_AND_UNLOCKED; -import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE; -import static android.app.ActivityManager.RECENT_WITH_EXCLUDED; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; -import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; -import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; - import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS_TRIM_TASKS; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_TASKS; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; -import static com.android.server.am.ActivityStackSupervisor.REMOVE_FROM_RECENTS; import static com.android.server.am.TaskRecord.INVALID_TASK_ID; import com.google.android.collect.Sets; @@ -47,87 +37,43 @@ import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; -import android.content.pm.ParceledListSlice; -import android.content.pm.UserInfo; -import android.content.res.Resources; import android.graphics.Bitmap; -import android.graphics.Rect; -import android.os.Bundle; import android.os.Environment; -import android.os.IBinder; import android.os.RemoteException; -import android.os.SystemProperties; import android.os.UserHandle; import android.util.ArraySet; -import android.util.MutableBoolean; -import android.util.MutableInt; import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; -import com.android.internal.annotations.VisibleForTesting; -import com.android.server.am.ActivityStack.ActivityState; - import java.io.File; -import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; -import java.util.HashSet; import java.util.Set; -import java.util.concurrent.TimeUnit; /** - * Class for managing the recent tasks list. The list is ordered by most recent (index 0) to the - * least recent. + * Class for managing the recent tasks list. */ -class RecentTasks { +class RecentTasks extends ArrayList<TaskRecord> { private static final String TAG = TAG_WITH_CLASS_NAME ? "RecentTasks" : TAG_AM; private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS; private static final String TAG_TASKS = TAG + POSTFIX_TASKS; - private static final boolean TRIMMED = true; + // Maximum number recent bitmaps to keep in memory. + private static final int MAX_RECENT_BITMAPS = 3; private static final int DEFAULT_INITIAL_CAPACITY = 5; // Whether or not to move all affiliated tasks to the front when one of the tasks is launched private static final boolean MOVE_AFFILIATED_TASKS_TO_FRONT = false; - // Comparator to sort by taskId - private static final Comparator<TaskRecord> TASK_ID_COMPARATOR = - (lhs, rhs) -> rhs.taskId - lhs.taskId; - - // Placeholder variables to keep track of activities/apps that are no longer avialble while - // iterating through the recents list - private static final ActivityInfo NO_ACTIVITY_INFO_TOKEN = new ActivityInfo(); - private static final ApplicationInfo NO_APPLICATION_INFO_TOKEN = new ApplicationInfo(); - - /** - * Callbacks made when manipulating the list. - */ - interface Callbacks { - /** - * Called when a task is added to the recent tasks list. - */ - void onRecentTaskAdded(TaskRecord task); - - /** - * Called when a task is removed from the recent tasks list. - */ - void onRecentTaskRemoved(TaskRecord task, boolean wasTrimmed); - } - /** * Save recent tasks information across reboots. */ private final TaskPersister mTaskPersister; private final ActivityManagerService mService; - private final UserController mUserController; - - /** - * Mapping of user id -> whether recent tasks have been loaded for that user. - */ private final SparseBooleanArray mUsersWithRecentsLoaded = new SparseBooleanArray( DEFAULT_INITIAL_CAPACITY); @@ -135,106 +81,21 @@ class RecentTasks { * Stores for each user task ids that are taken by tasks residing in persistent storage. These * tasks may or may not currently be in memory. */ - private final SparseArray<SparseBooleanArray> mPersistedTaskIds = new SparseArray<>( + final SparseArray<SparseBooleanArray> mPersistedTaskIds = new SparseArray<>( DEFAULT_INITIAL_CAPACITY); - // List of all active recent tasks - private final ArrayList<TaskRecord> mTasks = new ArrayList<>(); - private final ArrayList<Callbacks> mCallbacks = new ArrayList<>(); - - // These values are generally loaded from resources, but can be set dynamically in the tests - private boolean mHasVisibleRecentTasks; - private int mGlobalMaxNumTasks; - private int mMinNumVisibleTasks; - private int mMaxNumVisibleTasks; - private long mActiveTasksSessionDurationMs; - // Mainly to avoid object recreation on multiple calls. - private final ArrayList<TaskRecord> mTmpRecents = new ArrayList<>(); + private final ArrayList<TaskRecord> mTmpRecents = new ArrayList<TaskRecord>(); private final HashMap<ComponentName, ActivityInfo> mTmpAvailActCache = new HashMap<>(); private final HashMap<String, ApplicationInfo> mTmpAvailAppCache = new HashMap<>(); - private final SparseBooleanArray mTmpQuietProfileUserIds = new SparseBooleanArray(); + private final ActivityInfo mTmpActivityInfo = new ActivityInfo(); + private final ApplicationInfo mTmpAppInfo = new ApplicationInfo(); - @VisibleForTesting - RecentTasks(ActivityManagerService service, TaskPersister taskPersister, - UserController userController) { + RecentTasks(ActivityManagerService service, ActivityStackSupervisor mStackSupervisor) { + File systemDir = Environment.getDataSystemDirectory(); mService = service; - mUserController = userController; - mTaskPersister = taskPersister; - mGlobalMaxNumTasks = ActivityManager.getMaxRecentTasksStatic(); - mHasVisibleRecentTasks = true; - } - - RecentTasks(ActivityManagerService service, ActivityStackSupervisor stackSupervisor) { - final File systemDir = Environment.getDataSystemDirectory(); - final Resources res = service.mContext.getResources(); - mService = service; - mUserController = service.mUserController; - mTaskPersister = new TaskPersister(systemDir, stackSupervisor, service, this); - mGlobalMaxNumTasks = ActivityManager.getMaxRecentTasksStatic(); - mHasVisibleRecentTasks = res.getBoolean(com.android.internal.R.bool.config_hasRecents); - loadParametersFromResources(service.mContext.getResources()); - } - - @VisibleForTesting - void setParameters(int minNumVisibleTasks, int maxNumVisibleTasks, - long activeSessionDurationMs) { - mMinNumVisibleTasks = minNumVisibleTasks; - mMaxNumVisibleTasks = maxNumVisibleTasks; - mActiveTasksSessionDurationMs = activeSessionDurationMs; - } - - @VisibleForTesting - void setGlobalMaxNumTasks(int globalMaxNumTasks) { - mGlobalMaxNumTasks = globalMaxNumTasks; - } - - /** - * Loads the parameters from the system resources. - */ - @VisibleForTesting - void loadParametersFromResources(Resources res) { - if (ActivityManager.isLowRamDeviceStatic()) { - mMinNumVisibleTasks = res.getInteger( - com.android.internal.R.integer.config_minNumVisibleRecentTasks_lowRam); - mMaxNumVisibleTasks = res.getInteger( - com.android.internal.R.integer.config_maxNumVisibleRecentTasks_lowRam); - } else if (SystemProperties.getBoolean("ro.recents.grid", false)) { - mMinNumVisibleTasks = res.getInteger( - com.android.internal.R.integer.config_minNumVisibleRecentTasks_grid); - mMaxNumVisibleTasks = res.getInteger( - com.android.internal.R.integer.config_maxNumVisibleRecentTasks_grid); - } else { - mMinNumVisibleTasks = res.getInteger( - com.android.internal.R.integer.config_minNumVisibleRecentTasks); - mMaxNumVisibleTasks = res.getInteger( - com.android.internal.R.integer.config_maxNumVisibleRecentTasks); - } - final int sessionDurationHrs = res.getInteger( - com.android.internal.R.integer.config_activeTaskDurationHours); - mActiveTasksSessionDurationMs = (sessionDurationHrs > 0) - ? TimeUnit.HOURS.toMillis(sessionDurationHrs) - : -1; - } - - void registerCallback(Callbacks callback) { - mCallbacks.add(callback); - } - - void unregisterCallback(Callbacks callback) { - mCallbacks.remove(callback); - } - - private void notifyTaskAdded(TaskRecord task) { - for (int i = 0; i < mCallbacks.size(); i++) { - mCallbacks.get(i).onRecentTaskAdded(task); - } - } - - private void notifyTaskRemoved(TaskRecord task, boolean wasTrimmed) { - for (int i = 0; i < mCallbacks.size(); i++) { - mCallbacks.get(i).onRecentTaskRemoved(task, wasTrimmed); - } + mTaskPersister = new TaskPersister(systemDir, mStackSupervisor, service, this); + mStackSupervisor.setRecentTasks(this); } /** @@ -245,7 +106,6 @@ class RecentTasks { */ void loadUserRecentsLocked(int userId) { if (mUsersWithRecentsLoaded.get(userId)) { - // User already loaded, return early return; } @@ -254,14 +114,14 @@ class RecentTasks { // Check if any tasks are added before recents is loaded final SparseBooleanArray preaddedTasks = new SparseBooleanArray(); - for (final TaskRecord task : mTasks) { + for (final TaskRecord task : this) { if (task.userId == userId && shouldPersistTaskLocked(task)) { preaddedTasks.put(task.taskId, true); } } Slog.i(TAG, "Loading recents for user " + userId + " into memory."); - mTasks.addAll(mTaskPersister.restoreTasksForUserLocked(userId, preaddedTasks)); + addAll(mTaskPersister.restoreTasksForUserLocked(userId, preaddedTasks)); cleanupLocked(userId); mUsersWithRecentsLoaded.put(userId, true); @@ -280,25 +140,11 @@ class RecentTasks { } } - /** - * @return whether the {@param taskId} is currently in use for the given user. - */ - boolean containsTaskId(int taskId, int userId) { + boolean taskIdTakenForUserLocked(int taskId, int userId) { loadPersistedTaskIdsForUserLocked(userId); return mPersistedTaskIds.get(userId).get(taskId); } - /** - * @return all the task ids for the user with the given {@param userId}. - */ - SparseBooleanArray getTaskIdsForUser(int userId) { - loadPersistedTaskIdsForUserLocked(userId); - return mPersistedTaskIds.get(userId); - } - - /** - * Kicks off the task persister to write any pending tasks to disk. - */ void notifyTaskPersisterLocked(TaskRecord task, boolean flush) { final ActivityStack stack = task != null ? task.getStack() : null; if (stack != null && stack.isHomeOrRecentsStack()) { @@ -318,8 +164,8 @@ class RecentTasks { mPersistedTaskIds.valueAt(i).clear(); } } - for (int i = mTasks.size() - 1; i >= 0; i--) { - final TaskRecord task = mTasks.get(i); + for (int i = size() - 1; i >= 0; i--) { + final TaskRecord task = get(i); if (shouldPersistTaskLocked(task)) { // Set of persisted taskIds for task.userId should not be null here // TODO Investigate why it can happen. For now initialize with an empty set @@ -334,12 +180,12 @@ class RecentTasks { } private static boolean shouldPersistTaskLocked(TaskRecord task) { - final ActivityStack stack = task.getStack(); + final ActivityStack<?> stack = task.getStack(); return task.isPersistable && (stack == null || !stack.isHomeOrRecentsStack()); } void onSystemReadyLocked() { - mTasks.clear(); + clear(); mTaskPersister.startPersisting(); } @@ -379,6 +225,14 @@ class RecentTasks { return usersWithRecentsLoaded; } + private void unloadUserRecentsLocked(int userId) { + if (mUsersWithRecentsLoaded.get(userId)) { + Slog.i(TAG, "Unloading recents for user " + userId + " from memory."); + mUsersWithRecentsLoaded.delete(userId); + removeTasksForUserLocked(userId); + } + } + /** * Removes recent tasks and any other state kept in memory for the passed in user. Does not * touch the information present on persistent storage. @@ -386,36 +240,44 @@ class RecentTasks { * @param userId the id of the user */ void unloadUserDataFromMemoryLocked(int userId) { - if (mUsersWithRecentsLoaded.get(userId)) { - Slog.i(TAG, "Unloading recents for user " + userId + " from memory."); - mUsersWithRecentsLoaded.delete(userId); - removeTasksForUserLocked(userId); - } + unloadUserRecentsLocked(userId); mPersistedTaskIds.delete(userId); mTaskPersister.unloadUserDataFromMemory(userId); } + TaskRecord taskForIdLocked(int id) { + final int recentsCount = size(); + for (int i = 0; i < recentsCount; i++) { + TaskRecord tr = get(i); + if (tr.taskId == id) { + return tr; + } + } + return null; + } + /** Remove recent tasks for a user. */ - private void removeTasksForUserLocked(int userId) { + void removeTasksForUserLocked(int userId) { if(userId <= 0) { Slog.i(TAG, "Can't remove recent task on user " + userId); return; } - for (int i = mTasks.size() - 1; i >= 0; --i) { - TaskRecord tr = mTasks.get(i); + for (int i = size() - 1; i >= 0; --i) { + TaskRecord tr = get(i); if (tr.userId == userId) { if(DEBUG_TASKS) Slog.i(TAG_TASKS, "remove RecentTask " + tr + " when finishing user" + userId); - remove(mTasks.get(i)); + remove(i); + tr.removedFromRecents(); } } } void onPackagesSuspendedChanged(String[] packages, boolean suspended, int userId) { final Set<String> packageNames = Sets.newHashSet(packages); - for (int i = mTasks.size() - 1; i >= 0; --i) { - final TaskRecord tr = mTasks.get(i); + for (int i = size() - 1; i >= 0; --i) { + final TaskRecord tr = get(i); if (tr.realActivity != null && packageNames.contains(tr.realActivity.getPackageName()) && tr.userId == userId @@ -424,36 +286,7 @@ class RecentTasks { notifyTaskPersisterLocked(tr, false); } } - } - - void removeTasksByPackageName(String packageName, int userId) { - for (int i = mTasks.size() - 1; i >= 0; --i) { - final TaskRecord tr = mTasks.get(i); - final String taskPackageName = - tr.getBaseIntent().getComponent().getPackageName(); - if (tr.userId != userId) return; - if (!taskPackageName.equals(packageName)) return; - - mService.mStackSupervisor.removeTaskByIdLocked(tr.taskId, true, REMOVE_FROM_RECENTS); - } - } - - void cleanupDisabledPackageTasksLocked(String packageName, Set<String> filterByClasses, - int userId) { - for (int i = mTasks.size() - 1; i >= 0; --i) { - final TaskRecord tr = mTasks.get(i); - if (userId != UserHandle.USER_ALL && tr.userId != userId) { - continue; - } - ComponentName cn = tr.intent.getComponent(); - final boolean sameComponent = cn != null && cn.getPackageName().equals(packageName) - && (filterByClasses == null || filterByClasses.contains(cn.getClassName())); - if (sameComponent) { - mService.mStackSupervisor.removeTaskByIdLocked(tr.taskId, false, - REMOVE_FROM_RECENTS); - } - } } /** @@ -462,28 +295,24 @@ class RecentTasks { * of affiliations. */ void cleanupLocked(int userId) { - int recentsCount = mTasks.size(); + int recentsCount = size(); if (recentsCount == 0) { // Happens when called from the packagemanager broadcast before boot, // or just any empty list. return; } - // Clear the temp lists - mTmpAvailActCache.clear(); - mTmpAvailAppCache.clear(); - final IPackageManager pm = AppGlobals.getPackageManager(); for (int i = recentsCount - 1; i >= 0; i--) { - final TaskRecord task = mTasks.get(i); + final TaskRecord task = get(i); if (userId != UserHandle.USER_ALL && task.userId != userId) { // Only look at tasks for the user ID of interest. continue; } if (task.autoRemoveRecents && task.getTopActivity() == null) { // This situation is broken, and we should just get rid of it now. - mTasks.remove(i); - notifyTaskRemoved(task, !TRIMMED); + remove(i); + task.removedFromRecents(); Slog.w(TAG, "Removing auto-remove without activity: " + task); continue; } @@ -502,11 +331,11 @@ class RecentTasks { continue; } if (ai == null) { - ai = NO_ACTIVITY_INFO_TOKEN; + ai = mTmpActivityInfo; } mTmpAvailActCache.put(task.realActivity, ai); } - if (ai == NO_ACTIVITY_INFO_TOKEN) { + if (ai == mTmpActivityInfo) { // This could be either because the activity no longer exists, or the // app is temporarily gone. For the former we want to remove the recents // entry; for the latter we want to mark it as unavailable. @@ -521,15 +350,15 @@ class RecentTasks { continue; } if (app == null) { - app = NO_APPLICATION_INFO_TOKEN; + app = mTmpAppInfo; } mTmpAvailAppCache.put(task.realActivity.getPackageName(), app); } - if (app == NO_APPLICATION_INFO_TOKEN + if (app == mTmpAppInfo || (app.flags & ApplicationInfo.FLAG_INSTALLED) == 0) { // Doesn't exist any more! Good-bye. - mTasks.remove(i); - notifyTaskRemoved(task, !TRIMMED); + remove(i); + task.removedFromRecents(); Slog.w(TAG, "Removing no longer valid recent: " + task); continue; } else { @@ -561,197 +390,121 @@ class RecentTasks { // Verify the affiliate chain for each task. int i = 0; - recentsCount = mTasks.size(); + recentsCount = size(); while (i < recentsCount) { i = processNextAffiliateChainLocked(i); } // recent tasks are now in sorted, affiliated order. } - /** - * @return whether the given {@param task} can be added to the list without causing another - * task to be trimmed as a result of that add. - */ - private boolean canAddTaskWithoutTrim(TaskRecord task) { - return findTrimIndexForAddTask(task) == -1; - } - - /** - * Returns the list of {@link ActivityManager.AppTask}s. - */ - ArrayList<IBinder> getAppTasksList(int callingUid, String callingPackage) { - final ArrayList<IBinder> list = new ArrayList<>(); - final int size = mTasks.size(); - for (int i = 0; i < size; i++) { - final TaskRecord tr = mTasks.get(i); - // Skip tasks that do not match the caller. We don't need to verify - // callingPackage, because we are also limiting to callingUid and know - // that will limit to the correct security sandbox. - if (tr.effectiveUid != callingUid) { - continue; - } - Intent intent = tr.getBaseIntent(); - if (intent == null || !callingPackage.equals(intent.getComponent().getPackageName())) { - continue; - } - ActivityManager.RecentTaskInfo taskInfo = createRecentTaskInfo(tr); - AppTaskImpl taskImpl = new AppTaskImpl(mService, taskInfo.persistentId, callingUid); - list.add(taskImpl.asBinder()); - } - return list; - } - - /** - * @return the list of recent tasks for presentation. - */ - ParceledListSlice<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum, int flags, - boolean getTasksAllowed, boolean getDetailedTasks, int userId, int callingUid) { - final boolean withExcluded = (flags & RECENT_WITH_EXCLUDED) != 0; - - if (!mService.isUserRunning(userId, FLAG_AND_UNLOCKED)) { - Slog.i(TAG, "user " + userId + " is still locked. Cannot load recents"); - return ParceledListSlice.emptyList(); + private final boolean moveAffiliatedTasksToFront(TaskRecord task, int taskIndex) { + int recentsCount = size(); + TaskRecord top = task; + int topIndex = taskIndex; + while (top.mNextAffiliate != null && topIndex > 0) { + top = top.mNextAffiliate; + topIndex--; } - loadUserRecentsLocked(userId); - - final Set<Integer> includedUsers = mUserController.getProfileIds(userId); - includedUsers.add(Integer.valueOf(userId)); - - final ArrayList<ActivityManager.RecentTaskInfo> res = new ArrayList<>(); - final int size = mTasks.size(); - int numVisibleTasks = 0; - for (int i = 0; i < size; i++) { - final TaskRecord tr = mTasks.get(i); - - if (isVisibleRecentTask(tr)) { - numVisibleTasks++; - if (isInVisibleRange(tr, numVisibleTasks)) { - // Fall through - } else { - // Not in visible range - continue; + if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: adding affilliates starting at " + + topIndex + " from intial " + taskIndex); + // Find the end of the chain, doing a sanity check along the way. + boolean sane = top.mAffiliatedTaskId == task.mAffiliatedTaskId; + int endIndex = topIndex; + TaskRecord prev = top; + while (endIndex < recentsCount) { + TaskRecord cur = get(endIndex); + if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: looking at next chain @" + + endIndex + " " + cur); + if (cur == top) { + // Verify start of the chain. + if (cur.mNextAffiliate != null || cur.mNextAffiliateTaskId != INVALID_TASK_ID) { + Slog.wtf(TAG, "Bad chain @" + endIndex + + ": first task has next affiliate: " + prev); + sane = false; + break; } } else { - // Not visible - continue; - } - - // Skip remaining tasks once we reach the requested size - if (res.size() >= maxNum) { - continue; - } - - // Only add calling user or related users recent tasks - if (!includedUsers.contains(Integer.valueOf(tr.userId))) { - if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not user: " + tr); - continue; - } - - if (tr.realActivitySuspended) { - if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, activity suspended: " + tr); - continue; - } - - // Return the entry if desired by the caller. We always return - // the first entry, because callers always expect this to be the - // foreground app. We may filter others if the caller has - // not supplied RECENT_WITH_EXCLUDED and there is some reason - // we should exclude the entry. - - if (i == 0 - || withExcluded - || (tr.intent == null) - || ((tr.intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) - == 0)) { - if (!getTasksAllowed) { - // If the caller doesn't have the GET_TASKS permission, then only - // allow them to see a small subset of tasks -- their own and home. - if (!tr.isActivityTypeHome() && tr.effectiveUid != callingUid) { - if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not allowed: " + tr); - continue; - } - } - if (tr.autoRemoveRecents && tr.getTopActivity() == null) { - // Don't include auto remove tasks that are finished or finishing. - if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, - "Skipping, auto-remove without activity: " + tr); - continue; - } - if ((flags & RECENT_IGNORE_UNAVAILABLE) != 0 && !tr.isAvailable) { - if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, - "Skipping, unavail real act: " + tr); - continue; + // Verify middle of the chain's next points back to the one before. + if (cur.mNextAffiliate != prev + || cur.mNextAffiliateTaskId != prev.taskId) { + Slog.wtf(TAG, "Bad chain @" + endIndex + + ": middle task " + cur + " @" + endIndex + + " has bad next affiliate " + + cur.mNextAffiliate + " id " + cur.mNextAffiliateTaskId + + ", expected " + prev); + sane = false; + break; } - - if (!tr.mUserSetupComplete) { - // Don't include task launched while user is not done setting-up. - if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, - "Skipping, user setup not complete: " + tr); - continue; + } + if (cur.mPrevAffiliateTaskId == INVALID_TASK_ID) { + // Chain ends here. + if (cur.mPrevAffiliate != null) { + Slog.wtf(TAG, "Bad chain @" + endIndex + + ": last task " + cur + " has previous affiliate " + + cur.mPrevAffiliate); + sane = false; } - - ActivityManager.RecentTaskInfo rti = RecentTasks.createRecentTaskInfo(tr); - if (!getDetailedTasks) { - rti.baseIntent.replaceExtras((Bundle)null); + if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: end of chain @" + endIndex); + break; + } else { + // Verify middle of the chain's prev points to a valid item. + if (cur.mPrevAffiliate == null) { + Slog.wtf(TAG, "Bad chain @" + endIndex + + ": task " + cur + " has previous affiliate " + + cur.mPrevAffiliate + " but should be id " + + cur.mPrevAffiliate); + sane = false; + break; } - - res.add(rti); + } + if (cur.mAffiliatedTaskId != task.mAffiliatedTaskId) { + Slog.wtf(TAG, "Bad chain @" + endIndex + + ": task " + cur + " has affiliated id " + + cur.mAffiliatedTaskId + " but should be " + + task.mAffiliatedTaskId); + sane = false; + break; + } + prev = cur; + endIndex++; + if (endIndex >= recentsCount) { + Slog.wtf(TAG, "Bad chain ran off index " + endIndex + + ": last task " + prev); + sane = false; + break; } } - return new ParceledListSlice<>(res); - } - - /** - * @return the list of persistable task ids. - */ - void getPersistableTaskIds(ArraySet<Integer> persistentTaskIds) { - final int size = mTasks.size(); - for (int i = 0; i < size; i++) { - final TaskRecord task = mTasks.get(i); - if (TaskPersister.DEBUG) Slog.d(TAG, "LazyTaskWriter: task=" + task - + " persistable=" + task.isPersistable); - final ActivityStack stack = task.getStack(); - if ((task.isPersistable || task.inRecents) - && (stack == null || !stack.isHomeOrRecentsStack())) { - if (TaskPersister.DEBUG) Slog.d(TAG, "adding to persistentTaskIds task=" + task); - persistentTaskIds.add(task.taskId); - } else { - if (TaskPersister.DEBUG) Slog.d(TAG, "omitting from persistentTaskIds task=" - + task); + if (sane) { + if (endIndex < taskIndex) { + Slog.wtf(TAG, "Bad chain @" + endIndex + + ": did not extend to task " + task + " @" + taskIndex); + sane = false; } } - } - - @VisibleForTesting - ArrayList<TaskRecord> getRawTasks() { - return mTasks; - } - - /** - * @return the task in the task list with the given {@param id} if one exists. - */ - TaskRecord getTask(int id) { - final int recentsCount = mTasks.size(); - for (int i = 0; i < recentsCount; i++) { - TaskRecord tr = mTasks.get(i); - if (tr.taskId == id) { - return tr; + if (sane) { + // All looks good, we can just move all of the affiliated tasks + // to the top. + for (int i=topIndex; i<=endIndex; i++) { + if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: moving affiliated " + task + + " from " + i + " to " + (i-topIndex)); + TaskRecord cur = remove(i); + add(i - topIndex, cur); } + if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: done moving tasks " + topIndex + + " to " + endIndex); + return true; } - return null; - } - /** - * Add a new task to the recent tasks list. - */ - void add(TaskRecord task) { - if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "add: task=" + task); + // Whoops, couldn't do it. + return false; + } + final void addLocked(TaskRecord task) { final boolean isAffiliated = task.mAffiliatedTaskId != task.taskId || task.mNextAffiliateTaskId != INVALID_TASK_ID || task.mPrevAffiliateTaskId != INVALID_TASK_ID; - int recentsCount = mTasks.size(); + int recentsCount = size(); // Quick case: never add voice sessions. // TODO: VI what about if it's just an activity? // Probably nothing to do here @@ -761,15 +514,15 @@ class RecentTasks { return; } // Another quick case: check if the top-most recent task is the same. - if (!isAffiliated && recentsCount > 0 && mTasks.get(0) == task) { + if (!isAffiliated && recentsCount > 0 && get(0) == task) { if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: already at top: " + task); return; } // Another quick case: check if this is part of a set of affiliated // tasks that are at the top. if (isAffiliated && recentsCount > 0 && task.inRecents - && task.mAffiliatedTaskId == mTasks.get(0).mAffiliatedTaskId) { - if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: affiliated " + mTasks.get(0) + && task.mAffiliatedTaskId == get(0).mAffiliatedTaskId) { + if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: affiliated " + get(0) + " at top when adding " + task); return; } @@ -779,12 +532,12 @@ class RecentTasks { // Slightly less quick case: the task is already in recents, so all we need // to do is move it. if (task.inRecents) { - int taskIndex = mTasks.indexOf(task); + int taskIndex = indexOf(task); if (taskIndex >= 0) { - if (!isAffiliated || !MOVE_AFFILIATED_TASKS_TO_FRONT) { + if (!isAffiliated || MOVE_AFFILIATED_TASKS_TO_FRONT) { // Simple case: this is not an affiliated task, so we just move it to the front. - mTasks.remove(taskIndex); - mTasks.add(0, task); + remove(taskIndex); + add(0, task); notifyTaskPersisterLocked(task, false); if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: moving to top " + task + " from " + taskIndex); @@ -807,14 +560,20 @@ class RecentTasks { } if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: trimming tasks for " + task); - trimForAddTask(task); + trimForTaskLocked(task, true); + recentsCount = size(); + final int maxRecents = ActivityManager.getMaxRecentTasksStatic(); + while (recentsCount >= maxRecents) { + final TaskRecord tr = remove(recentsCount - 1); + tr.removedFromRecents(); + recentsCount--; + } task.inRecents = true; if (!isAffiliated || needAffiliationFix) { // If this is a simple non-affiliated task, or we had some failure trying to // handle it as part of an affilated task, then just place it at the top. - mTasks.add(0, task); - notifyTaskAdded(task); + add(0, task); if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: adding " + task); } else if (isAffiliated) { // If this is a new affiliated task, then move all of the affiliated tasks @@ -824,7 +583,7 @@ class RecentTasks { other = task.mPrevAffiliate; } if (other != null) { - int otherIndex = mTasks.indexOf(other); + int otherIndex = indexOf(other); if (otherIndex >= 0) { // Insert new task at appropriate location. int taskIndex; @@ -839,8 +598,7 @@ class RecentTasks { } if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: new affiliated task added at " + taskIndex + ": " + task); - mTasks.add(taskIndex, task); - notifyTaskAdded(task); + add(taskIndex, task); // Now move everything to the front. if (moveAffiliatedTasksToFront(task, taskIndex)) { @@ -867,235 +625,21 @@ class RecentTasks { if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: regrouping affiliations"); cleanupLocked(task.userId); } - - // Trim the set of tasks to the active set - trimInactiveRecentTasks(); - } - - /** - * Add the task to the bottom if possible. - */ - boolean addToBottom(TaskRecord task) { - if (!canAddTaskWithoutTrim(task)) { - // Adding this task would cause the task to be removed (since it's appended at - // the bottom and would be trimmed) so just return now - return false; - } - - add(task); - return true; - } - - /** - * Remove a task from the recent tasks list. - */ - void remove(TaskRecord task) { - mTasks.remove(task); - notifyTaskRemoved(task, !TRIMMED); - } - - /** - * Trims the recents task list to the global max number of recents. - */ - private void trimInactiveRecentTasks() { - int recentsCount = mTasks.size(); - - // Remove from the end of the list until we reach the max number of recents - while (recentsCount > mGlobalMaxNumTasks) { - final TaskRecord tr = mTasks.remove(recentsCount - 1); - notifyTaskRemoved(tr, TRIMMED); - recentsCount--; - if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "Trimming over max-recents task=" + tr - + " max=" + mGlobalMaxNumTasks); - } - - // Remove any tasks that belong to currently quiet profiles - final int[] profileUserIds = mUserController.getCurrentProfileIds(); - mTmpQuietProfileUserIds.clear(); - for (int userId : profileUserIds) { - final UserInfo userInfo = mUserController.getUserInfo(userId); - if (userInfo.isManagedProfile() && userInfo.isQuietModeEnabled()) { - mTmpQuietProfileUserIds.put(userId, true); - } - if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "User: " + userInfo - + " quiet=" + mTmpQuietProfileUserIds.get(userId)); - } - - // Remove any inactive tasks, calculate the latest set of visible tasks - int numVisibleTasks = 0; - for (int i = 0; i < mTasks.size();) { - final TaskRecord task = mTasks.get(i); - - if (isActiveRecentTask(task, mTmpQuietProfileUserIds)) { - if (!mHasVisibleRecentTasks) { - // Keep all active tasks if visible recent tasks is not supported - i++; - continue; - } - - if (!isVisibleRecentTask(task)) { - // Keep all active-but-invisible tasks - i++; - continue; - } else { - numVisibleTasks++; - if (isInVisibleRange(task, numVisibleTasks)) { - // Keep visible tasks in range - i++; - continue; - } else { - // Fall through to trim visible tasks that are no longer in range - if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, - "Trimming out-of-range visible task=" + task); - } - } - } else { - // Fall through to trim inactive tasks - if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "Trimming inactive task=" + task); - } - - // Task is no longer active, trim it from the list - mTasks.remove(task); - notifyTaskRemoved(task, TRIMMED); - notifyTaskPersisterLocked(task, false /* flush */); - } - } - - /** - * @return whether the given task should be considered active. - */ - private boolean isActiveRecentTask(TaskRecord task, SparseBooleanArray quietProfileUserIds) { - if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "isActiveRecentTask: task=" + task - + " globalMax=" + mGlobalMaxNumTasks); - - if (quietProfileUserIds.get(task.userId)) { - // Quiet profile user's tasks are never active - if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "\tisQuietProfileTask=true"); - return false; - } - - if (task.mAffiliatedTaskId != INVALID_TASK_ID && task.mAffiliatedTaskId != task.taskId) { - // Keep the task active if its affiliated task is also active - final TaskRecord affiliatedTask = getTask(task.mAffiliatedTaskId); - if (affiliatedTask != null) { - if (!isActiveRecentTask(affiliatedTask, quietProfileUserIds)) { - if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, - "\taffiliatedWithTask=" + affiliatedTask + " is not active"); - return false; - } - } - } - - // All other tasks are considered active - return true; - } - - /** - * @return whether the given active task should be presented to the user through SystemUI. - */ - private boolean isVisibleRecentTask(TaskRecord task) { - if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "isVisibleRecentTask: task=" + task - + " minVis=" + mMinNumVisibleTasks + " maxVis=" + mMaxNumVisibleTasks - + " sessionDuration=" + mActiveTasksSessionDurationMs - + " inactiveDuration=" + task.getInactiveDuration() - + " activityType=" + task.getActivityType() - + " windowingMode=" + task.getWindowingMode()); - - // Ignore certain activity types completely - switch (task.getActivityType()) { - case ACTIVITY_TYPE_HOME: - case ACTIVITY_TYPE_RECENTS: - return false; - } - - // Ignore certain windowing modes - switch (task.getWindowingMode()) { - case WINDOWING_MODE_PINNED: - return false; - case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY: - if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "\ttop=" + task.getStack().topTask()); - final ActivityStack stack = task.getStack(); - if (stack != null && stack.topTask() == task) { - // Only the non-top task of the primary split screen mode is visible - return false; - } - } - - return true; - } - - /** - * @return whether the given visible task is within the policy range. - */ - private boolean isInVisibleRange(TaskRecord task, int numVisibleTasks) { - // Keep the last most task even if it is excluded from recents - final boolean isExcludeFromRecents = - (task.getBaseIntent().getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) - == Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; - if (isExcludeFromRecents) { - if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "\texcludeFromRecents=true"); - return numVisibleTasks == 1; - } - - if (mMinNumVisibleTasks >= 0 && numVisibleTasks <= mMinNumVisibleTasks) { - // Always keep up to the min number of recent tasks, after that fall through to the - // checks below - return true; - } - - if (mMaxNumVisibleTasks >= 0) { - // Always keep up to the max number of recent tasks, but return false afterwards - return numVisibleTasks <= mMaxNumVisibleTasks; - } - - if (mActiveTasksSessionDurationMs > 0) { - // Keep the task if the inactive time is within the session window, this check must come - // after the checks for the min/max visible task range - if (task.getInactiveDuration() <= mActiveTasksSessionDurationMs) { - return true; - } - } - - return false; } /** * If needed, remove oldest existing entries in recents that are for the same kind * of task as the given one. */ - private void trimForAddTask(TaskRecord task) { - final int removeIndex = findTrimIndexForAddTask(task); - if (removeIndex == -1) { - // Nothing to trim - return; - } - - // There is a similar task that will be removed for the addition of {@param task}, but it - // can be the same task, and if so, the task will be re-added in add(), so skip the - // callbacks here. - final TaskRecord removedTask = mTasks.remove(removeIndex); - if (removedTask != task) { - notifyTaskRemoved(removedTask, TRIMMED); - if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "Trimming task=" + removedTask - + " for addition of task=" + task); - } - notifyTaskPersisterLocked(removedTask, false /* flush */); - } - - /** - * Find the task that would be removed if the given {@param task} is added to the recent tasks - * list (if any). - */ - private int findTrimIndexForAddTask(TaskRecord task) { - int recentsCount = mTasks.size(); + int trimForTaskLocked(TaskRecord task, boolean doTrim) { + int recentsCount = size(); final Intent intent = task.intent; final boolean document = intent != null && intent.isDocument(); int maxRecents = task.maxRecents - 1; final ActivityStack stack = task.getStack(); for (int i = 0; i < recentsCount; i++) { - final TaskRecord tr = mTasks.get(i); + final TaskRecord tr = get(i); final ActivityStack trStack = tr.getStack(); - if (task != tr) { if (stack != null && trStack != null && stack != trStack) { continue; @@ -1106,7 +650,7 @@ class RecentTasks { final Intent trIntent = tr.intent; final boolean sameAffinity = task.affinity != null && task.affinity.equals(tr.affinity); - final boolean sameIntent = intent != null && intent.filterEquals(trIntent); + final boolean sameIntentFilter = intent != null && intent.filterEquals(trIntent); boolean multiTasksAllowed = false; final int flags = intent.getFlags(); if ((flags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NEW_DOCUMENT)) != 0 @@ -1115,7 +659,7 @@ class RecentTasks { } final boolean trIsDocument = trIntent != null && trIntent.isDocument(); final boolean bothDocuments = document && trIsDocument; - if (!sameAffinity && !sameIntent && !bothDocuments) { + if (!sameAffinity && !sameIntentFilter && !bothDocuments) { continue; } @@ -1124,17 +668,17 @@ class RecentTasks { final boolean sameActivity = task.realActivity != null && tr.realActivity != null && task.realActivity.equals(tr.realActivity); + // If the document is open in another app or is not the same + // document, we don't need to trim it. if (!sameActivity) { - // If the document is open in another app or is not the same document, we - // don't need to trim it. continue; + // Otherwise only trim if we are over our max recents for this task } else if (maxRecents > 0) { - // Otherwise only trim if we are over our max recents for this task --maxRecents; - if (!sameIntent || multiTasksAllowed) { + if (!doTrim || !sameIntentFilter || multiTasksAllowed) { // We don't want to trim if we are not over the max allowed entries and - // the tasks are not of the same intent filter, or multiple entries for - // the task is allowed. + // the caller doesn't want us to trim, the tasks are not of the same + // intent filter, or multiple entries fot the task is allowed. continue; } } @@ -1145,14 +689,44 @@ class RecentTasks { continue; } } - return i; + + if (!doTrim) { + // If the caller is not actually asking for a trim, just tell them we reached + // a point where the trim would happen. + return i; + } + + // Either task and tr are the same or, their affinities match or their intents match + // and neither of them is a document, or they are documents using the same activity + // and their maxRecents has been reached. + remove(i); + if (task != tr) { + tr.removedFromRecents(); + } + i--; + recentsCount--; + if (task.intent == null) { + // If the new recent task we are adding is not fully + // specified, then replace it with the existing recent task. + task = tr; + } + notifyTaskPersisterLocked(tr, false); } + return -1; } + // Sort by taskId + private static Comparator<TaskRecord> sTaskRecordComparator = new Comparator<TaskRecord>() { + @Override + public int compare(TaskRecord lhs, TaskRecord rhs) { + return rhs.taskId - lhs.taskId; + } + }; + // Extract the affiliates of the chain containing recent at index start. private int processNextAffiliateChainLocked(int start) { - final TaskRecord startTask = mTasks.get(start); + final TaskRecord startTask = get(start); final int affiliateId = startTask.mAffiliatedTaskId; // Quick identification of isolated tasks. I.e. those not launched behind. @@ -1167,17 +741,17 @@ class RecentTasks { // Remove all tasks that are affiliated to affiliateId and put them in mTmpRecents. mTmpRecents.clear(); - for (int i = mTasks.size() - 1; i >= start; --i) { - final TaskRecord task = mTasks.get(i); + for (int i = size() - 1; i >= start; --i) { + final TaskRecord task = get(i); if (task.mAffiliatedTaskId == affiliateId) { - mTasks.remove(i); + remove(i); mTmpRecents.add(task); } } // Sort them all by taskId. That is the order they were create in and that order will // always be correct. - Collections.sort(mTmpRecents, TASK_ID_COMPARATOR); + Collections.sort(mTmpRecents, sTaskRecordComparator); // Go through and fix up the linked list. // The first one is the end of the chain and has no next. @@ -1215,197 +789,11 @@ class RecentTasks { notifyTaskPersisterLocked(last, false); } - // Insert the group back into mTmpTasks at start. - mTasks.addAll(start, mTmpRecents); + // Insert the group back into mRecentTasks at start. + addAll(start, mTmpRecents); mTmpRecents.clear(); // Let the caller know where we left off. return start + tmpSize; } - - private boolean moveAffiliatedTasksToFront(TaskRecord task, int taskIndex) { - int recentsCount = mTasks.size(); - TaskRecord top = task; - int topIndex = taskIndex; - while (top.mNextAffiliate != null && topIndex > 0) { - top = top.mNextAffiliate; - topIndex--; - } - if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: adding affilliates starting at " - + topIndex + " from intial " + taskIndex); - // Find the end of the chain, doing a sanity check along the way. - boolean sane = top.mAffiliatedTaskId == task.mAffiliatedTaskId; - int endIndex = topIndex; - TaskRecord prev = top; - while (endIndex < recentsCount) { - TaskRecord cur = mTasks.get(endIndex); - if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: looking at next chain @" - + endIndex + " " + cur); - if (cur == top) { - // Verify start of the chain. - if (cur.mNextAffiliate != null || cur.mNextAffiliateTaskId != INVALID_TASK_ID) { - Slog.wtf(TAG, "Bad chain @" + endIndex - + ": first task has next affiliate: " + prev); - sane = false; - break; - } - } else { - // Verify middle of the chain's next points back to the one before. - if (cur.mNextAffiliate != prev - || cur.mNextAffiliateTaskId != prev.taskId) { - Slog.wtf(TAG, "Bad chain @" + endIndex - + ": middle task " + cur + " @" + endIndex - + " has bad next affiliate " - + cur.mNextAffiliate + " id " + cur.mNextAffiliateTaskId - + ", expected " + prev); - sane = false; - break; - } - } - if (cur.mPrevAffiliateTaskId == INVALID_TASK_ID) { - // Chain ends here. - if (cur.mPrevAffiliate != null) { - Slog.wtf(TAG, "Bad chain @" + endIndex - + ": last task " + cur + " has previous affiliate " - + cur.mPrevAffiliate); - sane = false; - } - if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: end of chain @" + endIndex); - break; - } else { - // Verify middle of the chain's prev points to a valid item. - if (cur.mPrevAffiliate == null) { - Slog.wtf(TAG, "Bad chain @" + endIndex - + ": task " + cur + " has previous affiliate " - + cur.mPrevAffiliate + " but should be id " - + cur.mPrevAffiliate); - sane = false; - break; - } - } - if (cur.mAffiliatedTaskId != task.mAffiliatedTaskId) { - Slog.wtf(TAG, "Bad chain @" + endIndex - + ": task " + cur + " has affiliated id " - + cur.mAffiliatedTaskId + " but should be " - + task.mAffiliatedTaskId); - sane = false; - break; - } - prev = cur; - endIndex++; - if (endIndex >= recentsCount) { - Slog.wtf(TAG, "Bad chain ran off index " + endIndex - + ": last task " + prev); - sane = false; - break; - } - } - if (sane) { - if (endIndex < taskIndex) { - Slog.wtf(TAG, "Bad chain @" + endIndex - + ": did not extend to task " + task + " @" + taskIndex); - sane = false; - } - } - if (sane) { - // All looks good, we can just move all of the affiliated tasks - // to the top. - for (int i=topIndex; i<=endIndex; i++) { - if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: moving affiliated " + task - + " from " + i + " to " + (i-topIndex)); - TaskRecord cur = mTasks.remove(i); - mTasks.add(i - topIndex, cur); - } - if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: done moving tasks " + topIndex - + " to " + endIndex); - return true; - } - - // Whoops, couldn't do it. - return false; - } - - void dump(PrintWriter pw, boolean dumpAll, String dumpPackage) { - pw.println("ACTIVITY MANAGER RECENT TASKS (dumpsys activity recents)"); - if (mTasks.isEmpty()) { - return; - } - - final MutableBoolean printedAnything = new MutableBoolean(false); - final MutableBoolean printedHeader = new MutableBoolean(false); - final int size = mTasks.size(); - for (int i = 0; i < size; i++) { - final TaskRecord tr = mTasks.get(i); - if (dumpPackage != null && (tr.realActivity == null || - !dumpPackage.equals(tr.realActivity.getPackageName()))) { - continue; - } - - if (!printedHeader.value) { - pw.println(" Recent tasks:"); - printedHeader.value = true; - printedAnything.value = true; - } - pw.print(" * Recent #"); pw.print(i); pw.print(": "); - pw.println(tr); - if (dumpAll) { - tr.dump(pw, " "); - } - } - - if (!printedAnything.value) { - pw.println(" (nothing)"); - } - } - - /** - * Creates a new RecentTaskInfo from a TaskRecord. - */ - static ActivityManager.RecentTaskInfo createRecentTaskInfo(TaskRecord tr) { - // Update the task description to reflect any changes in the task stack - tr.updateTaskDescription(); - - // Compose the recent task info - ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo(); - rti.id = tr.getTopActivity() == null ? INVALID_TASK_ID : tr.taskId; - rti.persistentId = tr.taskId; - rti.baseIntent = new Intent(tr.getBaseIntent()); - rti.origActivity = tr.origActivity; - rti.realActivity = tr.realActivity; - rti.description = tr.lastDescription; - rti.stackId = tr.getStackId(); - rti.userId = tr.userId; - rti.taskDescription = new ActivityManager.TaskDescription(tr.lastTaskDescription); - rti.lastActiveTime = tr.lastActiveTime; - rti.affiliatedTaskId = tr.mAffiliatedTaskId; - rti.affiliatedTaskColor = tr.mAffiliatedTaskColor; - rti.numActivities = 0; - if (tr.mBounds != null) { - rti.bounds = new Rect(tr.mBounds); - } - rti.supportsSplitScreenMultiWindow = tr.supportsSplitScreenWindowingMode(); - rti.resizeMode = tr.mResizeMode; - rti.configuration.setTo(tr.getConfiguration()); - - ActivityRecord base = null; - ActivityRecord top = null; - ActivityRecord tmp; - - for (int i = tr.mActivities.size() - 1; i >= 0; --i) { - tmp = tr.mActivities.get(i); - if (tmp.finishing) { - continue; - } - base = tmp; - if (top == null || (top.state == ActivityState.INITIALIZING)) { - top = base; - } - rti.numActivities++; - } - - rti.baseActivity = (base != null) ? base.intent.getComponent() : null; - rti.topActivity = (top != null) ? top.intent.getComponent() : null; - - return rti; - } } diff --git a/com/android/server/am/ServiceRecord.java b/com/android/server/am/ServiceRecord.java index 16995e50..ac85e6b1 100644 --- a/com/android/server/am/ServiceRecord.java +++ b/com/android/server/am/ServiceRecord.java @@ -33,7 +33,6 @@ import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; import android.net.Uri; import android.os.Binder; -import android.os.Build; import android.os.IBinder; import android.os.RemoteException; import android.os.SystemClock; @@ -518,27 +517,14 @@ final class ServiceRecord extends Binder { } catch (PackageManager.NameNotFoundException e) { } } - if (nm.getNotificationChannel(localPackageName, appUid, + if (localForegroundNoti.getSmallIcon() == null + || nm.getNotificationChannel(localPackageName, appUid, localForegroundNoti.getChannelId()) == null) { - int targetSdkVersion = Build.VERSION_CODES.O_MR1; - try { - final ApplicationInfo applicationInfo = - ams.mContext.getPackageManager().getApplicationInfoAsUser( - appInfo.packageName, 0, userId); - targetSdkVersion = applicationInfo.targetSdkVersion; - } catch (PackageManager.NameNotFoundException e) { - } - if (targetSdkVersion >= Build.VERSION_CODES.O_MR1) { - throw new RuntimeException( - "invalid channel for service notification: " - + foregroundNoti); - } - } - if (localForegroundNoti.getSmallIcon() == null) { // Notifications whose icon is 0 are defined to not show // a notification, silently ignoring it. We don't want to // just ignore it, we want to prevent the service from // being foreground. + // Also every notification needs a channel. throw new RuntimeException("invalid service notification: " + foregroundNoti); } diff --git a/com/android/server/am/TaskPersister.java b/com/android/server/am/TaskPersister.java index 2689d6a4..61994b55 100644 --- a/com/android/server/am/TaskPersister.java +++ b/com/android/server/am/TaskPersister.java @@ -567,7 +567,7 @@ public class TaskPersister { SparseArray<SparseBooleanArray> changedTaskIdsPerUser = new SparseArray<>(); synchronized (mService) { for (int userId : mRecentTasks.usersWithRecentsLoadedLocked()) { - SparseBooleanArray taskIdsToSave = mRecentTasks.getTaskIdsForUser(userId); + SparseBooleanArray taskIdsToSave = mRecentTasks.mPersistedTaskIds.get(userId); SparseBooleanArray persistedIdsInFile = mTaskIdsInFile.get(userId); if (persistedIdsInFile != null && persistedIdsInFile.equals(taskIdsToSave)) { continue; @@ -640,7 +640,7 @@ public class TaskPersister { @Override public void run() { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); - ArraySet<Integer> persistentTaskIds = new ArraySet<>(); + ArraySet<Integer> persistentTaskIds = new ArraySet<Integer>(); while (true) { // We can't lock mService while holding TaskPersister.this, but we don't want to // call removeObsoleteFiles every time through the loop, only the last time before @@ -654,7 +654,20 @@ public class TaskPersister { persistentTaskIds.clear(); synchronized (mService) { if (DEBUG) Slog.d(TAG, "mRecents=" + mRecentTasks); - mRecentTasks.getPersistableTaskIds(persistentTaskIds); + for (int taskNdx = mRecentTasks.size() - 1; taskNdx >= 0; --taskNdx) { + final TaskRecord task = mRecentTasks.get(taskNdx); + if (DEBUG) Slog.d(TAG, "LazyTaskWriter: task=" + task + + " persistable=" + task.isPersistable); + final ActivityStack stack = task.getStack(); + if ((task.isPersistable || task.inRecents) + && (stack == null || !stack.isHomeOrRecentsStack())) { + if (DEBUG) Slog.d(TAG, "adding to persistentTaskIds task=" + task); + persistentTaskIds.add(task.taskId); + } else { + if (DEBUG) Slog.d(TAG, + "omitting from persistentTaskIds task=" + task); + } + } mService.mWindowManager.removeObsoleteTaskFiles(persistentTaskIds, mRecentTasks.usersWithRecentsLoadedLocked()); } diff --git a/com/android/server/am/TaskRecord.java b/com/android/server/am/TaskRecord.java index a1b45a1e..0d8df796 100644 --- a/com/android/server/am/TaskRecord.java +++ b/com/android/server/am/TaskRecord.java @@ -18,7 +18,10 @@ package com.android.server.am; import static android.app.ActivityManager.RESIZE_MODE_FORCED; import static android.app.ActivityManager.RESIZE_MODE_SYSTEM; +import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; +import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; +import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; @@ -28,7 +31,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; -import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS; import static android.content.pm.ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY; @@ -43,6 +45,7 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE; import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED; import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; +import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRIVILEGED; import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; import static android.provider.Settings.Secure.USER_SETUP_COMPLETE; import static android.view.Display.DEFAULT_DISPLAY; @@ -83,6 +86,7 @@ import android.annotation.IntDef; import android.annotation.Nullable; import android.app.Activity; import android.app.ActivityManager; +import android.app.ActivityManager.StackId; import android.app.ActivityManager.TaskDescription; import android.app.ActivityManager.TaskSnapshot; import android.app.ActivityOptions; @@ -98,7 +102,6 @@ import android.content.res.Configuration; import android.graphics.Rect; import android.os.Debug; import android.os.RemoteException; -import android.os.SystemClock; import android.os.Trace; import android.os.UserHandle; import android.provider.Settings; @@ -152,6 +155,8 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi private static final String ATTR_EFFECTIVE_UID = "effective_uid"; @Deprecated private static final String ATTR_TASKTYPE = "task_type"; + private static final String ATTR_FIRSTACTIVETIME = "first_active_time"; + private static final String ATTR_LASTACTIVETIME = "last_active_time"; private static final String ATTR_LASTDESCRIPTION = "last_description"; private static final String ATTR_LASTTIMEMOVED = "last_time_moved"; private static final String ATTR_NEVERRELINQUISH = "never_relinquish_identity"; @@ -163,6 +168,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi private static final String ATTR_CALLING_PACKAGE = "calling_package"; private static final String ATTR_SUPPORTS_PICTURE_IN_PICTURE = "supports_picture_in_picture"; private static final String ATTR_RESIZE_MODE = "resize_mode"; + private static final String ATTR_PRIVILEGED = "privileged"; private static final String ATTR_NON_FULLSCREEN_BOUNDS = "non_fullscreen_bounds"; private static final String ATTR_MIN_WIDTH = "min_width"; private static final String ATTR_MIN_HEIGHT = "min_height"; @@ -206,10 +212,9 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi ComponentName realActivity; // The actual activity component that started the task. boolean realActivitySuspended; // True if the actual activity component that started the // task is suspended. + long firstActiveTime; // First time this task was active. + long lastActiveTime; // Last time this task was active, including sleep. boolean inRecents; // Actually in the recents list? - long lastActiveTime; // Last time this task was active in the current device session, - // including sleep. This time is initialized to the elapsed time when - // restored from disk. boolean isAvailable; // Is the activity available to be launched? boolean rootWasReset; // True if the intent at the root of the task had // the FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag. @@ -232,6 +237,10 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi // of the root activity. boolean mTemporarilyUnresizable; // Separate flag from mResizeMode used to suppress resize // changes on a temporary basis. + private int mLockTaskMode; // Which tasklock mode to launch this task in. One of + // ActivityManager.LOCK_TASK_LAUNCH_MODE_* + private boolean mPrivileged; // The root activity application of this task holds + // privileged permissions. /** Can't be put in lockTask mode. */ final static int LOCK_TASK_AUTH_DONT_LOCK = 0; @@ -330,7 +339,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi TaskPersister.IMAGE_EXTENSION; userId = UserHandle.getUserId(info.applicationInfo.uid); taskId = _taskId; - lastActiveTime = SystemClock.elapsedRealtime(); mAffiliatedTaskId = _taskId; voiceSession = _voiceSession; voiceInteractor = _voiceInteractor; @@ -351,7 +359,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi TaskPersister.IMAGE_EXTENSION; userId = UserHandle.getUserId(info.applicationInfo.uid); taskId = _taskId; - lastActiveTime = SystemClock.elapsedRealtime(); mAffiliatedTaskId = _taskId; voiceSession = null; voiceInteractor = null; @@ -378,11 +385,12 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset, boolean _autoRemoveRecents, boolean _askedCompatMode, int _userId, int _effectiveUid, String _lastDescription, ArrayList<ActivityRecord> activities, - long lastTimeMoved, boolean neverRelinquishIdentity, - TaskDescription _lastTaskDescription, int taskAffiliation, int prevTaskId, - int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage, - int resizeMode, boolean supportsPictureInPicture, boolean _realActivitySuspended, - boolean userSetupComplete, int minWidth, int minHeight) { + long _firstActiveTime, long _lastActiveTime, long lastTimeMoved, + boolean neverRelinquishIdentity, TaskDescription _lastTaskDescription, + int taskAffiliation, int prevTaskId, int nextTaskId, int taskAffiliationColor, + int callingUid, String callingPackage, int resizeMode, boolean supportsPictureInPicture, + boolean privileged, boolean _realActivitySuspended, boolean userSetupComplete, + int minWidth, int minHeight) { mService = service; mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX + TaskPersister.IMAGE_EXTENSION; @@ -404,7 +412,8 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi userId = _userId; mUserSetupComplete = userSetupComplete; effectiveUid = _effectiveUid; - lastActiveTime = SystemClock.elapsedRealtime(); + firstActiveTime = _firstActiveTime; + lastActiveTime = _lastActiveTime; lastDescription = _lastDescription; mActivities = activities; mLastTimeMoved = lastTimeMoved; @@ -418,6 +427,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi mCallingPackage = callingPackage; mResizeMode = resizeMode; mSupportsPictureInPicture = supportsPictureInPicture; + mPrivileged = privileged; mMinWidth = minWidth; mMinHeight = minHeight; mService.mTaskChangeNotificationController.notifyTaskCreated(_taskId, realActivity); @@ -510,7 +520,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi // All we can do for now is update the bounds so it can be used when the task is // added to window manager. updateOverrideConfiguration(bounds); - if (!inFreeformWindowingMode()) { + if (getStackId() != FREEFORM_WORKSPACE_STACK_ID) { // re-restore the task so it can have the proper stack association. mService.mStackSupervisor.restoreRecentTaskLocked(this, null); } @@ -606,7 +616,8 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi * @return whether the task was reparented */ // TODO: Inspect all call sites and change to just changing windowing mode of the stack vs. - // re-parenting the task. Can only be done when we are no longer using static stack Ids. + // re-parenting the task. Can only be done when we are no longer using static stack Ids like + /** {@link ActivityManager.StackId#FULLSCREEN_WORKSPACE_STACK_ID} */ boolean reparent(ActivityStack preferredStack, int position, @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume, boolean schedulePictureInPictureModeChange, String reason) { @@ -619,12 +630,12 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi return false; } - final int toStackWindowingMode = toStack.getWindowingMode(); + final int sourceStackId = getStackId(); + final int stackId = toStack.getStackId(); final ActivityRecord topActivity = getTopActivity(); - final boolean mightReplaceWindow = - replaceWindowsOnTaskMove(getWindowingMode(), toStackWindowingMode) - && topActivity != null; + final boolean mightReplaceWindow = StackId.replaceWindowsOnTaskMove(sourceStackId, stackId) + && topActivity != null; if (mightReplaceWindow) { // We are about to relaunch the activity because its configuration changed due to // being maximized, i.e. size change. The activity will first remove the old window @@ -649,7 +660,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi // In some cases the focused stack isn't the front stack. E.g. pinned stack. // Whenever we are moving the top activity from the front stack we want to make sure to // move the stack to the front. - final boolean wasFront = r != null && sourceStack.isTopStackOnDisplay() + final boolean wasFront = r != null && supervisor.isFrontStackOnDisplay(sourceStack) && (sourceStack.topRunningActivityLocked() == r); // Adjust the position for the new parent stack as needed. @@ -696,10 +707,10 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi toStack.prepareFreezingTaskBounds(); // Make sure the task has the appropriate bounds/size for the stack it is in. + final int toStackWindowingMode = toStack.getWindowingMode(); final boolean toStackSplitScreenPrimary = toStackWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; - if ((toStackWindowingMode == WINDOWING_MODE_FULLSCREEN - || toStackWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) + if (stackId == FULLSCREEN_WORKSPACE_STACK_ID && !Objects.equals(mBounds, toStack.mBounds)) { kept = resize(toStack.mBounds, RESIZE_MODE_SYSTEM, !mightReplaceWindow, deferResume); @@ -738,9 +749,9 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi } // TODO: Handle incorrect request to move before the actual move, not after. - final boolean inSplitScreenMode = supervisor.getDefaultDisplay().hasSplitScreenPrimaryStack(); + final boolean inSplitScreenMode = supervisor.getDefaultDisplay().hasSplitScreenStack(); supervisor.handleNonResizableTaskIfNeeded(this, preferredStack.getWindowingMode(), - DEFAULT_DISPLAY, toStack); + DEFAULT_DISPLAY, stackId); boolean successful = (preferredStack == toStack); if (successful && toStack.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { @@ -750,18 +761,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi return successful; } - /** - * Returns true if the windows of tasks being moved to the target stack from the source - * stack should be replaced, meaning that window manager will keep the old window around - * until the new is ready. - * @hide - */ - private static boolean replaceWindowsOnTaskMove( - int sourceWindowingMode, int targetWindowingMode) { - return sourceWindowingMode == WINDOWING_MODE_FREEFORM - || targetWindowingMode == WINDOWING_MODE_FREEFORM; - } - void cancelWindowTransition() { mWindowContainerController.cancelWindowTransition(); } @@ -781,11 +780,14 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi } void touchActiveTime() { - lastActiveTime = SystemClock.elapsedRealtime(); + lastActiveTime = System.currentTimeMillis(); + if (firstActiveTime == 0) { + firstActiveTime = lastActiveTime; + } } long getInactiveDuration() { - return SystemClock.elapsedRealtime() - lastActiveTime; + return System.currentTimeMillis() - lastActiveTime; } /** Sets the original intent, and the calling uid and package. */ @@ -793,7 +795,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi mCallingUid = r.launchedFromUid; mCallingPackage = r.launchedFromPackage; setIntent(r.intent, r.info); - setLockTaskAuth(r); } /** Sets the original intent, _without_ updating the calling uid or package. */ @@ -877,6 +878,14 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi } mResizeMode = info.resizeMode; mSupportsPictureInPicture = info.supportsPictureInPicture(); + mPrivileged = (info.applicationInfo.privateFlags & PRIVATE_FLAG_PRIVILEGED) != 0; + mLockTaskMode = info.lockTaskLaunchMode; + if (!mPrivileged && (mLockTaskMode == LOCK_TASK_LAUNCH_MODE_ALWAYS + || mLockTaskMode == LOCK_TASK_LAUNCH_MODE_NEVER)) { + // Non-priv apps are not allowed to use always or never, fall back to default + mLockTaskMode = LOCK_TASK_LAUNCH_MODE_DEFAULT; + } + setLockTaskAuth(); } /** Sets the original minimal width and height. */ @@ -1254,7 +1263,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi mService.notifyTaskPersisterLocked(this, false); } - if (inPinnedWindowingMode()) { + if (getStackId() == PINNED_STACK_ID) { // We normally notify listeners of task stack changes on pause, however pinned stack // activities are normally in the paused state so no notification will be sent there // before the activity is removed. We send it here so instead. @@ -1413,17 +1422,8 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi } void setLockTaskAuth() { - setLockTaskAuth(getRootActivity()); - } - - private void setLockTaskAuth(@Nullable ActivityRecord r) { - if (r == null) { - mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE; - return; - } - final String pkg = (realActivity != null) ? realActivity.getPackageName() : null; - switch (r.lockTaskLaunchMode) { + switch (mLockTaskMode) { case LOCK_TASK_LAUNCH_MODE_DEFAULT: mLockTaskAuth = mService.mLockTaskController.isPackageWhitelisted(userId, pkg) ? LOCK_TASK_AUTH_WHITELISTED : LOCK_TASK_AUTH_PINNABLE; @@ -1493,7 +1493,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi * @return True if the requested bounds are okay for a resizing request. */ private boolean canResizeToBounds(Rect bounds) { - if (bounds == null || !inFreeformWindowingMode()) { + if (bounds == null || getStackId() != FREEFORM_WORKSPACE_STACK_ID) { // Note: If not on the freeform workspace, we ignore the bounds. return true; } @@ -1559,7 +1559,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi // values in the TaskRecord. String label = null; String iconFilename = null; - int iconResource = -1; int colorPrimary = 0; int colorBackground = 0; int statusBarColor = 0; @@ -1571,9 +1570,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi if (label == null) { label = r.taskDescription.getLabel(); } - if (iconResource == -1) { - iconResource = r.taskDescription.getIconResource(); - } if (iconFilename == null) { iconFilename = r.taskDescription.getIconFilename(); } @@ -1588,8 +1584,8 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi } topActivity = false; } - lastTaskDescription = new TaskDescription(label, null, iconResource, iconFilename, - colorPrimary, colorBackground, statusBarColor, navigationBarColor); + lastTaskDescription = new TaskDescription(label, null, iconFilename, colorPrimary, + colorBackground, statusBarColor, navigationBarColor); if (mWindowContainerController != null) { mWindowContainerController.setTaskDescription(lastTaskDescription); } @@ -1651,6 +1647,8 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi out.attribute(null, ATTR_USERID, String.valueOf(userId)); out.attribute(null, ATTR_USER_SETUP_COMPLETE, String.valueOf(mUserSetupComplete)); out.attribute(null, ATTR_EFFECTIVE_UID, String.valueOf(effectiveUid)); + out.attribute(null, ATTR_FIRSTACTIVETIME, String.valueOf(firstActiveTime)); + out.attribute(null, ATTR_LASTACTIVETIME, String.valueOf(lastActiveTime)); out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved)); out.attribute(null, ATTR_NEVERRELINQUISH, String.valueOf(mNeverRelinquishIdentity)); if (lastDescription != null) { @@ -1668,6 +1666,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi out.attribute(null, ATTR_RESIZE_MODE, String.valueOf(mResizeMode)); out.attribute(null, ATTR_SUPPORTS_PICTURE_IN_PICTURE, String.valueOf(mSupportsPictureInPicture)); + out.attribute(null, ATTR_PRIVILEGED, String.valueOf(mPrivileged)); if (mLastNonFullscreenBounds != null) { out.attribute( null, ATTR_NON_FULLSCREEN_BOUNDS, mLastNonFullscreenBounds.flattenToString()); @@ -1722,6 +1721,8 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi boolean userSetupComplete = true; int effectiveUid = -1; String lastDescription = null; + long firstActiveTime = -1; + long lastActiveTime = -1; long lastTimeOnTop = 0; boolean neverRelinquishIdentity = true; int taskId = INVALID_TASK_ID; @@ -1735,6 +1736,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi String callingPackage = ""; int resizeMode = RESIZE_MODE_FORCE_RESIZEABLE; boolean supportsPictureInPicture = false; + boolean privileged = false; Rect bounds = null; int minWidth = INVALID_MIN_SIZE; int minHeight = INVALID_MIN_SIZE; @@ -1772,6 +1774,10 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi effectiveUid = Integer.parseInt(attrValue); } else if (ATTR_TASKTYPE.equals(attrName)) { taskType = Integer.parseInt(attrValue); + } else if (ATTR_FIRSTACTIVETIME.equals(attrName)) { + firstActiveTime = Long.parseLong(attrValue); + } else if (ATTR_LASTACTIVETIME.equals(attrName)) { + lastActiveTime = Long.parseLong(attrValue); } else if (ATTR_LASTDESCRIPTION.equals(attrName)) { lastDescription = attrValue; } else if (ATTR_LASTTIMEMOVED.equals(attrName)) { @@ -1796,6 +1802,8 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi resizeMode = Integer.parseInt(attrValue); } else if (ATTR_SUPPORTS_PICTURE_IN_PICTURE.equals(attrName)) { supportsPictureInPicture = Boolean.parseBoolean(attrValue); + } else if (ATTR_PRIVILEGED.equals(attrName)) { + privileged = Boolean.parseBoolean(attrValue); } else if (ATTR_NON_FULLSCREEN_BOUNDS.equals(attrName)) { bounds = Rect.unflattenFromString(attrValue); } else if (ATTR_MIN_WIDTH.equals(attrName)) { @@ -1880,10 +1888,10 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi final TaskRecord task = new TaskRecord(stackSupervisor.mService, taskId, intent, affinityIntent, affinity, rootAffinity, realActivity, origActivity, rootHasReset, autoRemoveRecents, askedCompatMode, userId, effectiveUid, lastDescription, - activities, lastTimeOnTop, neverRelinquishIdentity, taskDescription, - taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor, callingUid, - callingPackage, resizeMode, supportsPictureInPicture, realActivitySuspended, - userSetupComplete, minWidth, minHeight); + activities, firstActiveTime, lastActiveTime, lastTimeOnTop, neverRelinquishIdentity, + taskDescription, taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor, + callingUid, callingPackage, resizeMode, supportsPictureInPicture, privileged, + realActivitySuspended, userSetupComplete, minWidth, minHeight); task.updateOverrideConfiguration(bounds); for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) { @@ -1903,7 +1911,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi // If the task has no requested minimal size, we'd like to enforce a minimal size // so that the user can not render the task too small to manipulate. We don't need // to do this for the pinned stack as the bounds are controlled by the system. - if (!inPinnedWindowingMode()) { + if (getStackId() != PINNED_STACK_ID) { if (minWidth == INVALID_MIN_SIZE) { minWidth = mService.mStackSupervisor.mDefaultMinSizeOfResizeableTask; } @@ -2077,7 +2085,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi return; } - if (inStack.inFreeformWindowingMode()) { + if (inStack.mStackId == FREEFORM_WORKSPACE_STACK_ID) { if (!isResizeable()) { throw new IllegalArgumentException("Can not position non-resizeable task=" + this + " in stack=" + inStack); @@ -2212,6 +2220,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi pw.print(" mResizeMode=" + ActivityInfo.resizeModeToString(mResizeMode)); pw.print(" mSupportsPictureInPicture=" + mSupportsPictureInPicture); pw.print(" isResizeable=" + isResizeable()); + pw.print(" firstActiveTime=" + firstActiveTime); pw.print(" lastActiveTime=" + lastActiveTime); pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)"); } diff --git a/com/android/server/appwidget/AppWidgetServiceImpl.java b/com/android/server/appwidget/AppWidgetServiceImpl.java index 51afada2..a6aaaa67 100644 --- a/com/android/server/appwidget/AppWidgetServiceImpl.java +++ b/com/android/server/appwidget/AppWidgetServiceImpl.java @@ -71,6 +71,7 @@ import android.os.SystemClock; import android.os.Trace; import android.os.UserHandle; import android.os.UserManager; +import android.os.storage.StorageManager; import android.service.appwidget.AppWidgetServiceDumpProto; import android.service.appwidget.WidgetProto; import android.text.TextUtils; @@ -158,9 +159,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku // Bump if the stored widgets need to be upgraded. private static final int CURRENT_VERSION = 1; - // Every widget update request is associated which an increasing sequence number. This is - // used to verify which request has successfully been received by the host. - private static final AtomicLong UPDATE_COUNTER = new AtomicLong(); + private static final AtomicLong REQUEST_COUNTER = new AtomicLong(); private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override @@ -815,9 +814,9 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku Host host = lookupOrAddHostLocked(id); host.callbacks = callbacks; - long updateSequenceNo = UPDATE_COUNTER.incrementAndGet(); int N = appWidgetIds.length; ArrayList<PendingHostUpdate> outUpdates = new ArrayList<>(N); + LongSparseArray<PendingHostUpdate> updatesMap = new LongSparseArray<>(); for (int i = 0; i < N; i++) { if (host.getPendingUpdatesForId(appWidgetIds[i], updatesMap)) { @@ -829,8 +828,6 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } } } - // Reset the update counter once all the updates have been calculated - host.lastWidgetUpdateSequenceNo = updateSequenceNo; return new ParceledListSlice<>(outUpdates); } } @@ -1917,9 +1914,9 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku // method with a wrong id. In that case, ignore the call. return; } - long requestId = UPDATE_COUNTER.incrementAndGet(); + long requestId = REQUEST_COUNTER.incrementAndGet(); if (widget != null) { - widget.updateSequenceNos.put(viewId, requestId); + widget.updateRequestIds.put(viewId, requestId); } if (widget == null || widget.host == null || widget.host.zombie || widget.host.callbacks == null || widget.provider == null @@ -1944,7 +1941,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku int appWidgetId, int viewId, long requestId) { try { callbacks.viewDataChanged(appWidgetId, viewId); - host.lastWidgetUpdateSequenceNo = requestId; + host.lastWidgetUpdateRequestId = requestId; } catch (RemoteException re) { // It failed; remove the callback. No need to prune because // we know that this host is still referenced by this instance. @@ -1991,9 +1988,9 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } private void scheduleNotifyUpdateAppWidgetLocked(Widget widget, RemoteViews updateViews) { - long requestId = UPDATE_COUNTER.incrementAndGet(); + long requestId = REQUEST_COUNTER.incrementAndGet(); if (widget != null) { - widget.updateSequenceNos.put(ID_VIEWS_UPDATE, requestId); + widget.updateRequestIds.put(ID_VIEWS_UPDATE, requestId); } if (widget == null || widget.provider == null || widget.provider.zombie || widget.host.callbacks == null || widget.host.zombie) { @@ -2016,7 +2013,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku int appWidgetId, RemoteViews views, long requestId) { try { callbacks.updateAppWidget(appWidgetId, views); - host.lastWidgetUpdateSequenceNo = requestId; + host.lastWidgetUpdateRequestId = requestId; } catch (RemoteException re) { synchronized (mLock) { Slog.e(TAG, "Widget host dead: " + host.id, re); @@ -2026,11 +2023,11 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } private void scheduleNotifyProviderChangedLocked(Widget widget) { - long requestId = UPDATE_COUNTER.incrementAndGet(); + long requestId = REQUEST_COUNTER.incrementAndGet(); if (widget != null) { // When the provider changes, reset everything else. - widget.updateSequenceNos.clear(); - widget.updateSequenceNos.append(ID_PROVIDER_CHANGED, requestId); + widget.updateRequestIds.clear(); + widget.updateRequestIds.append(ID_PROVIDER_CHANGED, requestId); } if (widget == null || widget.provider == null || widget.provider.zombie || widget.host.callbacks == null || widget.host.zombie) { @@ -2053,7 +2050,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku int appWidgetId, AppWidgetProviderInfo info, long requestId) { try { callbacks.providerChanged(appWidgetId, info); - host.lastWidgetUpdateSequenceNo = requestId; + host.lastWidgetUpdateRequestId = requestId; } catch (RemoteException re) { synchronized (mLock){ Slog.e(TAG, "Widget host dead: " + host.id, re); @@ -3890,11 +3887,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku boolean zombie; // if we're in safe mode, don't prune this just because nobody references it int tag = TAG_UNDEFINED; // for use while saving state (the index) - // Sequence no for the last update successfully sent. This is updated whenever a - // widget update is successfully sent to the host callbacks. As all new/undelivered updates - // will have sequenceNo greater than this, all those updates will be sent when the host - // callbacks are attached again. - long lastWidgetUpdateSequenceNo; + long lastWidgetUpdateRequestId; // request id for the last update successfully sent public int getUserId() { return UserHandle.getUserId(id.uid); @@ -3921,18 +3914,18 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku */ public boolean getPendingUpdatesForId(int appWidgetId, LongSparseArray<PendingHostUpdate> outUpdates) { - long updateSequenceNo = lastWidgetUpdateSequenceNo; + long updateRequestId = lastWidgetUpdateRequestId; int N = widgets.size(); for (int i = 0; i < N; i++) { Widget widget = widgets.get(i); if (widget.appWidgetId == appWidgetId) { outUpdates.clear(); - for (int j = widget.updateSequenceNos.size() - 1; j >= 0; j--) { - long requestId = widget.updateSequenceNos.valueAt(j); - if (requestId <= updateSequenceNo) { + for (int j = widget.updateRequestIds.size() - 1; j >= 0; j--) { + long requestId = widget.updateRequestIds.valueAt(j); + if (requestId <= updateRequestId) { continue; } - int id = widget.updateSequenceNos.keyAt(j); + int id = widget.updateRequestIds.keyAt(j); final PendingHostUpdate update; switch (id) { case ID_PROVIDER_CHANGED: @@ -4028,8 +4021,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku RemoteViews maskedViews; Bundle options; Host host; - // Map of request type to updateSequenceNo. - SparseLongArray updateSequenceNos = new SparseLongArray(2); + // Request ids for various operations + SparseLongArray updateRequestIds = new SparseLongArray(2); @Override public String toString() { diff --git a/com/android/server/audio/PlaybackActivityMonitor.java b/com/android/server/audio/PlaybackActivityMonitor.java index 49431733..6506cf7f 100644 --- a/com/android/server/audio/PlaybackActivityMonitor.java +++ b/com/android/server/audio/PlaybackActivityMonitor.java @@ -184,15 +184,11 @@ public final class PlaybackActivityMonitor } } - private static final int FLAGS_FOR_SILENCE_OVERRIDE = - AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY | - AudioAttributes.FLAG_BYPASS_MUTE; - private void checkVolumeForPrivilegedAlarm(AudioPlaybackConfiguration apc, int event) { if (event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED || apc.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) { - if ((apc.getAudioAttributes().getAllFlags() & FLAGS_FOR_SILENCE_OVERRIDE) - == FLAGS_FOR_SILENCE_OVERRIDE && + if ((apc.getAudioAttributes().getAllFlags() & + AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0 && apc.getAudioAttributes().getUsage() == AudioAttributes.USAGE_ALARM && mContext.checkPermission(android.Manifest.permission.MODIFY_PHONE_STATE, apc.getClientPid(), apc.getClientUid()) == diff --git a/com/android/server/autofill/AutofillManagerServiceImpl.java b/com/android/server/autofill/AutofillManagerServiceImpl.java index 880f236c..862070ad 100644 --- a/com/android/server/autofill/AutofillManagerServiceImpl.java +++ b/com/android/server/autofill/AutofillManagerServiceImpl.java @@ -216,12 +216,9 @@ final class AutofillManagerServiceImpl { serviceComponent = ComponentName.unflattenFromString(componentName); serviceInfo = AppGlobals.getPackageManager().getServiceInfo(serviceComponent, 0, mUserId); - if (serviceInfo == null) { - Slog.e(TAG, "Bad AutofillService name: " + componentName); - } } catch (RuntimeException | RemoteException e) { - Slog.e(TAG, "Error getting service info for '" + componentName + "': " + e); - serviceInfo = null; + Slog.e(TAG, "Bad autofill service name " + componentName + ": " + e); + return; } } try { @@ -231,24 +228,21 @@ final class AutofillManagerServiceImpl { if (sDebug) Slog.d(TAG, "Set component for user " + mUserId + " as " + mInfo); } else { mInfo = null; - if (sDebug) { - Slog.d(TAG, "Reset component for user " + mUserId + " (" + componentName + ")"); - } + if (sDebug) Slog.d(TAG, "Reset component for user " + mUserId); } - } catch (Exception e) { - Slog.e(TAG, "Bad AutofillServiceInfo for '" + componentName + "': " + e); - mInfo = null; - } - final boolean isEnabled = isEnabled(); - if (wasEnabled != isEnabled) { - if (!isEnabled) { - final int sessionCount = mSessions.size(); - for (int i = sessionCount - 1; i >= 0; i--) { - final Session session = mSessions.valueAt(i); - session.removeSelfLocked(); + final boolean isEnabled = isEnabled(); + if (wasEnabled != isEnabled) { + if (!isEnabled) { + final int sessionCount = mSessions.size(); + for (int i = sessionCount - 1; i >= 0; i--) { + final Session session = mSessions.valueAt(i); + session.removeSelfLocked(); + } } + sendStateToClients(false); } - sendStateToClients(false); + } catch (Exception e) { + Slog.e(TAG, "Bad AutofillService '" + componentName + "': " + e); } } diff --git a/com/android/server/autofill/Session.java b/com/android/server/autofill/Session.java index 3c12d670..ed00ffed 100644 --- a/com/android/server/autofill/Session.java +++ b/com/android/server/autofill/Session.java @@ -495,7 +495,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState notifyUnavailableToClient(false); } synchronized (mLock) { - processResponseLocked(response, null, requestFlags); + processResponseLocked(response, requestFlags); } final LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_REQUEST, servicePackageName) @@ -762,21 +762,13 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } final Parcelable result = data.getParcelable(AutofillManager.EXTRA_AUTHENTICATION_RESULT); - final Bundle newClientState = data.getBundle(AutofillManager.EXTRA_CLIENT_STATE); - if (sDebug) { - Slog.d(TAG, "setAuthenticationResultLocked(): result=" + result - + ", clientState=" + newClientState); - } + if (sDebug) Slog.d(TAG, "setAuthenticationResultLocked(): result=" + result); if (result instanceof FillResponse) { writeLog(MetricsEvent.AUTOFILL_AUTHENTICATED); - replaceResponseLocked(authenticatedResponse, (FillResponse) result, newClientState); + replaceResponseLocked(authenticatedResponse, (FillResponse) result); } else if (result instanceof Dataset) { if (datasetIdx != AutofillManager.AUTHENTICATION_ID_DATASET_ID_UNDEFINED) { writeLog(MetricsEvent.AUTOFILL_DATASET_AUTHENTICATED); - if (newClientState != null) { - if (sDebug) Slog.d(TAG, "Updating client state from auth dataset"); - mClientState = newClientState; - } final Dataset dataset = (Dataset) result; authenticatedResponse.getDatasets().set(datasetIdx, dataset); autoFill(requestId, datasetIdx, dataset, false); @@ -1499,14 +1491,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState ArraySet<AutofillId> trackedViews = null; boolean saveOnAllViewsInvisible = false; - boolean saveOnFinish = true; final SaveInfo saveInfo = response.getSaveInfo(); - final AutofillId saveTriggerId; if (saveInfo != null) { - saveTriggerId = saveInfo.getTriggerId(); - if (saveTriggerId != null) { - writeLog(MetricsEvent.AUTOFILL_EXPLICIT_SAVE_TRIGGER_DEFINITION); - } saveOnAllViewsInvisible = (saveInfo.getFlags() & SaveInfo.FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE) != 0; @@ -1523,12 +1509,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState Collections.addAll(trackedViews, saveInfo.getOptionalIds()); } } - if ((saveInfo.getFlags() & SaveInfo.FLAG_DONT_SAVE_ON_FINISH) != 0) { - saveOnFinish = false; - } - - } else { - saveTriggerId = null; } // Must also track that are part of datasets, otherwise the FillUI won't be hidden when @@ -1553,18 +1533,17 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState try { if (sVerbose) { - Slog.v(TAG, "updateTrackedIdsLocked(): " + trackedViews + " => " + fillableIds - + " (triggering on " + saveTriggerId + ")"); + Slog.v(TAG, "updateTrackedIdsLocked(): " + trackedViews + " => " + fillableIds); } mClient.setTrackedViews(id, toArray(trackedViews), saveOnAllViewsInvisible, - saveOnFinish, toArray(fillableIds), saveTriggerId); + toArray(fillableIds)); } catch (RemoteException e) { Slog.w(TAG, "Cannot set tracked ids", e); } } private void replaceResponseLocked(@NonNull FillResponse oldResponse, - @NonNull FillResponse newResponse, @Nullable Bundle newClientState) { + @NonNull FillResponse newResponse) { // Disassociate view states with the old response setViewStatesLocked(oldResponse, ViewState.STATE_INITIAL, true); // Move over the id @@ -1572,7 +1551,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState // Replace the old response mResponses.put(newResponse.getRequestId(), newResponse); // Now process the new response - processResponseLocked(newResponse, newClientState, 0); + processResponseLocked(newResponse, 0); } private void processNullResponseLocked(int flags) { @@ -1586,8 +1565,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState removeSelf(); } - private void processResponseLocked(@NonNull FillResponse newResponse, - @Nullable Bundle newClientState, int flags) { + private void processResponseLocked(@NonNull FillResponse newResponse, int flags) { // Make sure we are hiding the UI which will be shown // only if handling the current response requires it. mUi.hideAll(this); @@ -1595,15 +1573,14 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState final int requestId = newResponse.getRequestId(); if (sVerbose) { Slog.v(TAG, "processResponseLocked(): mCurrentViewId=" + mCurrentViewId - + ",flags=" + flags + ", reqId=" + requestId + ", resp=" + newResponse - + ",newClientState=" + newClientState); + + ",flags=" + flags + ", reqId=" + requestId + ", resp=" + newResponse); } if (mResponses == null) { mResponses = new SparseArray<>(4); } mResponses.put(requestId, newResponse); - mClientState = newClientState != null ? newClientState : newResponse.getClientState(); + mClientState = newResponse.getClientState(); setViewStatesLocked(newResponse, ViewState.STATE_FILLABLE, false); updateTrackedIdsLocked(); diff --git a/com/android/server/backup/BackupManagerService.java b/com/android/server/backup/BackupManagerService.java index f9213aab..eabe21fe 100644 --- a/com/android/server/backup/BackupManagerService.java +++ b/com/android/server/backup/BackupManagerService.java @@ -319,6 +319,7 @@ public class BackupManagerService implements BackupManagerServiceInterface { boolean mProvisioned; boolean mAutoRestore; PowerManager.WakeLock mWakelock; + HandlerThread mHandlerThread; BackupHandler mBackupHandler; PendingIntent mRunBackupIntent, mRunInitIntent; BroadcastReceiver mRunBackupReceiver, mRunInitReceiver; @@ -408,37 +409,43 @@ public class BackupManagerService implements BackupManagerServiceInterface { // Called through the trampoline from onUnlockUser(), then we buck the work // off to the background thread to keep the unlock time down. public void unlockSystemUser() { - // Migrate legacy setting - Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup migrate"); - if (!backupSettingMigrated(UserHandle.USER_SYSTEM)) { - if (DEBUG) { - Slog.i(TAG, "Backup enable apparently not migrated"); - } - final ContentResolver r = sInstance.mContext.getContentResolver(); - final int enableState = Settings.Secure.getIntForUser(r, - Settings.Secure.BACKUP_ENABLED, -1, UserHandle.USER_SYSTEM); - if (enableState >= 0) { + mBackupHandler.post(() -> { + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup init"); + sInstance.initialize(UserHandle.USER_SYSTEM); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); + + // Migrate legacy setting + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup migrate"); + if (!backupSettingMigrated(UserHandle.USER_SYSTEM)) { if (DEBUG) { - Slog.i(TAG, "Migrating enable state " + (enableState != 0)); + Slog.i(TAG, "Backup enable apparently not migrated"); } - writeBackupEnableState(enableState != 0, UserHandle.USER_SYSTEM); - Settings.Secure.putStringForUser(r, - Settings.Secure.BACKUP_ENABLED, null, UserHandle.USER_SYSTEM); - } else { - if (DEBUG) { - Slog.i(TAG, "Backup not yet configured; retaining null enable state"); + final ContentResolver r = sInstance.mContext.getContentResolver(); + final int enableState = Settings.Secure.getIntForUser(r, + Settings.Secure.BACKUP_ENABLED, -1, UserHandle.USER_SYSTEM); + if (enableState >= 0) { + if (DEBUG) { + Slog.i(TAG, "Migrating enable state " + (enableState != 0)); + } + writeBackupEnableState(enableState != 0, UserHandle.USER_SYSTEM); + Settings.Secure.putStringForUser(r, + Settings.Secure.BACKUP_ENABLED, null, UserHandle.USER_SYSTEM); + } else { + if (DEBUG) { + Slog.i(TAG, "Backup not yet configured; retaining null enable state"); + } } } - } - Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); - Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup enable"); - try { - sInstance.setBackupEnabled(readBackupEnableState(UserHandle.USER_SYSTEM)); - } catch (RemoteException e) { - // can't happen; it's a local object - } - Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup enable"); + try { + sInstance.setBackupEnabled(readBackupEnableState(UserHandle.USER_SYSTEM)); + } catch (RemoteException e) { + // can't happen; it's a local object + } + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); + }); } class ProvisionedObserver extends ContentObserver { @@ -1213,7 +1220,7 @@ public class BackupManagerService implements BackupManagerServiceInterface { // ----- Main service implementation ----- - public BackupManagerService(Context context, Trampoline parent, HandlerThread backupThread) { + public BackupManagerService(Context context, Trampoline parent) { mContext = context; mPackageManager = context.getPackageManager(); mPackageManagerBinder = AppGlobals.getPackageManager(); @@ -1226,7 +1233,9 @@ public class BackupManagerService implements BackupManagerServiceInterface { mBackupManagerBinder = Trampoline.asInterface(parent.asBinder()); // spin up the backup/restore handler thread - mBackupHandler = new BackupHandler(backupThread.getLooper()); + mHandlerThread = new HandlerThread("backup", Process.THREAD_PRIORITY_BACKGROUND); + mHandlerThread.start(); + mBackupHandler = new BackupHandler(mHandlerThread.getLooper()); // Set up our bookkeeping final ContentResolver resolver = context.getContentResolver(); @@ -1351,7 +1360,7 @@ public class BackupManagerService implements BackupManagerServiceInterface { if (DEBUG) Slog.v(TAG, "Starting with transport " + currentTransport); mTransportManager = new TransportManager(context, transportWhitelist, currentTransport, - mTransportBoundListener, backupThread.getLooper()); + mTransportBoundListener, mHandlerThread.getLooper()); mTransportManager.registerAllTransports(); // Now that we know about valid backup participants, parse any diff --git a/com/android/server/backup/RefactoredBackupManagerService.java b/com/android/server/backup/RefactoredBackupManagerService.java index 20f23690..f2980659 100644 --- a/com/android/server/backup/RefactoredBackupManagerService.java +++ b/com/android/server/backup/RefactoredBackupManagerService.java @@ -237,6 +237,7 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter private boolean mProvisioned; private boolean mAutoRestore; private PowerManager.WakeLock mWakelock; + private HandlerThread mHandlerThread; private BackupHandler mBackupHandler; private PendingIntent mRunBackupIntent; private PendingIntent mRunInitIntent; @@ -555,37 +556,43 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter // Called through the trampoline from onUnlockUser(), then we buck the work // off to the background thread to keep the unlock time down. public void unlockSystemUser() { - // Migrate legacy setting - Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup migrate"); - if (!backupSettingMigrated(UserHandle.USER_SYSTEM)) { - if (DEBUG) { - Slog.i(TAG, "Backup enable apparently not migrated"); - } - final ContentResolver r = sInstance.mContext.getContentResolver(); - final int enableState = Settings.Secure.getIntForUser(r, - Settings.Secure.BACKUP_ENABLED, -1, UserHandle.USER_SYSTEM); - if (enableState >= 0) { + mBackupHandler.post(() -> { + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup init"); + sInstance.initialize(UserHandle.USER_SYSTEM); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); + + // Migrate legacy setting + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup migrate"); + if (!backupSettingMigrated(UserHandle.USER_SYSTEM)) { if (DEBUG) { - Slog.i(TAG, "Migrating enable state " + (enableState != 0)); + Slog.i(TAG, "Backup enable apparently not migrated"); } - writeBackupEnableState(enableState != 0, UserHandle.USER_SYSTEM); - Settings.Secure.putStringForUser(r, - Settings.Secure.BACKUP_ENABLED, null, UserHandle.USER_SYSTEM); - } else { - if (DEBUG) { - Slog.i(TAG, "Backup not yet configured; retaining null enable state"); + final ContentResolver r = sInstance.mContext.getContentResolver(); + final int enableState = Settings.Secure.getIntForUser(r, + Settings.Secure.BACKUP_ENABLED, -1, UserHandle.USER_SYSTEM); + if (enableState >= 0) { + if (DEBUG) { + Slog.i(TAG, "Migrating enable state " + (enableState != 0)); + } + writeBackupEnableState(enableState != 0, UserHandle.USER_SYSTEM); + Settings.Secure.putStringForUser(r, + Settings.Secure.BACKUP_ENABLED, null, UserHandle.USER_SYSTEM); + } else { + if (DEBUG) { + Slog.i(TAG, "Backup not yet configured; retaining null enable state"); + } } } - } - Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); - Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup enable"); - try { - sInstance.setBackupEnabled(readBackupEnableState(UserHandle.USER_SYSTEM)); - } catch (RemoteException e) { - // can't happen; it's a local object - } - Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup enable"); + try { + sInstance.setBackupEnabled(readBackupEnableState(UserHandle.USER_SYSTEM)); + } catch (RemoteException e) { + // can't happen; it's a local object + } + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); + }); } // Bookkeeping of in-flight operations for timeout etc. purposes. The operation @@ -722,8 +729,7 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter // ----- Main service implementation ----- - public RefactoredBackupManagerService(Context context, Trampoline parent, - HandlerThread backupThread) { + public RefactoredBackupManagerService(Context context, Trampoline parent) { mContext = context; mPackageManager = context.getPackageManager(); mPackageManagerBinder = AppGlobals.getPackageManager(); @@ -736,7 +742,9 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter mBackupManagerBinder = Trampoline.asInterface(parent.asBinder()); // spin up the backup/restore handler thread - mBackupHandler = new BackupHandler(this, backupThread.getLooper()); + mHandlerThread = new HandlerThread("backup", Process.THREAD_PRIORITY_BACKGROUND); + mHandlerThread.start(); + mBackupHandler = new BackupHandler(this, mHandlerThread.getLooper()); // Set up our bookkeeping final ContentResolver resolver = context.getContentResolver(); @@ -816,7 +824,7 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter if (DEBUG) Slog.v(TAG, "Starting with transport " + currentTransport); mTransportManager = new TransportManager(context, transportWhitelist, currentTransport, - mTransportBoundListener, backupThread.getLooper()); + mTransportBoundListener, mHandlerThread.getLooper()); mTransportManager.registerAllTransports(); // Now that we know about valid backup participants, parse any diff --git a/com/android/server/backup/Trampoline.java b/com/android/server/backup/Trampoline.java index 9847edf8..9739e380 100644 --- a/com/android/server/backup/Trampoline.java +++ b/com/android/server/backup/Trampoline.java @@ -28,15 +28,11 @@ import android.content.Context; import android.content.Intent; import android.os.Binder; import android.os.Environment; -import android.os.Handler; -import android.os.HandlerThread; import android.os.IBinder; -import android.os.Looper; import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.RemoteException; import android.os.SystemProperties; -import android.os.Trace; import android.os.UserHandle; import android.provider.Settings; import android.util.Slog; @@ -79,8 +75,6 @@ public class Trampoline extends IBackupManager.Stub { final boolean mGlobalDisable; volatile BackupManagerServiceInterface mService; - private HandlerThread mHandlerThread; - public Trampoline(Context context) { mContext = context; mGlobalDisable = isBackupDisabled(); @@ -117,11 +111,11 @@ public class Trampoline extends IBackupManager.Stub { } protected BackupManagerServiceInterface createRefactoredBackupManagerService() { - return new RefactoredBackupManagerService(mContext, this, mHandlerThread); + return new RefactoredBackupManagerService(mContext, this); } protected BackupManagerServiceInterface createBackupManagerService() { - return new BackupManagerService(mContext, this, mHandlerThread); + return new BackupManagerService(mContext, this); } // internal control API @@ -146,21 +140,10 @@ public class Trampoline extends IBackupManager.Stub { } void unlockSystemUser() { - mHandlerThread = new HandlerThread("backup", Process.THREAD_PRIORITY_BACKGROUND); - mHandlerThread.start(); - - Handler h = new Handler(mHandlerThread.getLooper()); - h.post(() -> { - Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup init"); - initialize(UserHandle.USER_SYSTEM); - Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); - - BackupManagerServiceInterface svc = mService; - Slog.i(TAG, "Unlocking system user; mService=" + mService); - if (svc != null) { - svc.unlockSystemUser(); - } - }); + BackupManagerServiceInterface svc = mService; + if (svc != null) { + svc.unlockSystemUser(); + } } public void setBackupServiceActive(final int userHandle, boolean makeActive) { diff --git a/com/android/server/clipboard/ClipboardService.java b/com/android/server/clipboard/ClipboardService.java index 0c9d70a9..e6228d46 100644 --- a/com/android/server/clipboard/ClipboardService.java +++ b/com/android/server/clipboard/ClipboardService.java @@ -435,12 +435,11 @@ public class ClipboardService extends SystemService { } private boolean isDeviceLocked() { - int callingUserId = UserHandle.getCallingUserId(); final long token = Binder.clearCallingIdentity(); try { final KeyguardManager keyguardManager = getContext().getSystemService( KeyguardManager.class); - return keyguardManager != null && keyguardManager.isDeviceLocked(callingUserId); + return keyguardManager != null && keyguardManager.isDeviceLocked(); } finally { Binder.restoreCallingIdentity(token); } diff --git a/com/android/server/connectivity/Tethering.java b/com/android/server/connectivity/Tethering.java index d7cd81ff..5583e86c 100644 --- a/com/android/server/connectivity/Tethering.java +++ b/com/android/server/connectivity/Tethering.java @@ -1371,7 +1371,6 @@ public class Tethering extends BaseNetworkObserver { sendMessageDelayed(CMD_RETRY_UPSTREAM, UPSTREAM_SETTLE_TIME_MS); } } - mUpstreamNetworkMonitor.setCurrentUpstream((ns != null) ? ns.network : null); setUpstreamNetwork(ns); } diff --git a/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java b/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java index b35ed751..c5f75280 100644 --- a/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java +++ b/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java @@ -95,10 +95,7 @@ public class UpstreamNetworkMonitor { private NetworkCallback mDefaultNetworkCallback; private NetworkCallback mMobileNetworkCallback; private boolean mDunRequired; - // The current system default network (not really used yet). - private Network mDefaultInternetNetwork; - // The current upstream network used for tethering. - private Network mTetheringUpstreamNetwork; + private Network mCurrentDefault; public UpstreamNetworkMonitor(Context ctx, StateMachine tgt, SharedLog log, int what) { mContext = ctx; @@ -133,12 +130,10 @@ public class UpstreamNetworkMonitor { releaseCallback(mDefaultNetworkCallback); mDefaultNetworkCallback = null; - mDefaultInternetNetwork = null; releaseCallback(mListenAllCallback); mListenAllCallback = null; - mTetheringUpstreamNetwork = null; mNetworkMap.clear(); } @@ -212,7 +207,7 @@ public class UpstreamNetworkMonitor { break; default: /* If we've found an active upstream connection that's not DUN/HIPRI - * we should stop any outstanding DUN/HIPRI requests. + * 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. @@ -224,10 +219,6 @@ public class UpstreamNetworkMonitor { return typeStatePair.ns; } - public void setCurrentUpstream(Network upstream) { - mTetheringUpstreamNetwork = upstream; - } - public Set<IpPrefix> getLocalPrefixes() { return (Set<IpPrefix>) mLocalPrefixes.clone(); } @@ -259,7 +250,7 @@ public class UpstreamNetworkMonitor { // These request*() calls can be deleted post oag/339444. return; } - mDefaultInternetNetwork = network; + mCurrentDefault = network; break; case CALLBACK_MOBILE_REQUEST: @@ -311,13 +302,6 @@ public class UpstreamNetworkMonitor { network, newNc)); } - // Log changes in upstream network signal strength, if available. - if (network.equals(mTetheringUpstreamNetwork) && newNc.hasSignalStrength()) { - final int newSignal = newNc.getSignalStrength(); - final String prevSignal = getSignalStrength(prev.networkCapabilities); - mLog.logf("upstream network signal strength: %s -> %s", prevSignal, newSignal); - } - mNetworkMap.put(network, new NetworkState( null, prev.linkProperties, newNc, network, null, null)); // TODO: If sufficient information is available to select a more @@ -346,21 +330,9 @@ public class UpstreamNetworkMonitor { notifyTarget(EVENT_ON_LINKPROPERTIES, network); } - private void handleSuspended(int callbackType, Network network) { - if (callbackType != CALLBACK_LISTEN_ALL) return; - if (!network.equals(mTetheringUpstreamNetwork)) return; - mLog.log("SUSPENDED current upstream: " + network); - } - - private void handleResumed(int callbackType, Network network) { - if (callbackType != CALLBACK_LISTEN_ALL) return; - if (!network.equals(mTetheringUpstreamNetwork)) return; - mLog.log("RESUMED current upstream: " + network); - } - private void handleLost(int callbackType, Network network) { if (callbackType == CALLBACK_TRACK_DEFAULT) { - mDefaultInternetNetwork = null; + mCurrentDefault = null; // Receiving onLost() for a default network does not necessarily // mean the network is gone. We wait for a separate notification // on either the LISTEN_ALL or MOBILE_REQUEST callbacks before @@ -429,15 +401,8 @@ public class UpstreamNetworkMonitor { recomputeLocalPrefixes(); } - @Override - public void onNetworkSuspended(Network network) { - handleSuspended(mCallbackType, network); - } - - @Override - public void onNetworkResumed(Network network) { - handleResumed(mCallbackType, network); - } + // TODO: Handle onNetworkSuspended(); + // TODO: Handle onNetworkResumed(); @Override public void onLost(Network network) { @@ -502,9 +467,4 @@ public class UpstreamNetworkMonitor { return prefixSet; } - - private static String getSignalStrength(NetworkCapabilities nc) { - if (nc == null || !nc.hasSignalStrength()) return "unknown"; - return Integer.toString(nc.getSignalStrength()); - } } diff --git a/com/android/server/display/AutomaticBrightnessController.java b/com/android/server/display/AutomaticBrightnessController.java index 9a6e6094..9aabdab7 100644 --- a/com/android/server/display/AutomaticBrightnessController.java +++ b/com/android/server/display/AutomaticBrightnessController.java @@ -29,7 +29,6 @@ import android.os.Looper; import android.os.Message; import android.os.PowerManager; import android.os.SystemClock; -import android.os.Trace; import android.text.format.DateUtils; import android.util.EventLog; import android.util.MathUtils; @@ -305,7 +304,6 @@ class AutomaticBrightnessController { } private void handleLightSensorEvent(long time, float lux) { - Trace.traceCounter(Trace.TRACE_TAG_POWER, "ALS", (int) lux); mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX); if (mAmbientLightRingBuffer.size() == 0) { diff --git a/com/android/server/display/DisplayPowerController.java b/com/android/server/display/DisplayPowerController.java index f930b523..f8e58362 100644 --- a/com/android/server/display/DisplayPowerController.java +++ b/com/android/server/display/DisplayPowerController.java @@ -683,8 +683,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // Configure auto-brightness. boolean autoBrightnessEnabled = false; if (mAutomaticBrightnessController != null) { - final boolean autoBrightnessEnabledInDoze = - mAllowAutoBrightnessWhileDozingConfig && Display.isDozeState(state); + final boolean autoBrightnessEnabledInDoze = mAllowAutoBrightnessWhileDozingConfig + && (state == Display.STATE_DOZE || state == Display.STATE_DOZE_SUSPEND); autoBrightnessEnabled = mPowerRequest.useAutoBrightness && (state == Display.STATE_ON || autoBrightnessEnabledInDoze) && brightness < 0; @@ -726,7 +726,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } // Use default brightness when dozing unless overridden. - if (brightness < 0 && Display.isDozeState(state)) { + if (brightness < 0 && (state == Display.STATE_DOZE + || state == Display.STATE_DOZE_SUSPEND)) { brightness = mScreenBrightnessDozeConfig; } @@ -776,6 +777,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // Skip the animation when the screen is off or suspended or transition to/from VR. if (!mPendingScreenOff) { if (mSkipScreenOnBrightnessRamp) { + if (state == Display.STATE_ON) { if (mSkipRampState == RAMP_STATE_SKIP_NONE && mDozing) { mInitialAutoBrightness = brightness; @@ -792,25 +794,15 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } } - final boolean wasOrWillBeInVr = - (state == Display.STATE_VR || oldState == Display.STATE_VR); - final boolean initialRampSkip = - state == Display.STATE_ON && mSkipRampState != RAMP_STATE_SKIP_NONE; - // While dozing, sometimes the brightness is split into buckets. Rather than animating - // through the buckets, which is unlikely to be smooth in the first place, just jump - // right to the suggested brightness. - final boolean hasBrightnessBuckets = - Display.isDozeState(state) && mBrightnessBucketsInDozeConfig; - // If the color fade is totally covering the screen then we can change the backlight - // level without it being a noticeable jump since any actual content isn't yet visible. - final boolean isDisplayContentVisible = - mColorFadeEnabled && mPowerState.getColorFadeLevel() == 1.0f; - if (initialRampSkip || hasBrightnessBuckets - || wasOrWillBeInVr || !isDisplayContentVisible) { - animateScreenBrightness(brightness, 0); - } else { + boolean wasOrWillBeInVr = (state == Display.STATE_VR || oldState == Display.STATE_VR); + if ((state == Display.STATE_ON + && mSkipRampState == RAMP_STATE_SKIP_NONE + || state == Display.STATE_DOZE && !mBrightnessBucketsInDozeConfig) + && !wasOrWillBeInVr) { animateScreenBrightness(brightness, slowChange ? mBrightnessRampRateSlow : mBrightnessRampRateFast); + } else { + animateScreenBrightness(brightness, 0); } } @@ -933,7 +925,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } if (!reportOnly) { - Trace.traceCounter(Trace.TRACE_TAG_POWER, "ScreenState", state); mPowerState.setScreenState(state); // Tell battery stats about the transition. try { diff --git a/com/android/server/job/controllers/TimeController.java b/com/android/server/job/controllers/TimeController.java index ee4c606f..d90699a6 100644 --- a/com/android/server/job/controllers/TimeController.java +++ b/com/android/server/job/controllers/TimeController.java @@ -110,7 +110,7 @@ public final class TimeController extends StateController { maybeUpdateAlarmsLocked( job.hasTimingDelayConstraint() ? job.getEarliestRunTime() : Long.MAX_VALUE, job.hasDeadlineConstraint() ? job.getLatestRunTimeElapsed() : Long.MAX_VALUE, - new WorkSource(job.getSourceUid(), job.getSourcePackageName())); + job.getSourceUid()); } } @@ -156,7 +156,6 @@ public final class TimeController extends StateController { synchronized (mLock) { long nextExpiryTime = Long.MAX_VALUE; int nextExpiryUid = 0; - String nextExpiryPackageName = null; final long nowElapsedMillis = SystemClock.elapsedRealtime(); Iterator<JobStatus> it = mTrackedJobs.iterator(); @@ -172,13 +171,10 @@ public final class TimeController extends StateController { } else { // Sorted by expiry time, so take the next one and stop. nextExpiryTime = job.getLatestRunTimeElapsed(); nextExpiryUid = job.getSourceUid(); - nextExpiryPackageName = job.getSourcePackageName(); break; } } - setDeadlineExpiredAlarmLocked(nextExpiryTime, nextExpiryPackageName != null - ? new WorkSource(nextExpiryUid, nextExpiryPackageName) - : new WorkSource(nextExpiryUid)); + setDeadlineExpiredAlarmLocked(nextExpiryTime, nextExpiryUid); } } @@ -204,7 +200,6 @@ public final class TimeController extends StateController { final long nowElapsedMillis = SystemClock.elapsedRealtime(); long nextDelayTime = Long.MAX_VALUE; int nextDelayUid = 0; - String nextDelayPackageName = null; boolean ready = false; Iterator<JobStatus> it = mTrackedJobs.iterator(); while (it.hasNext()) { @@ -226,16 +221,13 @@ public final class TimeController extends StateController { if (nextDelayTime > jobDelayTime) { nextDelayTime = jobDelayTime; nextDelayUid = job.getSourceUid(); - nextDelayPackageName = job.getSourcePackageName(); } } } if (ready) { mStateChangedListener.onControllerStateChanged(); } - setDelayExpiredAlarmLocked(nextDelayTime, nextDelayPackageName != null - ? new WorkSource(nextDelayUid, nextDelayPackageName) - : new WorkSource(nextDelayUid)); + setDelayExpiredAlarmLocked(nextDelayTime, nextDelayUid); } } @@ -249,12 +241,12 @@ public final class TimeController extends StateController { } private void maybeUpdateAlarmsLocked(long delayExpiredElapsed, long deadlineExpiredElapsed, - WorkSource ws) { + int uid) { if (delayExpiredElapsed < mNextDelayExpiredElapsedMillis) { - setDelayExpiredAlarmLocked(delayExpiredElapsed, ws); + setDelayExpiredAlarmLocked(delayExpiredElapsed, uid); } if (deadlineExpiredElapsed < mNextJobExpiredElapsedMillis) { - setDeadlineExpiredAlarmLocked(deadlineExpiredElapsed, ws); + setDeadlineExpiredAlarmLocked(deadlineExpiredElapsed, uid); } } @@ -263,11 +255,11 @@ public final class TimeController extends StateController { * delay will expire. * This alarm <b>will</b> wake up the phone. */ - private void setDelayExpiredAlarmLocked(long alarmTimeElapsedMillis, WorkSource ws) { + private void setDelayExpiredAlarmLocked(long alarmTimeElapsedMillis, int uid) { alarmTimeElapsedMillis = maybeAdjustAlarmTime(alarmTimeElapsedMillis); mNextDelayExpiredElapsedMillis = alarmTimeElapsedMillis; updateAlarmWithListenerLocked(DELAY_TAG, mNextDelayExpiredListener, - mNextDelayExpiredElapsedMillis, ws); + mNextDelayExpiredElapsedMillis, uid); } /** @@ -275,11 +267,11 @@ public final class TimeController extends StateController { * deadline will expire. * This alarm <b>will</b> wake up the phone. */ - private void setDeadlineExpiredAlarmLocked(long alarmTimeElapsedMillis, WorkSource ws) { + private void setDeadlineExpiredAlarmLocked(long alarmTimeElapsedMillis, int uid) { alarmTimeElapsedMillis = maybeAdjustAlarmTime(alarmTimeElapsedMillis); mNextJobExpiredElapsedMillis = alarmTimeElapsedMillis; updateAlarmWithListenerLocked(DEADLINE_TAG, mDeadlineExpiredListener, - mNextJobExpiredElapsedMillis, ws); + mNextJobExpiredElapsedMillis, uid); } private long maybeAdjustAlarmTime(long proposedAlarmTimeElapsedMillis) { @@ -291,7 +283,7 @@ public final class TimeController extends StateController { } private void updateAlarmWithListenerLocked(String tag, OnAlarmListener listener, - long alarmTimeElapsed, WorkSource ws) { + long alarmTimeElapsed, int uid) { ensureAlarmServiceLocked(); if (alarmTimeElapsed == Long.MAX_VALUE) { mAlarmService.cancel(listener); @@ -300,7 +292,7 @@ public final class TimeController extends StateController { Slog.d(TAG, "Setting " + tag + " for: " + alarmTimeElapsed); } mAlarmService.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmTimeElapsed, - AlarmManager.WINDOW_HEURISTIC, 0, tag, listener, null, ws); + AlarmManager.WINDOW_HEURISTIC, 0, tag, listener, null, new WorkSource(uid)); } } diff --git a/com/android/server/location/GnssLocationProvider.java b/com/android/server/location/GnssLocationProvider.java index e41c17df..0aa6a90e 100644 --- a/com/android/server/location/GnssLocationProvider.java +++ b/com/android/server/location/GnssLocationProvider.java @@ -417,11 +417,7 @@ public class GnssLocationProvider implements LocationProviderInterface { // stops output right at 600m/s, depriving this of the information of a device that reaches // greater than 600m/s, and higher than the speed of sound to avoid impacting most use cases. private static final float ITAR_SPEED_LIMIT_METERS_PER_SECOND = 400.0F; - - // TODO: improve comment - // Volatile to ensure that potentially near-concurrent outputs from HAL - // react to this value change promptly - private volatile boolean mItarSpeedLimitExceeded = false; + private boolean mItarSpeedLimitExceeded = false; // GNSS Metrics private GnssMetrics mGnssMetrics; diff --git a/com/android/server/media/MediaSessionRecord.java b/com/android/server/media/MediaSessionRecord.java index 664d2f97..0b11479a 100644 --- a/com/android/server/media/MediaSessionRecord.java +++ b/com/android/server/media/MediaSessionRecord.java @@ -784,14 +784,6 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { mService.enforcePhoneStatePermission(pid, uid); } mFlags = flags; - if ((flags & MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) { - final long token = Binder.clearCallingIdentity(); - try { - mService.setGlobalPrioritySession(MediaSessionRecord.this); - } finally { - Binder.restoreCallingIdentity(token); - } - } mHandler.post(MessageHandler.MSG_UPDATE_SESSION_STATE); } diff --git a/com/android/server/media/MediaSessionService.java b/com/android/server/media/MediaSessionService.java index aa652445..b9a2d184 100644 --- a/com/android/server/media/MediaSessionService.java +++ b/com/android/server/media/MediaSessionService.java @@ -178,6 +178,17 @@ public class MediaSessionService extends SystemService implements Monitor { return; } if ((record.getFlags() & MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) { + if (mGlobalPrioritySession != record) { + Log.d(TAG, "Global priority session is changed from " + mGlobalPrioritySession + + " to " + record); + mGlobalPrioritySession = record; + if (user != null && user.mPriorityStack.contains(record)) { + // Handle the global priority session separately. + // Otherwise, it will be the media button session even after it becomes + // inactive because it has been the lastly played media app. + user.mPriorityStack.removeSession(record); + } + } if (DEBUG_KEY_EVENT) { Log.d(TAG, "Global priority session is updated, active=" + record.isActive()); } @@ -193,27 +204,10 @@ public class MediaSessionService extends SystemService implements Monitor { } } - public void setGlobalPrioritySession(MediaSessionRecord record) { - synchronized (mLock) { - FullUserRecord user = getFullUserRecordLocked(record.getUserId()); - if (mGlobalPrioritySession != record) { - Log.d(TAG, "Global priority session is changed from " + mGlobalPrioritySession - + " to " + record); - mGlobalPrioritySession = record; - if (user != null && user.mPriorityStack.contains(record)) { - // Handle the global priority session separately. - // Otherwise, it can be the media button session regardless of the active state - // because it or other system components might have been the lastly played media - // app. - user.mPriorityStack.removeSession(record); - } - } - } - } - private List<MediaSessionRecord> getActiveSessionsLocked(int userId) { - List<MediaSessionRecord> records = new ArrayList<>(); + List<MediaSessionRecord> records; if (userId == UserHandle.USER_ALL) { + records = new ArrayList<>(); int size = mUserRecords.size(); for (int i = 0; i < size; i++) { records.addAll(mUserRecords.valueAt(i).mPriorityStack.getActiveSessions(userId)); @@ -222,9 +216,9 @@ public class MediaSessionService extends SystemService implements Monitor { FullUserRecord user = getFullUserRecordLocked(userId); if (user == null) { Log.w(TAG, "getSessions failed. Unknown user " + userId); - return records; + return new ArrayList<>(); } - records.addAll(user.mPriorityStack.getActiveSessions(userId)); + records = user.mPriorityStack.getActiveSessions(userId); } // Return global priority session at the first whenever it's asked. diff --git a/com/android/server/notification/NotificationManagerService.java b/com/android/server/notification/NotificationManagerService.java index 238d87b7..14cd0555 100644 --- a/com/android/server/notification/NotificationManagerService.java +++ b/com/android/server/notification/NotificationManagerService.java @@ -133,6 +133,7 @@ import android.service.notification.NotificationListenerService; import android.service.notification.NotificationRankingUpdate; import android.service.notification.NotificationRecordProto; import android.service.notification.NotificationServiceDumpProto; +import android.service.notification.NotificationServiceProto; import android.service.notification.NotificationStats; import android.service.notification.SnoozeCriterion; import android.service.notification.StatusBarNotification; @@ -281,7 +282,6 @@ public class NotificationManagerService extends SystemService { private WindowManagerInternal mWindowManagerInternal; private AlarmManager mAlarmManager; private ICompanionDeviceManager mCompanionManager; - private AccessibilityManager mAccessibilityManager; final IBinder mForegroundToken = new Binder(); private WorkerHandler mHandler; @@ -1221,12 +1221,6 @@ public class NotificationManagerService extends SystemService { mUsageStats = us; } - @VisibleForTesting - void setAccessibilityManager(AccessibilityManager am) { - mAccessibilityManager = am; - } - - // TODO: All tests should use this init instead of the one-off setters above. @VisibleForTesting void init(Looper looper, IPackageManager packageManager, @@ -1241,8 +1235,6 @@ public class NotificationManagerService extends SystemService { Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE); - mAccessibilityManager = - (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE); mAm = ActivityManager.getService(); mPackageManager = packageManager; mPackageManagerClient = packageManagerClient; @@ -3262,7 +3254,7 @@ public class NotificationManagerService extends SystemService { final NotificationRecord nr = mNotificationList.get(i); if (filter.filtered && !filter.matches(nr.sbn)) continue; nr.dump(proto, filter.redact); - proto.write(NotificationRecordProto.STATE, NotificationRecordProto.POSTED); + proto.write(NotificationRecordProto.STATE, NotificationServiceProto.POSTED); } } N = mEnqueuedNotifications.size(); @@ -3271,7 +3263,7 @@ public class NotificationManagerService extends SystemService { final NotificationRecord nr = mEnqueuedNotifications.get(i); if (filter.filtered && !filter.matches(nr.sbn)) continue; nr.dump(proto, filter.redact); - proto.write(NotificationRecordProto.STATE, NotificationRecordProto.ENQUEUED); + proto.write(NotificationRecordProto.STATE, NotificationServiceProto.ENQUEUED); } } List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed(); @@ -3281,7 +3273,7 @@ public class NotificationManagerService extends SystemService { final NotificationRecord nr = snoozed.get(i); if (filter.filtered && !filter.matches(nr.sbn)) continue; nr.dump(proto, filter.redact); - proto.write(NotificationRecordProto.STATE, NotificationRecordProto.SNOOZED); + proto.write(NotificationRecordProto.STATE, NotificationServiceProto.SNOOZED); } } proto.end(records); @@ -4125,16 +4117,13 @@ public class NotificationManagerService extends SystemService { // These are set inside the conditional if the notification is allowed to make noise. boolean hasValidVibrate = false; boolean hasValidSound = false; - boolean sentAccessibilityEvent = false; - // If the notification will appear in the status bar, it should send an accessibility - // event - if (!record.isUpdate && record.getImportance() > IMPORTANCE_MIN) { - sendAccessibilityEvent(notification, record.sbn.getPackageName()); - sentAccessibilityEvent = true; - } if (aboveThreshold && isNotificationForCurrentUser(record)) { - + // If the notification will appear in the status bar, it should send an accessibility + // event + if (!record.isUpdate && record.getImportance() > IMPORTANCE_MIN) { + sendAccessibilityEvent(notification, record.sbn.getPackageName()); + } if (mSystemReady && mAudioManager != null) { Uri soundUri = record.getSound(); hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri); @@ -4152,10 +4141,6 @@ public class NotificationManagerService extends SystemService { boolean hasAudibleAlert = hasValidSound || hasValidVibrate; if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) { - if (!sentAccessibilityEvent) { - sendAccessibilityEvent(notification, record.sbn.getPackageName()); - sentAccessibilityEvent = true; - } if (DBG) Slog.v(TAG, "Interrupting!"); if (hasValidSound) { mSoundNotificationKey = key; @@ -4676,7 +4661,8 @@ public class NotificationManagerService extends SystemService { } void sendAccessibilityEvent(Notification notification, CharSequence packageName) { - if (!mAccessibilityManager.isEnabled()) { + AccessibilityManager manager = AccessibilityManager.getInstance(getContext()); + if (!manager.isEnabled()) { return; } @@ -4690,7 +4676,7 @@ public class NotificationManagerService extends SystemService { event.getText().add(tickerText); } - mAccessibilityManager.sendAccessibilityEvent(event); + manager.sendAccessibilityEvent(event); } /** diff --git a/com/android/server/notification/ZenModeFiltering.java b/com/android/server/notification/ZenModeFiltering.java index abf29006..a7a2743d 100644 --- a/com/android/server/notification/ZenModeFiltering.java +++ b/com/android/server/notification/ZenModeFiltering.java @@ -117,19 +117,15 @@ public class ZenModeFiltering { ZenLog.traceIntercepted(record, "alarmsOnly"); return true; case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: + if (isAlarm(record)) { + // Alarms are always priority + return false; + } // allow user-prioritized packages through in priority mode if (record.getPackagePriority() == Notification.PRIORITY_MAX) { ZenLog.traceNotIntercepted(record, "priorityApp"); return false; } - - if (isAlarm(record)) { - if (!config.allowAlarms) { - ZenLog.traceIntercepted(record, "!allowAlarms"); - return true; - } - return false; - } if (isCall(record)) { if (config.allowRepeatCallers && REPEAT_CALLERS.isRepeat(mContext, extras(record))) { @@ -163,15 +159,6 @@ public class ZenModeFiltering { } return false; } - AudioAttributes aa = record.getAudioAttributes(); - if (aa != null && AudioAttributes.SUPPRESSIBLE_USAGES.get(aa.getUsage()) == - AudioAttributes.SUPPRESSIBLE_MEDIA_SYSTEM_OTHER) { - if (!config.allowMediaSystemOther) { - ZenLog.traceIntercepted(record, "!allowMediaSystemOther"); - return true; - } - return false; - } ZenLog.traceIntercepted(record, "!priority"); return true; default: diff --git a/com/android/server/notification/ZenModeHelper.java b/com/android/server/notification/ZenModeHelper.java index 710684f4..9fcc67df 100644 --- a/com/android/server/notification/ZenModeHelper.java +++ b/com/android/server/notification/ZenModeHelper.java @@ -59,7 +59,6 @@ import android.util.SparseArray; import android.util.proto.ProtoOutputStream; import com.android.internal.R; -import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.server.LocalServices; @@ -88,7 +87,7 @@ public class ZenModeHelper { private final Context mContext; private final H mHandler; private final SettingsObserver mSettingsObserver; - @VisibleForTesting protected final AppOpsManager mAppOps; + private final AppOpsManager mAppOps; protected ZenModeConfig mDefaultConfig; private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>(); private final ZenModeFiltering mFiltering; @@ -103,9 +102,9 @@ public class ZenModeHelper { private final String SCHEDULED_DEFAULT_RULE_1 = "SCHEDULED_DEFAULT_RULE_1"; private final String SCHEDULED_DEFAULT_RULE_2 = "SCHEDULED_DEFAULT_RULE_2"; - @VisibleForTesting protected int mZenMode; + private int mZenMode; private int mUser = UserHandle.USER_SYSTEM; - @VisibleForTesting protected ZenModeConfig mConfig; + protected ZenModeConfig mConfig; private AudioManagerInternal mAudioManager; protected PackageManager mPm; private long mSuppressedEffects; @@ -596,9 +595,8 @@ public class ZenModeHelper { pw.println(config); return; } - pw.printf("allow(alarms=%b,media=%bcalls=%b,callsFrom=%s,repeatCallers=%b,messages=%b,messagesFrom=%s," + pw.printf("allow(calls=%b,callsFrom=%s,repeatCallers=%b,messages=%b,messagesFrom=%s," + "events=%b,reminders=%b,whenScreenOff=%b,whenScreenOn=%b)\n", - config.allowAlarms, config.allowMediaSystemOther, config.allowCalls, ZenModeConfig.sourceToString(config.allowCallsFrom), config.allowRepeatCallers, config.allowMessages, ZenModeConfig.sourceToString(config.allowMessagesFrom), @@ -815,8 +813,7 @@ public class ZenModeHelper { } } - @VisibleForTesting - protected void applyRestrictions() { + private void applyRestrictions() { final boolean zen = mZenMode != Global.ZEN_MODE_OFF; // notification restrictions @@ -825,10 +822,6 @@ public class ZenModeHelper { // call restrictions final boolean muteCalls = zen && !mConfig.allowCalls && !mConfig.allowRepeatCallers || (mSuppressedEffects & SUPPRESSED_EFFECT_CALLS) != 0; - // alarm restrictions - final boolean muteAlarms = zen && !mConfig.allowAlarms; - // alarm restrictions - final boolean muteMediaAndSystemSounds = zen && !mConfig.allowMediaSystemOther; // total silence restrictions final boolean muteEverything = mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS; @@ -840,18 +833,13 @@ public class ZenModeHelper { applyRestrictions(muteNotifications || muteEverything, usage); } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_CALL) { applyRestrictions(muteCalls || muteEverything, usage); - } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_ALARM) { - applyRestrictions(muteAlarms || muteEverything, usage); - } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_MEDIA_SYSTEM_OTHER) { - applyRestrictions(muteMediaAndSystemSounds || muteEverything, usage); } else { applyRestrictions(muteEverything, usage); } } } - @VisibleForTesting - protected void applyRestrictions(boolean mute, int usage) { + private void applyRestrictions(boolean mute, int usage) { final String[] exceptionPackages = null; // none (for now) mAppOps.setRestriction(AppOpsManager.OP_VIBRATE, usage, mute ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED, diff --git a/com/android/server/pm/LauncherAppsService.java b/com/android/server/pm/LauncherAppsService.java index b06b5838..4a5ce120 100644 --- a/com/android/server/pm/LauncherAppsService.java +++ b/com/android/server/pm/LauncherAppsService.java @@ -30,10 +30,12 @@ import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.ILauncherApps; import android.content.pm.IOnAppsChangedListener; +import android.content.pm.IPackageManager; import android.content.pm.LauncherApps.ShortcutQuery; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; +import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ParceledListSlice; import android.content.pm.ResolveInfo; import android.content.pm.ShortcutInfo; @@ -62,6 +64,7 @@ import com.android.internal.util.Preconditions; import com.android.server.LocalServices; import com.android.server.SystemService; +import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -86,14 +89,10 @@ public class LauncherAppsService extends SystemService { static class BroadcastCookie { public final UserHandle user; public final String packageName; - public final int callingUid; - public final int callingPid; - BroadcastCookie(UserHandle userHandle, String packageName, int callingPid, int callingUid) { + BroadcastCookie(UserHandle userHandle, String packageName) { this.user = userHandle; this.packageName = packageName; - this.callingUid = callingUid; - this.callingPid = callingPid; } } @@ -128,11 +127,6 @@ public class LauncherAppsService extends SystemService { return getCallingUid(); } - @VisibleForTesting - int injectBinderCallingPid() { - return getCallingPid(); - } - final int injectCallingUserId() { return UserHandle.getUserId(injectBinderCallingUid()); } @@ -172,7 +166,7 @@ public class LauncherAppsService extends SystemService { } mListeners.unregister(listener); mListeners.register(listener, new BroadcastCookie(UserHandle.of(getCallingUserId()), - callingPackage, injectBinderCallingPid(), injectBinderCallingUid())); + callingPackage)); } } @@ -444,7 +438,7 @@ public class LauncherAppsService extends SystemService { private void ensureShortcutPermission(@NonNull String callingPackage) { verifyCallingPackage(callingPackage); if (!mShortcutServiceInternal.hasShortcutHostPermission(getCallingUserId(), - callingPackage, injectBinderCallingPid(), injectBinderCallingUid())) { + callingPackage)) { throw new SecurityException("Caller can't access shortcut information"); } } @@ -467,8 +461,7 @@ public class LauncherAppsService extends SystemService { return new ParceledListSlice<>((List<ShortcutInfo>) mShortcutServiceInternal.getShortcuts(getCallingUserId(), callingPackage, changedSince, packageName, shortcutIds, - componentName, flags, targetUser.getIdentifier(), - injectBinderCallingPid(), injectBinderCallingUid())); + componentName, flags, targetUser.getIdentifier())); } @Override @@ -521,7 +514,7 @@ public class LauncherAppsService extends SystemService { public boolean hasShortcutHostPermission(String callingPackage) { verifyCallingPackage(callingPackage); return mShortcutServiceInternal.hasShortcutHostPermission(getCallingUserId(), - callingPackage, injectBinderCallingPid(), injectBinderCallingUid()); + callingPackage); } @Override @@ -543,8 +536,7 @@ public class LauncherAppsService extends SystemService { } final Intent[] intents = mShortcutServiceInternal.createShortcutIntents( - getCallingUserId(), callingPackage, packageName, shortcutId, targetUserId, - injectBinderCallingPid(), injectBinderCallingUid()); + getCallingUserId(), callingPackage, packageName, shortcutId, targetUserId); if (intents == null || intents.length == 0) { return false; } @@ -909,8 +901,7 @@ public class LauncherAppsService extends SystemService { // Make sure the caller has the permission. if (!mShortcutServiceInternal.hasShortcutHostPermission( - launcherUserId, cookie.packageName, - cookie.callingPid, cookie.callingUid)) { + launcherUserId, cookie.packageName)) { continue; } // Each launcher has a different set of pinned shortcuts, so we need to do a @@ -923,8 +914,8 @@ public class LauncherAppsService extends SystemService { /* changedSince= */ 0, packageName, /* shortcutIds=*/ null, /* component= */ null, ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY - | ShortcutQuery.FLAG_MATCH_ALL_KINDS_WITH_ALL_PINNED - , userId, cookie.callingPid, cookie.callingUid); + | ShortcutQuery.FLAG_GET_ALL_KINDS + , userId); try { listener.onShortcutChanged(user, packageName, new ParceledListSlice<>(list)); diff --git a/com/android/server/pm/PackageDexOptimizer.java b/com/android/server/pm/PackageDexOptimizer.java index cf0ffbb1..8ebeeae2 100644 --- a/com/android/server/pm/PackageDexOptimizer.java +++ b/com/android/server/pm/PackageDexOptimizer.java @@ -236,10 +236,9 @@ public class PackageDexOptimizer { */ @GuardedBy("mInstallLock") private int dexOptPath(PackageParser.Package pkg, String path, String isa, - String compilerFilter, boolean profileUpdated, String classLoaderContext, + String compilerFilter, boolean profileUpdated, String sharedLibrariesPath, int dexoptFlags, int uid, CompilerStats.PackageStats packageStats, boolean downgrade) { - int dexoptNeeded = getDexoptNeeded(path, isa, compilerFilter, classLoaderContext, - profileUpdated, downgrade); + int dexoptNeeded = getDexoptNeeded(path, isa, compilerFilter, profileUpdated, downgrade); if (Math.abs(dexoptNeeded) == DexFile.NO_DEXOPT_NEEDED) { return DEX_OPT_SKIPPED; } @@ -252,8 +251,8 @@ public class PackageDexOptimizer { Log.i(TAG, "Running dexopt (dexoptNeeded=" + dexoptNeeded + ") on: " + path + " pkg=" + pkg.applicationInfo.packageName + " isa=" + isa + " dexoptFlags=" + printDexoptFlags(dexoptFlags) - + " targetFilter=" + compilerFilter + " oatDir=" + oatDir - + " classLoaderContext=" + classLoaderContext); + + " target-filter=" + compilerFilter + " oatDir=" + oatDir + + " sharedLibraries=" + sharedLibrariesPath); try { long startTime = System.currentTimeMillis(); @@ -262,7 +261,7 @@ public class PackageDexOptimizer { // installd only uses downgrade flag for secondary dex files and ignores it for // primary dex files. mInstaller.dexopt(path, uid, pkg.packageName, isa, dexoptNeeded, oatDir, dexoptFlags, - compilerFilter, pkg.volumeUuid, classLoaderContext, pkg.applicationInfo.seInfo, + compilerFilter, pkg.volumeUuid, sharedLibrariesPath, pkg.applicationInfo.seInfo, false /* downgrade*/); if (packageStats != null) { @@ -509,11 +508,11 @@ public class PackageDexOptimizer { * configuration (isa, compiler filter, profile). */ private int getDexoptNeeded(String path, String isa, String compilerFilter, - String classLoaderContext, boolean newProfile, boolean downgrade) { + boolean newProfile, boolean downgrade) { int dexoptNeeded; try { - dexoptNeeded = DexFile.getDexOptNeeded(path, isa, compilerFilter, classLoaderContext, - newProfile, downgrade); + dexoptNeeded = DexFile.getDexOptNeeded(path, isa, compilerFilter, newProfile, + downgrade); } catch (IOException ioe) { Slog.w(TAG, "IOException reading apk: " + path, ioe); return DEX_OPT_FAILED; diff --git a/com/android/server/pm/PackageInstallerSession.java b/com/android/server/pm/PackageInstallerSession.java index 496ebc23..d62f0934 100644 --- a/com/android/server/pm/PackageInstallerSession.java +++ b/com/android/server/pm/PackageInstallerSession.java @@ -1127,8 +1127,15 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { mResolvedInstructionSets.add(archSubDir.getName()); List<File> oatFiles = Arrays.asList(archSubDir.listFiles()); - if (!oatFiles.isEmpty()) { - mResolvedInheritedFiles.addAll(oatFiles); + + // Only add compiled files associated with the base. + // Once b/62269291 is resolved, we can add all compiled files again. + for (File oatFile : oatFiles) { + if (oatFile.getName().equals("base.art") + || oatFile.getName().equals("base.odex") + || oatFile.getName().equals("base.vdex")) { + mResolvedInheritedFiles.add(oatFile); + } } } } diff --git a/com/android/server/pm/PackageManagerService.java b/com/android/server/pm/PackageManagerService.java index 275db1fa..7d1a6470 100644 --- a/com/android/server/pm/PackageManagerService.java +++ b/com/android/server/pm/PackageManagerService.java @@ -398,7 +398,7 @@ public class PackageManagerService extends IPackageManager.Stub static final boolean DEBUG_DOMAIN_VERIFICATION = false; private static final boolean DEBUG_BACKUP = false; private static final boolean DEBUG_INSTALL = false; - public static final boolean DEBUG_REMOVE = false; + private static final boolean DEBUG_REMOVE = false; private static final boolean DEBUG_BROADCASTS = false; private static final boolean DEBUG_SHOW_INFO = false; private static final boolean DEBUG_PACKAGE_INFO = false; @@ -406,7 +406,7 @@ public class PackageManagerService extends IPackageManager.Stub public static final boolean DEBUG_PACKAGE_SCANNING = false; private static final boolean DEBUG_VERIFY = false; private static final boolean DEBUG_FILTERS = false; - public static final boolean DEBUG_PERMISSIONS = false; + private static final boolean DEBUG_PERMISSIONS = false; private static final boolean DEBUG_SHARED_LIBRARIES = false; private static final boolean DEBUG_COMPRESSION = Build.IS_DEBUGGABLE; @@ -954,6 +954,9 @@ public class PackageManagerService extends IPackageManager.Stub final SparseArray<PackageVerificationState> mPendingVerification = new SparseArray<PackageVerificationState>(); + /** Set of packages associated with each app op permission. */ + final ArrayMap<String, ArraySet<String>> mAppOpPermissionPackages = new ArrayMap<>(); + final PackageInstallerService mInstallerService; private final PackageDexOptimizer mPackageDexOptimizer; @@ -2878,7 +2881,7 @@ public class PackageManagerService extends IPackageManager.Stub + mSdkVersion + "; regranting permissions for internal storage"); updateFlags |= UPDATE_PERMISSIONS_REPLACE_PKG | UPDATE_PERMISSIONS_REPLACE_ALL; } - updatePermissionsLocked(null, null, StorageManager.UUID_PRIVATE_INTERNAL, updateFlags); + updatePermissionsLPw(null, null, StorageManager.UUID_PRIVATE_INTERNAL, updateFlags); ver.sdkVersion = mSdkVersion; // If this is the first boot or an update from pre-M, and it is a normal @@ -3261,6 +3264,23 @@ public class PackageManagerService extends IPackageManager.Stub return null; } + // If we have a profile for a compressed APK, copy it to the reference location. + // Since the package is the stub one, remove the stub suffix to get the normal package and + // APK name. + File profileFile = new File(getPrebuildProfilePath(pkg).replace(STUB_SUFFIX, "")); + if (profileFile.exists()) { + try { + // We could also do this lazily before calling dexopt in + // PackageDexOptimizer to prevent this happening on first boot. The issue + // is that we don't have a good way to say "do this only once". + if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(), + pkg.applicationInfo.uid, pkg.packageName)) { + Log.e(TAG, "decompressPackage failed to copy system profile!"); + } + } catch (Exception e) { + Log.e(TAG, "Failed to copy profile " + profileFile.getAbsolutePath() + " ", e); + } + } return dstCodePath; } @@ -3348,9 +3368,7 @@ public class PackageManagerService extends IPackageManager.Stub @Override public boolean isUpgrade() { // allow instant applications - // The system property allows testing ota flow when upgraded to the same image. - return mIsUpgrade || SystemProperties.getBoolean( - "persist.pm.mock-upgrade", false /* default */); + return mIsUpgrade; } private @Nullable String getRequiredButNotReallyRequiredVerifierLPr() { @@ -5164,7 +5182,7 @@ public class PackageManagerService extends IPackageManager.Stub final PermissionsState permissionsState = settingBase.getPermissionsState(); if (permissionsState.hasPermission(permName, userId)) { if (isUidInstantApp) { - if (mSettings.mPermissions.isPermissionInstant(permName)) { + if (mPermissionManager.isPermissionInstant(permName)) { return PackageManager.PERMISSION_GRANTED; } } else { @@ -5233,8 +5251,8 @@ public class PackageManagerService extends IPackageManager.Stub } } - private boolean addDynamicPermission(PermissionInfo info, final boolean async) { - return mPermissionManager.addDynamicPermission( + boolean addPermission(PermissionInfo info, final boolean async) { + return mPermissionManager.addPermission( info, async, getCallingUid(), new PermissionCallback() { @Override public void onPermissionChanged() { @@ -5250,20 +5268,20 @@ public class PackageManagerService extends IPackageManager.Stub @Override public boolean addPermission(PermissionInfo info) { synchronized (mPackages) { - return addDynamicPermission(info, false); + return addPermission(info, false); } } @Override public boolean addPermissionAsync(PermissionInfo info) { synchronized (mPackages) { - return addDynamicPermission(info, true); + return addPermission(info, true); } } @Override public void removePermission(String permName) { - mPermissionManager.removeDynamicPermission(permName, getCallingUid(), mPermissionCallback); + mPermissionManager.removePermission(permName, getCallingUid(), mPermissionCallback); } @Override @@ -5924,8 +5942,17 @@ public class PackageManagerService extends IPackageManager.Stub } @Override - public String[] getAppOpPermissionPackages(String permName) { - return mPermissionManager.getAppOpPermissionPackages(permName); + public String[] getAppOpPermissionPackages(String permissionName) { + if (getInstantAppPackageName(Binder.getCallingUid()) != null) { + return null; + } + synchronized (mPackages) { + ArraySet<String> pkgs = mAppOpPermissionPackages.get(permissionName); + if (pkgs == null) { + return null; + } + return pkgs.toArray(new String[pkgs.size()]); + } } @Override @@ -9097,30 +9124,10 @@ public class PackageManagerService extends IPackageManager.Stub // package and APK names. String systemProfilePath = getPrebuildProfilePath(disabledPs.pkg).replace(STUB_SUFFIX, ""); - profileFile = new File(systemProfilePath); - // If we have a profile for a compressed APK, copy it to the reference - // location. - // Note that copying the profile here will cause it to override the - // reference profile every OTA even though the existing reference profile - // may have more data. We can't copy during decompression since the - // directories are not set up at that point. - if (profileFile.exists()) { - try { - // We could also do this lazily before calling dexopt in - // PackageDexOptimizer to prevent this happening on first boot. The - // issue is that we don't have a good way to say "do this only - // once". - if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(), - pkg.applicationInfo.uid, pkg.packageName)) { - Log.e(TAG, "Failed to copy system profile for stub package!"); - } else { - useProfileForDexopt = true; - } - } catch (Exception e) { - Log.e(TAG, "Failed to copy profile " + - profileFile.getAbsolutePath() + " ", e); - } - } + File systemProfile = new File(systemProfilePath); + // Use the profile for compilation if there exists one for the same package + // in the system partition. + useProfileForDexopt = systemProfile.exists(); } } } @@ -10339,7 +10346,7 @@ public class PackageManagerService extends IPackageManager.Stub Slog.i(TAG, "Adopting permissions from " + origName + " to " + pkg.packageName); // SIDE EFFECTS; updates permissions system state; move elsewhere - mSettings.mPermissions.transferPermissions(origName, pkg.packageName); + mSettings.transferPermissionsLPw(origName, pkg.packageName); } } } @@ -11187,13 +11194,54 @@ public class PackageManagerService extends IPackageManager.Stub if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Permission Groups: " + r); } + N = pkg.permissions.size(); + r = null; + for (i=0; i<N; i++) { + PackageParser.Permission p = pkg.permissions.get(i); - // Dont allow ephemeral apps to define new permissions. - if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) { - Slog.w(TAG, "Permissions from package " + pkg.packageName - + " ignored: instant apps cannot define new permissions."); - } else { - mPermissionManager.addAllPermissions(pkg, chatty); + // Dont allow ephemeral apps to define new permissions. + if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) { + Slog.w(TAG, "Permission " + p.info.name + " from package " + + p.info.packageName + + " ignored: instant apps cannot define new permissions."); + continue; + } + + // Assume by default that we did not install this permission into the system. + p.info.flags &= ~PermissionInfo.FLAG_INSTALLED; + + // Now that permission groups have a special meaning, we ignore permission + // groups for legacy apps to prevent unexpected behavior. In particular, + // permissions for one app being granted to someone just because they happen + // to be in a group defined by another app (before this had no implications). + if (pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) { + p.group = mPermissionGroups.get(p.info.group); + // Warn for a permission in an unknown group. + if (DEBUG_PERMISSIONS && p.info.group != null && p.group == null) { + Slog.i(TAG, "Permission " + p.info.name + " from package " + + p.info.packageName + " in an unknown group " + p.info.group); + } + } + + // TODO Move to PermissionManager once mPermissionTrees moves there. +// p.tree ? mSettings.mPermissionTrees +// : mSettings.mPermissions; +// final BasePermission bp = BasePermission.createOrUpdate( +// permissionMap.get(p.info.name), p, pkg, mSettings.mPermissionTrees, chatty); +// permissionMap.put(p.info.name, bp); + if (p.tree) { + final ArrayMap<String, BasePermission> permissionMap = + mSettings.mPermissionTrees; + final BasePermission bp = BasePermission.createOrUpdate( + permissionMap.get(p.info.name), p, pkg, mSettings.mPermissionTrees, + chatty); + permissionMap.put(p.info.name, bp); + } else { + final BasePermission bp = BasePermission.createOrUpdate( + (BasePermission) mPermissionManager.getPermissionTEMP(p.info.name), + p, pkg, mSettings.mPermissionTrees, chatty); + mPermissionManager.putPermissionTEMP(p.info.name, bp); + } } N = pkg.instrumentation.size(); @@ -11919,7 +11967,53 @@ public class PackageManagerService extends IPackageManager.Stub if (DEBUG_REMOVE) Log.d(TAG, " Activities: " + r); } - mPermissionManager.removeAllPermissions(pkg, chatty); + N = pkg.permissions.size(); + r = null; + for (i=0; i<N; i++) { + PackageParser.Permission p = pkg.permissions.get(i); + BasePermission bp = (BasePermission) mPermissionManager.getPermissionTEMP(p.info.name); + if (bp == null) { + bp = mSettings.mPermissionTrees.get(p.info.name); + } + if (bp != null && bp.isPermission(p)) { + bp.setPermission(null); + if (DEBUG_REMOVE && chatty) { + if (r == null) { + r = new StringBuilder(256); + } else { + r.append(' '); + } + r.append(p.info.name); + } + } + if ((p.info.protectionLevel&PermissionInfo.PROTECTION_FLAG_APPOP) != 0) { + ArraySet<String> appOpPkgs = mAppOpPermissionPackages.get(p.info.name); + if (appOpPkgs != null) { + appOpPkgs.remove(pkg.packageName); + } + } + } + if (r != null) { + if (DEBUG_REMOVE) Log.d(TAG, " Permissions: " + r); + } + + N = pkg.requestedPermissions.size(); + r = null; + for (i=0; i<N; i++) { + String perm = pkg.requestedPermissions.get(i); + if (mPermissionManager.isPermissionAppOp(perm)) { + ArraySet<String> appOpPkgs = mAppOpPermissionPackages.get(perm); + if (appOpPkgs != null) { + appOpPkgs.remove(pkg.packageName); + if (appOpPkgs.isEmpty()) { + mAppOpPermissionPackages.remove(perm); + } + } + } + } + if (r != null) { + if (DEBUG_REMOVE) Log.d(TAG, " Permissions: " + r); + } N = pkg.instrumentation.size(); r = null; @@ -11980,9 +12074,18 @@ public class PackageManagerService extends IPackageManager.Stub } } - public static final int UPDATE_PERMISSIONS_ALL = 1<<0; - public static final int UPDATE_PERMISSIONS_REPLACE_PKG = 1<<1; - public static final int UPDATE_PERMISSIONS_REPLACE_ALL = 1<<2; + private static boolean hasPermission(PackageParser.Package pkgInfo, String perm) { + for (int i=pkgInfo.permissions.size()-1; i>=0; i--) { + if (pkgInfo.permissions.get(i).info.name.equals(perm)) { + return true; + } + } + return false; + } + + static final int UPDATE_PERMISSIONS_ALL = 1<<0; + static final int UPDATE_PERMISSIONS_REPLACE_PKG = 1<<1; + static final int UPDATE_PERMISSIONS_REPLACE_ALL = 1<<2; private void updatePermissionsLPw(PackageParser.Package pkg, int flags) { // Update the parent permissions @@ -11998,10 +12101,10 @@ public class PackageManagerService extends IPackageManager.Stub private void updatePermissionsLPw(String changingPkg, PackageParser.Package pkgInfo, int flags) { final String volumeUuid = (pkgInfo != null) ? getVolumeUuidForPackage(pkgInfo) : null; - updatePermissionsLocked(changingPkg, pkgInfo, volumeUuid, flags); + updatePermissionsLPw(changingPkg, pkgInfo, volumeUuid, flags); } - private void updatePermissionsLocked(String changingPkg, + private void updatePermissionsLPw(String changingPkg, PackageParser.Package pkgInfo, String replaceVolumeUuid, int flags) { // TODO: Most of the methods exposing BasePermission internals [source package name, // etc..] shouldn't be needed. Instead, when we've parsed a permission that doesn't @@ -12013,11 +12116,55 @@ public class PackageManagerService extends IPackageManager.Stub // normal permissions. Today, we need two separate loops because these BasePermission // objects are stored separately. // Make sure there are no dangling permission trees. - flags = mPermissionManager.updatePermissionTrees(changingPkg, pkgInfo, flags); + Iterator<BasePermission> it = mSettings.mPermissionTrees.values().iterator(); + while (it.hasNext()) { + final BasePermission bp = it.next(); + if (bp.getSourcePackageSetting() == null) { + // We may not yet have parsed the package, so just see if + // we still know about its settings. + bp.setSourcePackageSetting(mSettings.mPackages.get(bp.getSourcePackageName())); + } + if (bp.getSourcePackageSetting() == null) { + Slog.w(TAG, "Removing dangling permission tree: " + bp.getName() + + " from package " + bp.getSourcePackageName()); + it.remove(); + } else if (changingPkg != null && changingPkg.equals(bp.getSourcePackageName())) { + if (pkgInfo == null || !hasPermission(pkgInfo, bp.getName())) { + Slog.i(TAG, "Removing old permission tree: " + bp.getName() + + " from package " + bp.getSourcePackageName()); + flags |= UPDATE_PERMISSIONS_ALL; + it.remove(); + } + } + } // Make sure all dynamic permissions have been assigned to a package, // and make sure there are no dangling permissions. - flags = mPermissionManager.updatePermissions(changingPkg, pkgInfo, flags); + final Iterator<BasePermission> permissionIter = + mPermissionManager.getPermissionIteratorTEMP(); + while (permissionIter.hasNext()) { + final BasePermission bp = permissionIter.next(); + if (bp.isDynamic()) { + bp.updateDynamicPermission(mSettings.mPermissionTrees); + } + if (bp.getSourcePackageSetting() == null) { + // We may not yet have parsed the package, so just see if + // we still know about its settings. + bp.setSourcePackageSetting(mSettings.mPackages.get(bp.getSourcePackageName())); + } + if (bp.getSourcePackageSetting() == null) { + Slog.w(TAG, "Removing dangling permission: " + bp.getName() + + " from package " + bp.getSourcePackageName()); + permissionIter.remove(); + } else if (changingPkg != null && changingPkg.equals(bp.getSourcePackageName())) { + if (pkgInfo == null || !hasPermission(pkgInfo, bp.getName())) { + Slog.i(TAG, "Removing old permission: " + bp.getName() + + " from package " + bp.getSourcePackageName()); + flags |= UPDATE_PERMISSIONS_ALL; + permissionIter.remove(); + } + } + } Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "grantPermissions"); // Now update the permissions for all packages, in particular @@ -12139,7 +12286,12 @@ public class PackageManagerService extends IPackageManager.Stub // Keep track of app op permissions. if (bp.isAppOp()) { - mSettings.addAppOpPackage(perm, pkg.packageName); + ArraySet<String> pkgs = mAppOpPermissionPackages.get(perm); + if (pkgs == null) { + pkgs = new ArraySet<>(); + mAppOpPermissionPackages.put(perm, pkgs); + } + pkgs.add(pkg.packageName); } if (bp.isNormal()) { @@ -21086,7 +21238,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); // permissions, ensure permissions are updated. Beware of dragons if you // try optimizing this. synchronized (mPackages) { - updatePermissionsLocked(null, null, StorageManager.UUID_PRIVATE_INTERNAL, + updatePermissionsLPw(null, null, StorageManager.UUID_PRIVATE_INTERNAL, UPDATE_PERMISSIONS_ALL); } @@ -21137,8 +21289,9 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); reconcileApps(StorageManager.UUID_PRIVATE_INTERNAL); if (mPrivappPermissionsViolations != null) { - throw new IllegalStateException("Signature|privileged permissions not in " + Slog.wtf(TAG,"Signature|privileged permissions not in " + "privapp-permissions whitelist: " + mPrivappPermissionsViolations); + mPrivappPermissionsViolations = null; } } @@ -21631,6 +21784,22 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); if (!checkin && dumpState.isDumping(DumpState.DUMP_PERMISSIONS)) { mSettings.dumpPermissionsLPr(pw, packageName, permissionNames, dumpState); + if (packageName == null && permissionNames == null) { + for (int iperm=0; iperm<mAppOpPermissionPackages.size(); iperm++) { + if (iperm == 0) { + if (dumpState.onTitlePrinted()) + pw.println(); + pw.println("AppOp Permissions:"); + } + pw.print(" AppOp Permission "); + pw.print(mAppOpPermissionPackages.keyAt(iperm)); + pw.println(":"); + ArraySet<String> pkgs = mAppOpPermissionPackages.valueAt(iperm); + for (int ipkg=0; ipkg<pkgs.size(); ipkg++) { + pw.print(" "); pw.println(pkgs.valueAt(ipkg)); + } + } + } } if (!checkin && dumpState.isDumping(DumpState.DUMP_PROVIDERS)) { @@ -21860,7 +22029,11 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); synchronized (mAvailableFeatures) { final int count = mAvailableFeatures.size(); for (int i = 0; i < count; i++) { - mAvailableFeatures.valueAt(i).writeToProto(proto, PackageServiceDumpProto.FEATURES); + final FeatureInfo feat = mAvailableFeatures.valueAt(i); + final long featureToken = proto.start(PackageServiceDumpProto.FEATURES); + proto.write(PackageServiceDumpProto.FeatureProto.NAME, feat.name); + proto.write(PackageServiceDumpProto.FeatureProto.VERSION, feat.version); + proto.end(featureToken); } } } @@ -21892,7 +22065,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); } private void dumpDexoptStateLPr(PrintWriter pw, String packageName) { - final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); + final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120); ipw.println(); ipw.println("Dexopt state:"); ipw.increaseIndent(); @@ -21919,7 +22092,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); } private void dumpCompilerStatsLPr(PrintWriter pw, String packageName) { - final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); + final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120); ipw.println(); ipw.println("Compiler stats:"); ipw.increaseIndent(); @@ -22130,7 +22303,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); + mSdkVersion + "; regranting permissions for " + volumeUuid); updateFlags |= UPDATE_PERMISSIONS_REPLACE_PKG | UPDATE_PERMISSIONS_REPLACE_ALL; } - updatePermissionsLocked(null, null, volumeUuid, updateFlags); + updatePermissionsLPw(null, null, volumeUuid, updateFlags); // Yay, everything is now upgraded ver.forceCurrent(); @@ -23138,15 +23311,15 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); void onNewUserCreated(final int userId) { synchronized(mPackages) { mDefaultPermissionPolicy.grantDefaultPermissions(mPackages.values(), userId); - // If permission review for legacy apps is required, we represent - // dagerous permissions for such apps as always granted runtime - // permissions to keep per user flag state whether review is needed. - // Hence, if a new user is added we have to propagate dangerous - // permission grants for these legacy apps. - if (mPermissionReviewRequired) { - updatePermissionsLPw(null, null, UPDATE_PERMISSIONS_ALL - | UPDATE_PERMISSIONS_REPLACE_ALL); - } + } + // If permission review for legacy apps is required, we represent + // dagerous permissions for such apps as always granted runtime + // permissions to keep per user flag state whether review is needed. + // Hence, if a new user is added we have to propagate dangerous + // permission grants for these legacy apps. + if (mPermissionReviewRequired) { + updatePermissionsLPw(null, null, UPDATE_PERMISSIONS_ALL + | UPDATE_PERMISSIONS_REPLACE_ALL); } } @@ -23590,12 +23763,12 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); } @Override - public PackageParser.PermissionGroup getPermissionGroupTEMP(String groupName) { + public Object enforcePermissionTreeTEMP(String permName, int callingUid) { synchronized (mPackages) { - return mPermissionGroups.get(groupName); + return BasePermission.enforcePermissionTreeLP( + mSettings.mPermissionTrees, permName, callingUid); } } - @Override public boolean isInstantApp(String packageName, int userId) { return PackageManagerService.this.isInstantApp(packageName, userId); diff --git a/com/android/server/pm/Settings.java b/com/android/server/pm/Settings.java index 191b43a6..00844114 100644 --- a/com/android/server/pm/Settings.java +++ b/com/android/server/pm/Settings.java @@ -378,6 +378,10 @@ public final class Settings { private final ArrayMap<Long, Integer> mKeySetRefs = new ArrayMap<Long, Integer>(); + // Mapping from permission tree names to info about them. + final ArrayMap<String, BasePermission> mPermissionTrees = + new ArrayMap<String, BasePermission>(); + // Packages that have been uninstalled and still need their external // storage data deleted. final ArrayList<PackageCleanItem> mPackagesToBeCleaned = new ArrayList<PackageCleanItem>(); @@ -412,7 +416,7 @@ public final class Settings { public final KeySetManagerService mKeySetManagerService = new KeySetManagerService(mPackages); /** Settings and other information about permissions */ - final PermissionSettings mPermissions; + private final PermissionSettings mPermissions; Settings(PermissionSettings permissions, Object lock) { this(Environment.getDataDirectory(), permissions, lock); @@ -618,10 +622,6 @@ public final class Settings { return null; } - void addAppOpPackage(String permName, String packageName) { - mPermissions.addAppOpPackage(permName, packageName); - } - SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags, int pkgPrivateFlags) { SharedUserSetting s = mSharedUsers.get(name); if (s != null) { @@ -666,6 +666,13 @@ public final class Settings { } /** + * Transfers ownership of permissions from one package to another. + */ + void transferPermissionsLPw(String origPackageName, String newPackageName) { + mPermissions.transferPermissions(origPackageName, newPackageName, mPermissionTrees); + } + + /** * Creates a new {@code PackageSetting} object. * Use this method instead of the constructor to ensure a settings object is created * with the correct base. @@ -2489,7 +2496,9 @@ public final class Settings { } serializer.startTag(null, "permission-trees"); - mPermissions.writePermissionTrees(serializer); + for (BasePermission bp : mPermissionTrees.values()) { + writePermissionLPr(serializer, bp); + } serializer.endTag(null, "permission-trees"); serializer.startTag(null, "permissions"); @@ -3033,7 +3042,7 @@ public final class Settings { } else if (tagName.equals("permissions")) { mPermissions.readPermissions(parser); } else if (tagName.equals("permission-trees")) { - mPermissions.readPermissionTrees(parser); + PermissionSettings.readPermissions(mPermissionTrees, parser); } else if (tagName.equals("shared-user")) { readSharedUserLPw(parser); } else if (tagName.equals("preferred-packages")) { @@ -4929,7 +4938,11 @@ public final class Settings { void dumpSharedUsersProto(ProtoOutputStream proto) { final int count = mSharedUsers.size(); for (int i = 0; i < count; i++) { - mSharedUsers.valueAt(i).writeToProto(proto, PackageServiceDumpProto.SHARED_USERS); + final SharedUserSetting su = mSharedUsers.valueAt(i); + final long sharedUserToken = proto.start(PackageServiceDumpProto.SHARED_USERS); + proto.write(PackageServiceDumpProto.SharedUserProto.USER_ID, su.userId); + proto.write(PackageServiceDumpProto.SharedUserProto.NAME, su.name); + proto.end(sharedUserToken); } } diff --git a/com/android/server/pm/SharedUserSetting.java b/com/android/server/pm/SharedUserSetting.java index 877da144..a0dadae3 100644 --- a/com/android/server/pm/SharedUserSetting.java +++ b/com/android/server/pm/SharedUserSetting.java @@ -18,9 +18,7 @@ package com.android.server.pm; import android.annotation.Nullable; import android.content.pm.PackageParser; -import android.service.pm.PackageServiceDumpProto; import android.util.ArraySet; -import android.util.proto.ProtoOutputStream; import java.util.ArrayList; import java.util.Collection; @@ -55,13 +53,6 @@ public final class SharedUserSetting extends SettingBase { + name + "/" + userId + "}"; } - public void writeToProto(ProtoOutputStream proto, long fieldId) { - long token = proto.start(fieldId); - proto.write(PackageServiceDumpProto.SharedUserProto.USER_ID, userId); - proto.write(PackageServiceDumpProto.SharedUserProto.NAME, name); - proto.end(token); - } - void removePackage(PackageSetting packageSetting) { if (packages.remove(packageSetting)) { // recalculate the pkgFlags for this shared user if needed diff --git a/com/android/server/pm/ShortcutBitmapSaver.java b/com/android/server/pm/ShortcutBitmapSaver.java index 815f8851..4f5d1560 100644 --- a/com/android/server/pm/ShortcutBitmapSaver.java +++ b/com/android/server/pm/ShortcutBitmapSaver.java @@ -21,8 +21,6 @@ import android.content.pm.ShortcutInfo; import android.graphics.Bitmap; import android.graphics.Bitmap.CompressFormat; import android.graphics.drawable.Icon; -import android.os.StrictMode; -import android.os.StrictMode.ThreadPolicy; import android.os.SystemClock; import android.util.Log; import android.util.Slog; @@ -167,13 +165,7 @@ public class ShortcutBitmapSaver { // Compress it and enqueue to the requests. final byte[] bytes; - final StrictMode.ThreadPolicy oldPolicy = StrictMode.getThreadPolicy(); try { - // compress() triggers a slow call, but in this case it's needed to save RAM and also - // the target bitmap is of an icon size, so let's just permit it. - StrictMode.setThreadPolicy(new ThreadPolicy.Builder(oldPolicy) - .permitCustomSlowCalls() - .build()); final Bitmap shrunk = mService.shrinkBitmap(original, maxDimension); try { try (final ByteArrayOutputStream out = new ByteArrayOutputStream(64 * 1024)) { @@ -192,8 +184,6 @@ public class ShortcutBitmapSaver { } catch (IOException | RuntimeException | OutOfMemoryError e) { Slog.wtf(ShortcutService.TAG, "Unable to write bitmap to file", e); return; - } finally { - StrictMode.setThreadPolicy(oldPolicy); } shortcut.addFlags( diff --git a/com/android/server/pm/ShortcutLauncher.java b/com/android/server/pm/ShortcutLauncher.java index cedf4763..f922ad19 100644 --- a/com/android/server/pm/ShortcutLauncher.java +++ b/com/android/server/pm/ShortcutLauncher.java @@ -83,16 +83,11 @@ class ShortcutLauncher extends ShortcutPackageItem { return mOwnerUserId; } - @Override - protected boolean canRestoreAnyVersion() { - // Launcher's pinned shortcuts can be restored to an older version. - return true; - } - /** * Called when the new package can't receive the backup, due to signature or version mismatch. */ - private void onRestoreBlocked() { + @Override + protected void onRestoreBlocked() { final ArrayList<PackageWithUser> pinnedPackages = new ArrayList<>(mPinnedShortcuts.keySet()); mPinnedShortcuts.clear(); @@ -106,21 +101,15 @@ class ShortcutLauncher extends ShortcutPackageItem { } @Override - protected void onRestored(int restoreBlockReason) { - // For launcher, possible reasons here are DISABLED_REASON_SIGNATURE_MISMATCH or - // DISABLED_REASON_BACKUP_NOT_SUPPORTED. - // DISABLED_REASON_VERSION_LOWER will NOT happen because we don't check version - // code for launchers. - if (restoreBlockReason != ShortcutInfo.DISABLED_REASON_NOT_DISABLED) { - onRestoreBlocked(); - } + protected void onRestored() { + // Nothing to do. } /** * Pin the given shortcuts, replacing the current pinned ones. */ public void pinShortcuts(@UserIdInt int packageUserId, - @NonNull String packageName, @NonNull List<String> ids, boolean forPinRequest) { + @NonNull String packageName, @NonNull List<String> ids) { final ShortcutPackage packageShortcuts = mShortcutUser.getPackageShortcutsIfExists(packageName); if (packageShortcuts == null) { @@ -135,12 +124,8 @@ class ShortcutLauncher extends ShortcutPackageItem { } else { final ArraySet<String> prevSet = mPinnedShortcuts.get(pu); - // Actually pin shortcuts. - // This logic here is to make sure a launcher cannot pin a shortcut that is floating - // (i.e. not dynamic nor manifest but is pinned) and pinned by another launcher. - // In this case, technically the shortcut doesn't exist to this launcher, so it can't - // pin it. - // (Maybe unnecessarily strict...) + // Pin shortcuts. Make sure only pin the ones that were visible to the caller. + // i.e. a non-dynamic, pinned shortcut by *other launchers* shouldn't be pinned here. final ArraySet<String> newSet = new ArraySet<>(); @@ -150,10 +135,8 @@ class ShortcutLauncher extends ShortcutPackageItem { if (si == null) { continue; } - if (si.isDynamic() - || si.isManifestShortcut() - || (prevSet != null && prevSet.contains(id)) - || forPinRequest) { + if (si.isDynamic() || si.isManifestShortcut() + || (prevSet != null && prevSet.contains(id))) { newSet.add(id); } } @@ -172,7 +155,7 @@ class ShortcutLauncher extends ShortcutPackageItem { } /** - * Return true if the given shortcut is pinned by this launcher.<code></code> + * Return true if the given shortcut is pinned by this launcher. */ public boolean hasPinned(ShortcutInfo shortcut) { final ArraySet<String> pinned = @@ -181,10 +164,10 @@ class ShortcutLauncher extends ShortcutPackageItem { } /** - * Additionally pin a shortcut. c.f. {@link #pinShortcuts(int, String, List, boolean)} + * Additionally pin a shortcut. c.f. {@link #pinShortcuts(int, String, List)} */ public void addPinnedShortcut(@NonNull String packageName, @UserIdInt int packageUserId, - String id, boolean forPinRequest) { + String id) { final ArraySet<String> pinnedSet = getPinnedShortcutIds(packageName, packageUserId); final ArrayList<String> pinnedList; if (pinnedSet != null) { @@ -195,21 +178,21 @@ class ShortcutLauncher extends ShortcutPackageItem { } pinnedList.add(id); - pinShortcuts(packageUserId, packageName, pinnedList, forPinRequest); + pinShortcuts(packageUserId, packageName, pinnedList); } boolean cleanUpPackage(String packageName, @UserIdInt int packageUserId) { return mPinnedShortcuts.remove(PackageWithUser.of(packageUserId, packageName)) != null; } - public void ensurePackageInfo() { + public void ensureVersionInfo() { final PackageInfo pi = mShortcutUser.mService.getPackageInfoWithSignatures( getPackageName(), getPackageUserId()); if (pi == null) { Slog.w(TAG, "Package not found: " + getPackageName()); return; } - getPackageInfo().updateFromPackageInfo(pi); + getPackageInfo().updateVersionInfo(pi); } /** @@ -218,10 +201,6 @@ class ShortcutLauncher extends ShortcutPackageItem { @Override public void saveToXml(XmlSerializer out, boolean forBackup) throws IOException { - if (forBackup && !getPackageInfo().isBackupAllowed()) { - // If an launcher app doesn't support backup&restore, then nothing to do. - return; - } final int size = mPinnedShortcuts.size(); if (size == 0) { return; // Nothing to write. @@ -230,7 +209,7 @@ class ShortcutLauncher extends ShortcutPackageItem { out.startTag(null, TAG_ROOT); ShortcutService.writeAttr(out, ATTR_PACKAGE_NAME, getPackageName()); ShortcutService.writeAttr(out, ATTR_LAUNCHER_USER_ID, getPackageUserId()); - getPackageInfo().saveToXml(out, forBackup); + getPackageInfo().saveToXml(out); for (int i = 0; i < size; i++) { final PackageWithUser pu = mPinnedShortcuts.keyAt(i); diff --git a/com/android/server/pm/ShortcutPackage.java b/com/android/server/pm/ShortcutPackage.java index 12f490fa..6fc1e738 100644 --- a/com/android/server/pm/ShortcutPackage.java +++ b/com/android/server/pm/ShortcutPackage.java @@ -84,7 +84,6 @@ class ShortcutPackage extends ShortcutPackageItem { private static final String ATTR_DISABLED_MESSAGE = "dmessage"; private static final String ATTR_DISABLED_MESSAGE_RES_ID = "dmessageid"; private static final String ATTR_DISABLED_MESSAGE_RES_NAME = "dmessagename"; - private static final String ATTR_DISABLED_REASON = "disabled-reason"; private static final String ATTR_INTENT_LEGACY = "intent"; private static final String ATTR_INTENT_NO_EXTRA = "intent-base"; private static final String ATTR_RANK = "rank"; @@ -157,25 +156,13 @@ class ShortcutPackage extends ShortcutPackageItem { } @Override - protected boolean canRestoreAnyVersion() { - return false; + protected void onRestoreBlocked() { + // Can't restore due to version/signature mismatch. Remove all shortcuts. + mShortcuts.clear(); } @Override - protected void onRestored(int restoreBlockReason) { - // Shortcuts have been restored. - // - Unshadow all shortcuts. - // - Set disabled reason. - // - Disable if needed. - for (int i = mShortcuts.size() - 1; i >= 0; i--) { - ShortcutInfo si = mShortcuts.valueAt(i); - si.clearFlags(ShortcutInfo.FLAG_SHADOW); - - si.setDisabledReason(restoreBlockReason); - if (restoreBlockReason != ShortcutInfo.DISABLED_REASON_NOT_DISABLED) { - si.addFlags(ShortcutInfo.FLAG_DISABLED); - } - } + protected void onRestored() { // Because some launchers may not have been restored (e.g. allowBackup=false), // we need to re-calculate the pinned shortcuts. refreshPinnedFlags(); @@ -189,47 +176,31 @@ class ShortcutPackage extends ShortcutPackageItem { return mShortcuts.get(id); } - public boolean isShortcutExistsAndInvisibleToPublisher(String id) { - ShortcutInfo si = findShortcutById(id); - return si != null && !si.isVisibleToPublisher(); - } - - public boolean isShortcutExistsAndVisibleToPublisher(String id) { - ShortcutInfo si = findShortcutById(id); - return si != null && si.isVisibleToPublisher(); - } - - private void ensureNotImmutable(@Nullable ShortcutInfo shortcut, boolean ignoreInvisible) { - if (shortcut != null && shortcut.isImmutable() - && (!ignoreInvisible || shortcut.isVisibleToPublisher())) { + private void ensureNotImmutable(@Nullable ShortcutInfo shortcut) { + if (shortcut != null && shortcut.isImmutable()) { throw new IllegalArgumentException( "Manifest shortcut ID=" + shortcut.getId() + " may not be manipulated via APIs"); } } - public void ensureNotImmutable(@NonNull String id, boolean ignoreInvisible) { - ensureNotImmutable(mShortcuts.get(id), ignoreInvisible); + public void ensureNotImmutable(@NonNull String id) { + ensureNotImmutable(mShortcuts.get(id)); } - public void ensureImmutableShortcutsNotIncludedWithIds(@NonNull List<String> shortcutIds, - boolean ignoreInvisible) { + public void ensureImmutableShortcutsNotIncludedWithIds(@NonNull List<String> shortcutIds) { for (int i = shortcutIds.size() - 1; i >= 0; i--) { - ensureNotImmutable(shortcutIds.get(i), ignoreInvisible); + ensureNotImmutable(shortcutIds.get(i)); } } - public void ensureImmutableShortcutsNotIncluded(@NonNull List<ShortcutInfo> shortcuts, - boolean ignoreInvisible) { + public void ensureImmutableShortcutsNotIncluded(@NonNull List<ShortcutInfo> shortcuts) { for (int i = shortcuts.size() - 1; i >= 0; i--) { - ensureNotImmutable(shortcuts.get(i).getId(), ignoreInvisible); + ensureNotImmutable(shortcuts.get(i).getId()); } } - /** - * Delete a shortcut by ID. This will *always* remove it even if it's immutable or invisible. - */ - private ShortcutInfo forceDeleteShortcutInner(@NonNull String id) { + private ShortcutInfo deleteShortcutInner(@NonNull String id) { final ShortcutInfo shortcut = mShortcuts.remove(id); if (shortcut != null) { mShortcutUser.mService.removeIconLocked(shortcut); @@ -239,14 +210,10 @@ class ShortcutPackage extends ShortcutPackageItem { return shortcut; } - /** - * Force replace a shortcut. If there's already a shortcut with the same ID, it'll be removed, - * even if it's invisible. - */ - private void forceReplaceShortcutInner(@NonNull ShortcutInfo newShortcut) { + private void addShortcutInner(@NonNull ShortcutInfo newShortcut) { final ShortcutService s = mShortcutUser.mService; - forceDeleteShortcutInner(newShortcut.getId()); + deleteShortcutInner(newShortcut.getId()); // Extract Icon and update the icon res ID and the bitmap path. s.saveIconAndFixUpShortcutLocked(newShortcut); @@ -255,12 +222,11 @@ class ShortcutPackage extends ShortcutPackageItem { } /** - * Add a shortcut. If there's already a one with the same ID, it'll be removed, even if it's - * invisible. + * Add a shortcut, or update one with the same ID, with taking over existing flags. * * It checks the max number of dynamic shortcuts. */ - public void addOrReplaceDynamicShortcut(@NonNull ShortcutInfo newShortcut) { + public void addOrUpdateDynamicShortcut(@NonNull ShortcutInfo newShortcut) { Preconditions.checkArgument(newShortcut.isEnabled(), "add/setDynamicShortcuts() cannot publish disabled shortcuts"); @@ -276,7 +242,7 @@ class ShortcutPackage extends ShortcutPackageItem { } else { // It's an update case. // Make sure the target is updatable. (i.e. should be mutable.) - oldShortcut.ensureUpdatableWith(newShortcut, /*isUpdating=*/ false); + oldShortcut.ensureUpdatableWith(newShortcut); wasPinned = oldShortcut.isPinned(); } @@ -286,7 +252,7 @@ class ShortcutPackage extends ShortcutPackageItem { newShortcut.addFlags(ShortcutInfo.FLAG_PINNED); } - forceReplaceShortcutInner(newShortcut); + addShortcutInner(newShortcut); } /** @@ -307,7 +273,7 @@ class ShortcutPackage extends ShortcutPackageItem { } if (removeList != null) { for (int i = removeList.size() - 1; i >= 0; i--) { - forceDeleteShortcutInner(removeList.get(i)); + deleteShortcutInner(removeList.get(i)); } } } @@ -315,13 +281,13 @@ class ShortcutPackage extends ShortcutPackageItem { /** * Remove all dynamic shortcuts. */ - public void deleteAllDynamicShortcuts(boolean ignoreInvisible) { + public void deleteAllDynamicShortcuts() { final long now = mShortcutUser.mService.injectCurrentTimeMillis(); boolean changed = false; for (int i = mShortcuts.size() - 1; i >= 0; i--) { final ShortcutInfo si = mShortcuts.valueAt(i); - if (si.isDynamic() && (!ignoreInvisible || si.isVisibleToPublisher())) { + if (si.isDynamic()) { changed = true; si.setTimestamp(now); @@ -341,10 +307,9 @@ class ShortcutPackage extends ShortcutPackageItem { * @return true if it's actually removed because it wasn't pinned, or false if it's still * pinned. */ - public boolean deleteDynamicWithId(@NonNull String shortcutId, boolean ignoreInvisible) { + public boolean deleteDynamicWithId(@NonNull String shortcutId) { final ShortcutInfo removed = deleteOrDisableWithId( - shortcutId, /* disable =*/ false, /* overrideImmutable=*/ false, ignoreInvisible, - ShortcutInfo.DISABLED_REASON_NOT_DISABLED); + shortcutId, /* disable =*/ false, /* overrideImmutable=*/ false); return removed == null; } @@ -355,11 +320,9 @@ class ShortcutPackage extends ShortcutPackageItem { * @return true if it's actually removed because it wasn't pinned, or false if it's still * pinned. */ - private boolean disableDynamicWithId(@NonNull String shortcutId, boolean ignoreInvisible, - int disabledReason) { + private boolean disableDynamicWithId(@NonNull String shortcutId) { final ShortcutInfo disabled = deleteOrDisableWithId( - shortcutId, /* disable =*/ true, /* overrideImmutable=*/ false, ignoreInvisible, - disabledReason); + shortcutId, /* disable =*/ true, /* overrideImmutable=*/ false); return disabled == null; } @@ -368,10 +331,9 @@ class ShortcutPackage extends ShortcutPackageItem { * is pinned, it'll remain as a pinned shortcut but will be disabled. */ public void disableWithId(@NonNull String shortcutId, String disabledMessage, - int disabledMessageResId, boolean overrideImmutable, boolean ignoreInvisible, - int disabledReason) { + int disabledMessageResId, boolean overrideImmutable) { final ShortcutInfo disabled = deleteOrDisableWithId(shortcutId, /* disable =*/ true, - overrideImmutable, ignoreInvisible, disabledReason); + overrideImmutable); if (disabled != null) { if (disabledMessage != null) { @@ -386,18 +348,14 @@ class ShortcutPackage extends ShortcutPackageItem { @Nullable private ShortcutInfo deleteOrDisableWithId(@NonNull String shortcutId, boolean disable, - boolean overrideImmutable, boolean ignoreInvisible, int disabledReason) { - Preconditions.checkState( - (disable == (disabledReason != ShortcutInfo.DISABLED_REASON_NOT_DISABLED)), - "disable and disabledReason disagree: " + disable + " vs " + disabledReason); + boolean overrideImmutable) { final ShortcutInfo oldShortcut = mShortcuts.get(shortcutId); - if (oldShortcut == null || !oldShortcut.isEnabled() - && (ignoreInvisible && !oldShortcut.isVisibleToPublisher())) { + if (oldShortcut == null || !oldShortcut.isEnabled()) { return null; // Doesn't exist or already disabled. } if (!overrideImmutable) { - ensureNotImmutable(oldShortcut, /*ignoreInvisible=*/ true); + ensureNotImmutable(oldShortcut); } if (oldShortcut.isPinned()) { @@ -405,10 +363,6 @@ class ShortcutPackage extends ShortcutPackageItem { oldShortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_MANIFEST); if (disable) { oldShortcut.addFlags(ShortcutInfo.FLAG_DISABLED); - // Do not overwrite the disabled reason if one is alreay set. - if (oldShortcut.getDisabledReason() == ShortcutInfo.DISABLED_REASON_NOT_DISABLED) { - oldShortcut.setDisabledReason(disabledReason); - } } oldShortcut.setTimestamp(mShortcutUser.mService.injectCurrentTimeMillis()); @@ -419,7 +373,7 @@ class ShortcutPackage extends ShortcutPackageItem { return oldShortcut; } else { - forceDeleteShortcutInner(shortcutId); + deleteShortcutInner(shortcutId); return null; } } @@ -427,25 +381,11 @@ class ShortcutPackage extends ShortcutPackageItem { public void enableWithId(@NonNull String shortcutId) { final ShortcutInfo shortcut = mShortcuts.get(shortcutId); if (shortcut != null) { - ensureNotImmutable(shortcut, /*ignoreInvisible=*/ true); + ensureNotImmutable(shortcut); shortcut.clearFlags(ShortcutInfo.FLAG_DISABLED); - shortcut.setDisabledReason(ShortcutInfo.DISABLED_REASON_NOT_DISABLED); } } - public void updateInvisibleShortcutForPinRequestWith(@NonNull ShortcutInfo shortcut) { - final ShortcutInfo source = mShortcuts.get(shortcut.getId()); - Preconditions.checkNotNull(source); - - mShortcutUser.mService.validateShortcutForPinRequest(shortcut); - - shortcut.addFlags(ShortcutInfo.FLAG_PINNED); - - forceReplaceShortcutInner(shortcut); - - adjustRanks(); - } - /** * Called after a launcher updates the pinned set. For each shortcut in this package, * set FLAG_PINNED if any launcher has pinned it. Otherwise, clear it. @@ -570,7 +510,7 @@ class ShortcutPackage extends ShortcutPackageItem { */ public void findAll(@NonNull List<ShortcutInfo> result, @Nullable Predicate<ShortcutInfo> query, int cloneFlag) { - findAll(result, query, cloneFlag, null, 0, /*getPinnedByAnyLauncher=*/ false); + findAll(result, query, cloneFlag, null, 0); } /** @@ -582,7 +522,7 @@ class ShortcutPackage extends ShortcutPackageItem { */ public void findAll(@NonNull List<ShortcutInfo> result, @Nullable Predicate<ShortcutInfo> query, int cloneFlag, - @Nullable String callingLauncher, int launcherUserId, boolean getPinnedByAnyLauncher) { + @Nullable String callingLauncher, int launcherUserId) { if (getPackageInfo().isShadow()) { // Restored and the app not installed yet, so don't return any. return; @@ -604,11 +544,9 @@ class ShortcutPackage extends ShortcutPackageItem { final boolean isPinnedByCaller = (callingLauncher == null) || ((pinnedByCallerSet != null) && pinnedByCallerSet.contains(si.getId())); - if (!getPinnedByAnyLauncher) { - if (si.isFloating()) { - if (!isPinnedByCaller) { - continue; - } + if (si.isFloating()) { + if (!isPinnedByCaller) { + continue; } } final ShortcutInfo clone = si.clone(cloneFlag); @@ -755,27 +693,7 @@ class ShortcutPackage extends ShortcutPackageItem { getPackageInfo().getVersionCode(), pi.versionCode)); } - getPackageInfo().updateFromPackageInfo(pi); - final int newVersionCode = getPackageInfo().getVersionCode(); - - // See if there are any shortcuts that were prevented restoring because the app was of a - // lower version, and re-enable them. - for (int i = mShortcuts.size() - 1; i >= 0; i--) { - final ShortcutInfo si = mShortcuts.valueAt(i); - if (si.getDisabledReason() != ShortcutInfo.DISABLED_REASON_VERSION_LOWER) { - continue; - } - if (getPackageInfo().getBackupSourceVersionCode() > newVersionCode) { - if (ShortcutService.DEBUG) { - Slog.d(TAG, String.format("Shortcut %s require version %s, still not restored.", - si.getId(), getPackageInfo().getBackupSourceVersionCode())); - } - continue; - } - Slog.i(TAG, String.format("Restoring shortcut: %s", si.getId())); - si.clearFlags(ShortcutInfo.FLAG_DISABLED); - si.setDisabledReason(ShortcutInfo.DISABLED_REASON_NOT_DISABLED); - } + getPackageInfo().updateVersionInfo(pi); // For existing shortcuts, update timestamps if they have any resources. // Also check if shortcuts' activities are still main activities. Otherwise, disable them. @@ -795,8 +713,7 @@ class ShortcutPackage extends ShortcutPackageItem { Slog.w(TAG, String.format( "%s is no longer main activity. Disabling shorcut %s.", getPackageName(), si.getId())); - if (disableDynamicWithId(si.getId(), /*ignoreInvisible*/ false, - ShortcutInfo.DISABLED_REASON_APP_CHANGED)) { + if (disableDynamicWithId(si.getId())) { continue; // Actually removed. } // Still pinned, so fall-through and possibly update the resources. @@ -892,7 +809,7 @@ class ShortcutPackage extends ShortcutPackageItem { // Note even if enabled=false, we still need to update all fields, so do it // regardless. - forceReplaceShortcutInner(newShortcut); // This will clean up the old one too. + addShortcutInner(newShortcut); // This will clean up the old one too. if (!newDisabled && toDisableList != null) { // Still alive, don't remove. @@ -914,8 +831,7 @@ class ShortcutPackage extends ShortcutPackageItem { final String id = toDisableList.valueAt(i); disableWithId(id, /* disable message =*/ null, /* disable message resid */ 0, - /* overrideImmutable=*/ true, /*ignoreInvisible=*/ false, - ShortcutInfo.DISABLED_REASON_APP_CHANGED); + /* overrideImmutable=*/ true); } removeOrphans(); } @@ -953,7 +869,7 @@ class ShortcutPackage extends ShortcutPackageItem { service.wtf("Found manifest shortcuts in excess list."); continue; } - deleteDynamicWithId(shortcut.getId(), /*ignoreInvisible=*/ true); + deleteDynamicWithId(shortcut.getId()); } } @@ -1159,7 +1075,7 @@ class ShortcutPackage extends ShortcutPackageItem { if (ret != 0) { return ret; } - // If they're still tie, just sort by their IDs. + // If they're stil tie, just sort by their IDs. // This may happen with updateShortcuts() -- see // the testUpdateShortcuts_noManifestShortcuts() test. return a.getId().compareTo(b.getId()); @@ -1341,34 +1257,25 @@ class ShortcutPackage extends ShortcutPackageItem { ShortcutService.writeAttr(out, ATTR_NAME, getPackageName()); ShortcutService.writeAttr(out, ATTR_CALL_COUNT, mApiCallCount); ShortcutService.writeAttr(out, ATTR_LAST_RESET, mLastResetTime); - getPackageInfo().saveToXml(out, forBackup); + getPackageInfo().saveToXml(out); for (int j = 0; j < size; j++) { - saveShortcut(out, mShortcuts.valueAt(j), forBackup, - getPackageInfo().isBackupAllowed()); + saveShortcut(out, mShortcuts.valueAt(j), forBackup); } out.endTag(null, TAG_ROOT); } - private void saveShortcut(XmlSerializer out, ShortcutInfo si, boolean forBackup, - boolean appSupportsBackup) + private void saveShortcut(XmlSerializer out, ShortcutInfo si, boolean forBackup) throws IOException, XmlPullParserException { final ShortcutService s = mShortcutUser.mService; if (forBackup) { if (!(si.isPinned() && si.isEnabled())) { - // We only backup pinned shortcuts that are enabled. - // Note, this means, shortcuts that are restored but are blocked restore, e.g. due - // to a lower version code, will not be ported to a new device. - return; + return; // We only backup pinned shortcuts that are enabled. } } - final boolean shouldBackupDetails = - !forBackup // It's not backup - || appSupportsBackup; // Or, it's a backup and app supports backup. - // Note: at this point no shortcuts should have bitmaps pending save, but if they do, // just remove the bitmap. if (si.isIconPendingSave()) { @@ -1385,31 +1292,20 @@ class ShortcutPackage extends ShortcutPackageItem { ShortcutService.writeAttr(out, ATTR_TEXT, si.getText()); ShortcutService.writeAttr(out, ATTR_TEXT_RES_ID, si.getTextResId()); ShortcutService.writeAttr(out, ATTR_TEXT_RES_NAME, si.getTextResName()); - if (shouldBackupDetails) { - ShortcutService.writeAttr(out, ATTR_DISABLED_MESSAGE, si.getDisabledMessage()); - ShortcutService.writeAttr(out, ATTR_DISABLED_MESSAGE_RES_ID, - si.getDisabledMessageResourceId()); - ShortcutService.writeAttr(out, ATTR_DISABLED_MESSAGE_RES_NAME, - si.getDisabledMessageResName()); - } - ShortcutService.writeAttr(out, ATTR_DISABLED_REASON, si.getDisabledReason()); + ShortcutService.writeAttr(out, ATTR_DISABLED_MESSAGE, si.getDisabledMessage()); + ShortcutService.writeAttr(out, ATTR_DISABLED_MESSAGE_RES_ID, + si.getDisabledMessageResourceId()); + ShortcutService.writeAttr(out, ATTR_DISABLED_MESSAGE_RES_NAME, + si.getDisabledMessageResName()); ShortcutService.writeAttr(out, ATTR_TIMESTAMP, si.getLastChangedTimestamp()); if (forBackup) { // Don't write icon information. Also drop the dynamic flag. - - int flags = si.getFlags() & - ~(ShortcutInfo.FLAG_HAS_ICON_FILE | ShortcutInfo.FLAG_HAS_ICON_RES + ShortcutService.writeAttr(out, ATTR_FLAGS, + si.getFlags() & + ~(ShortcutInfo.FLAG_HAS_ICON_FILE | ShortcutInfo.FLAG_HAS_ICON_RES | ShortcutInfo.FLAG_ICON_FILE_PENDING_SAVE - | ShortcutInfo.FLAG_DYNAMIC); - ShortcutService.writeAttr(out, ATTR_FLAGS, flags); - - // Set the publisher version code at every backup. - final int packageVersionCode = getPackageInfo().getVersionCode(); - if (packageVersionCode == 0) { - s.wtf("Package version code should be available at this point."); - // However, 0 is a valid version code, so we just go ahead with it... - } + | ShortcutInfo.FLAG_DYNAMIC)); } else { // When writing for backup, ranks shouldn't be saved, since shortcuts won't be restored // as dynamic. @@ -1421,28 +1317,26 @@ class ShortcutPackage extends ShortcutPackageItem { ShortcutService.writeAttr(out, ATTR_BITMAP_PATH, si.getBitmapPath()); } - if (shouldBackupDetails) { - { - final Set<String> cat = si.getCategories(); - if (cat != null && cat.size() > 0) { - out.startTag(null, TAG_CATEGORIES); - XmlUtils.writeStringArrayXml(cat.toArray(new String[cat.size()]), - NAME_CATEGORIES, out); - out.endTag(null, TAG_CATEGORIES); - } - } - final Intent[] intentsNoExtras = si.getIntentsNoExtras(); - final PersistableBundle[] intentsExtras = si.getIntentPersistableExtrases(); - final int numIntents = intentsNoExtras.length; - for (int i = 0; i < numIntents; i++) { - out.startTag(null, TAG_INTENT); - ShortcutService.writeAttr(out, ATTR_INTENT_NO_EXTRA, intentsNoExtras[i]); - ShortcutService.writeTagExtra(out, TAG_EXTRAS, intentsExtras[i]); - out.endTag(null, TAG_INTENT); + { + final Set<String> cat = si.getCategories(); + if (cat != null && cat.size() > 0) { + out.startTag(null, TAG_CATEGORIES); + XmlUtils.writeStringArrayXml(cat.toArray(new String[cat.size()]), + NAME_CATEGORIES, out); + out.endTag(null, TAG_CATEGORIES); } - - ShortcutService.writeTagExtra(out, TAG_EXTRAS, si.getExtras()); } + final Intent[] intentsNoExtras = si.getIntentsNoExtras(); + final PersistableBundle[] intentsExtras = si.getIntentPersistableExtrases(); + final int numIntents = intentsNoExtras.length; + for (int i = 0; i < numIntents; i++) { + out.startTag(null, TAG_INTENT); + ShortcutService.writeAttr(out, ATTR_INTENT_NO_EXTRA, intentsNoExtras[i]); + ShortcutService.writeTagExtra(out, TAG_EXTRAS, intentsExtras[i]); + out.endTag(null, TAG_INTENT); + } + + ShortcutService.writeTagExtra(out, TAG_EXTRAS, si.getExtras()); out.endTag(null, TAG_SHORTCUT); } @@ -1462,7 +1356,6 @@ class ShortcutPackage extends ShortcutPackageItem { ret.mLastResetTime = ShortcutService.parseLongAttribute(parser, ATTR_LAST_RESET); - final int outerDepth = parser.getDepth(); int type; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT @@ -1476,11 +1369,10 @@ class ShortcutPackage extends ShortcutPackageItem { switch (tag) { case ShortcutPackageInfo.TAG_ROOT: ret.getPackageInfo().loadFromXml(parser, fromBackup); - continue; case TAG_SHORTCUT: final ShortcutInfo si = parseShortcut(parser, packageName, - shortcutUser.getUserId(), fromBackup); + shortcutUser.getUserId()); // Don't use addShortcut(), we don't need to save the icon. ret.mShortcuts.put(si.getId(), si); @@ -1493,8 +1385,7 @@ class ShortcutPackage extends ShortcutPackageItem { } private static ShortcutInfo parseShortcut(XmlPullParser parser, String packageName, - @UserIdInt int userId, boolean fromBackup) - throws IOException, XmlPullParserException { + @UserIdInt int userId) throws IOException, XmlPullParserException { String id; ComponentName activityComponent; // Icon icon; @@ -1507,7 +1398,6 @@ class ShortcutPackage extends ShortcutPackageItem { String disabledMessage; int disabledMessageResId; String disabledMessageResName; - int disabledReason; Intent intentLegacy; PersistableBundle intentPersistableExtrasLegacy = null; ArrayList<Intent> intents = new ArrayList<>(); @@ -1518,7 +1408,6 @@ class ShortcutPackage extends ShortcutPackageItem { int iconResId; String iconResName; String bitmapPath; - int backupVersionCode; ArraySet<String> categories = null; id = ShortcutService.parseStringAttribute(parser, ATTR_ID); @@ -1535,7 +1424,6 @@ class ShortcutPackage extends ShortcutPackageItem { ATTR_DISABLED_MESSAGE_RES_ID); disabledMessageResName = ShortcutService.parseStringAttribute(parser, ATTR_DISABLED_MESSAGE_RES_NAME); - disabledReason = ShortcutService.parseIntAttribute(parser, ATTR_DISABLED_REASON); intentLegacy = ShortcutService.parseIntentAttributeNoDefault(parser, ATTR_INTENT_LEGACY); rank = (int) ShortcutService.parseLongAttribute(parser, ATTR_RANK); lastChangedTimestamp = ShortcutService.parseLongAttribute(parser, ATTR_TIMESTAMP); @@ -1592,19 +1480,6 @@ class ShortcutPackage extends ShortcutPackageItem { intents.add(intentLegacy); } - - if ((disabledReason == ShortcutInfo.DISABLED_REASON_NOT_DISABLED) - && ((flags & ShortcutInfo.FLAG_DISABLED) != 0)) { - // We didn't used to have the disabled reason, so if a shortcut is disabled - // and has no reason, we assume it was disabled by publisher. - disabledReason = ShortcutInfo.DISABLED_REASON_BY_APP; - } - - // All restored shortcuts are initially "shadow". - if (fromBackup) { - flags |= ShortcutInfo.FLAG_SHADOW; - } - return new ShortcutInfo( userId, id, packageName, activityComponent, /* icon =*/ null, title, titleResId, titleResName, text, textResId, textResName, @@ -1612,7 +1487,7 @@ class ShortcutPackage extends ShortcutPackageItem { categories, intents.toArray(new Intent[intents.size()]), rank, extras, lastChangedTimestamp, flags, - iconResId, iconResName, bitmapPath, disabledReason); + iconResId, iconResName, bitmapPath); } private static Intent parseIntent(XmlPullParser parser) @@ -1727,20 +1602,6 @@ class ShortcutPackage extends ShortcutPackageItem { Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId() + " has both resource and bitmap icons"); } - if (si.isEnabled() - != (si.getDisabledReason() == ShortcutInfo.DISABLED_REASON_NOT_DISABLED)) { - failed = true; - Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId() - + " isEnabled() and getDisabledReason() disagree: " - + si.isEnabled() + " vs " + si.getDisabledReason()); - } - if ((si.getDisabledReason() == ShortcutInfo.DISABLED_REASON_VERSION_LOWER) - && (getPackageInfo().getBackupSourceVersionCode() - == ShortcutInfo.VERSION_CODE_UNKNOWN)) { - failed = true; - Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId() - + " RESTORED_VERSION_LOWER with no backup source version code."); - } if (s.isDummyMainActivity(si.getActivity())) { failed = true; Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId() diff --git a/com/android/server/pm/ShortcutPackageInfo.java b/com/android/server/pm/ShortcutPackageInfo.java index 3a9bbc89..e5a2f5ac 100644 --- a/com/android/server/pm/ShortcutPackageInfo.java +++ b/com/android/server/pm/ShortcutPackageInfo.java @@ -18,7 +18,6 @@ package com.android.server.pm; import android.annotation.NonNull; import android.annotation.UserIdInt; import android.content.pm.PackageInfo; -import android.content.pm.ShortcutInfo; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; @@ -46,45 +45,32 @@ class ShortcutPackageInfo { static final String TAG_ROOT = "package-info"; private static final String ATTR_VERSION = "version"; private static final String ATTR_LAST_UPDATE_TIME = "last_udpate_time"; - private static final String ATTR_BACKUP_SOURCE_VERSION = "bk_src_version"; - private static final String ATTR_BACKUP_ALLOWED = "allow-backup"; - private static final String ATTR_BACKUP_SOURCE_BACKUP_ALLOWED = "bk_src_backup-allowed"; private static final String ATTR_SHADOW = "shadow"; private static final String TAG_SIGNATURE = "signature"; private static final String ATTR_SIGNATURE_HASH = "hash"; + private static final int VERSION_UNKNOWN = -1; + /** * When true, this package information was restored from the previous device, and the app hasn't * been installed yet. */ private boolean mIsShadow; - private int mVersionCode = ShortcutInfo.VERSION_CODE_UNKNOWN; - private int mBackupSourceVersionCode = ShortcutInfo.VERSION_CODE_UNKNOWN; + private int mVersionCode = VERSION_UNKNOWN; private long mLastUpdateTime; private ArrayList<byte[]> mSigHashes; - // mBackupAllowed didn't used to be parsisted, so we don't restore it from a file. - // mBackupAllowed will always start with false, and will have been updated before making a - // backup next time, which works file. - // We just don't want to print an uninitialzied mBackupAlldowed value on dumpsys, so - // we use this boolean to control dumpsys. - private boolean mBackupAllowedInitialized; - private boolean mBackupAllowed; - private boolean mBackupSourceBackupAllowed; - private ShortcutPackageInfo(int versionCode, long lastUpdateTime, ArrayList<byte[]> sigHashes, boolean isShadow) { mVersionCode = versionCode; mLastUpdateTime = lastUpdateTime; mIsShadow = isShadow; mSigHashes = sigHashes; - mBackupAllowed = false; // By default, we assume false. - mBackupSourceBackupAllowed = false; } public static ShortcutPackageInfo newEmpty() { - return new ShortcutPackageInfo(ShortcutInfo.VERSION_CODE_UNKNOWN, /* last update time =*/ 0, + return new ShortcutPackageInfo(VERSION_UNKNOWN, /* last update time =*/ 0, new ArrayList<>(0), /* isShadow */ false); } @@ -100,33 +86,15 @@ class ShortcutPackageInfo { return mVersionCode; } - public int getBackupSourceVersionCode() { - return mBackupSourceVersionCode; - } - - @VisibleForTesting - public boolean isBackupSourceBackupAllowed() { - return mBackupSourceBackupAllowed; - } - public long getLastUpdateTime() { return mLastUpdateTime; } - public boolean isBackupAllowed() { - return mBackupAllowed; - } - - /** - * Set {@link #mVersionCode}, {@link #mLastUpdateTime} and {@link #mBackupAllowed} - * from a {@link PackageInfo}. - */ - public void updateFromPackageInfo(@NonNull PackageInfo pi) { + /** Set {@link #mVersionCode} and {@link #mLastUpdateTime} from a {@link PackageInfo}. */ + public void updateVersionInfo(@NonNull PackageInfo pi) { if (pi != null) { mVersionCode = pi.versionCode; mLastUpdateTime = pi.lastUpdateTime; - mBackupAllowed = ShortcutService.shouldBackupApp(pi); - mBackupAllowedInitialized = true; } } @@ -134,24 +102,23 @@ class ShortcutPackageInfo { return mSigHashes.size() > 0; } - //@DisabledReason - public int canRestoreTo(ShortcutService s, PackageInfo currentPackage, boolean anyVersionOkay) { - if (!BackupUtils.signaturesMatch(mSigHashes, currentPackage)) { - Slog.w(TAG, "Can't restore: Package signature mismatch"); - return ShortcutInfo.DISABLED_REASON_SIGNATURE_MISMATCH; - } - if (!ShortcutService.shouldBackupApp(currentPackage) || !mBackupSourceBackupAllowed) { + public boolean canRestoreTo(ShortcutService s, PackageInfo target) { + if (!s.shouldBackupApp(target)) { // "allowBackup" was true when backed up, but now false. - Slog.w(TAG, "Can't restore: package didn't or doesn't allow backup"); - return ShortcutInfo.DISABLED_REASON_BACKUP_NOT_SUPPORTED; + Slog.w(TAG, "Can't restore: package no longer allows backup"); + return false; } - if (!anyVersionOkay && (currentPackage.versionCode < mBackupSourceVersionCode)) { + if (target.versionCode < mVersionCode) { Slog.w(TAG, String.format( "Can't restore: package current version %d < backed up version %d", - currentPackage.versionCode, mBackupSourceVersionCode)); - return ShortcutInfo.DISABLED_REASON_VERSION_LOWER; + target.versionCode, mVersionCode)); + return false; + } + if (!BackupUtils.signaturesMatch(mSigHashes, target)) { + Slog.w(TAG, "Can't restore: Package signature mismatch"); + return false; } - return ShortcutInfo.DISABLED_REASON_NOT_DISABLED; + return true; } @VisibleForTesting @@ -165,8 +132,6 @@ class ShortcutPackageInfo { final ShortcutPackageInfo ret = new ShortcutPackageInfo(pi.versionCode, pi.lastUpdateTime, BackupUtils.hashSignatureArray(pi.signatures), /* shadow=*/ false); - ret.mBackupSourceBackupAllowed = s.shouldBackupApp(pi); - ret.mBackupSourceVersionCode = pi.versionCode; return ret; } @@ -186,19 +151,13 @@ class ShortcutPackageInfo { mSigHashes = BackupUtils.hashSignatureArray(pi.signatures); } - public void saveToXml(XmlSerializer out, boolean forBackup) throws IOException { + public void saveToXml(XmlSerializer out) throws IOException { out.startTag(null, TAG_ROOT); ShortcutService.writeAttr(out, ATTR_VERSION, mVersionCode); ShortcutService.writeAttr(out, ATTR_LAST_UPDATE_TIME, mLastUpdateTime); ShortcutService.writeAttr(out, ATTR_SHADOW, mIsShadow); - ShortcutService.writeAttr(out, ATTR_BACKUP_ALLOWED, mBackupAllowed); - - ShortcutService.writeAttr(out, ATTR_BACKUP_SOURCE_VERSION, mBackupSourceVersionCode); - ShortcutService.writeAttr(out, - ATTR_BACKUP_SOURCE_BACKUP_ALLOWED, mBackupSourceBackupAllowed); - for (int i = 0; i < mSigHashes.size(); i++) { out.startTag(null, TAG_SIGNATURE); @@ -212,9 +171,7 @@ class ShortcutPackageInfo { public void loadFromXml(XmlPullParser parser, boolean fromBackup) throws IOException, XmlPullParserException { - // Don't use the version code from the backup file. - final int versionCode = ShortcutService.parseIntAttribute(parser, ATTR_VERSION, - ShortcutInfo.VERSION_CODE_UNKNOWN); + final int versionCode = ShortcutService.parseIntAttribute(parser, ATTR_VERSION); final long lastUpdateTime = ShortcutService.parseLongAttribute( parser, ATTR_LAST_UPDATE_TIME); @@ -223,20 +180,6 @@ class ShortcutPackageInfo { final boolean shadow = fromBackup || ShortcutService.parseBooleanAttribute(parser, ATTR_SHADOW); - // We didn't used to save these attributes, and all backed up shortcuts were from - // apps that support backups, so the default values take this fact into consideration. - final int backupSourceVersion = ShortcutService.parseIntAttribute(parser, - ATTR_BACKUP_SOURCE_VERSION, ShortcutInfo.VERSION_CODE_UNKNOWN); - - // Note the only time these "true" default value is used is when restoring from an old - // build that didn't save ATTR_BACKUP_ALLOWED, and that means all the data included in - // a backup file were from apps that support backup, so we can just use "true" as the - // default. - final boolean backupAllowed = ShortcutService.parseBooleanAttribute( - parser, ATTR_BACKUP_ALLOWED, true); - final boolean backupSourceBackupAllowed = ShortcutService.parseBooleanAttribute( - parser, ATTR_BACKUP_SOURCE_BACKUP_ALLOWED, true); - final ArrayList<byte[]> hashes = new ArrayList<>(); final int outerDepth = parser.getDepth(); @@ -264,28 +207,11 @@ class ShortcutPackageInfo { ShortcutService.warnForInvalidTag(depth, tag); } - // Successfully loaded; replace the fields. - if (fromBackup) { - mVersionCode = ShortcutInfo.VERSION_CODE_UNKNOWN; - mBackupSourceVersionCode = versionCode; - mBackupSourceBackupAllowed = backupAllowed; - } else { - mVersionCode = versionCode; - mBackupSourceVersionCode = backupSourceVersion; - mBackupSourceBackupAllowed = backupSourceBackupAllowed; - } + // Successfully loaded; replace the feilds. + mVersionCode = versionCode; mLastUpdateTime = lastUpdateTime; mIsShadow = shadow; mSigHashes = hashes; - - // Note we don't restore it from the file because it didn't used to be saved. - // We always start by assuming backup is disabled for the current package, - // and this field will have been updated before we actually create a backup, at the same - // time when we update the version code. - // Until then, the value of mBackupAllowed shouldn't matter, but we don't want to print - // a false flag on dumpsys, so set mBackupAllowedInitialized to false. - mBackupAllowed = false; - mBackupAllowedInitialized = false; } public void dump(PrintWriter pw, String prefix) { @@ -297,7 +223,6 @@ class ShortcutPackageInfo { pw.print(prefix); pw.print(" IsShadow: "); pw.print(mIsShadow); - pw.print(mIsShadow ? " (not installed)" : " (installed)"); pw.println(); pw.print(prefix); @@ -305,25 +230,6 @@ class ShortcutPackageInfo { pw.print(mVersionCode); pw.println(); - if (mBackupAllowedInitialized) { - pw.print(prefix); - pw.print(" Backup Allowed: "); - pw.print(mBackupAllowed); - pw.println(); - } - - if (mBackupSourceVersionCode != ShortcutInfo.VERSION_CODE_UNKNOWN) { - pw.print(prefix); - pw.print(" Backup source version: "); - pw.print(mBackupSourceVersionCode); - pw.println(); - - pw.print(prefix); - pw.print(" Backup source backup allowed: "); - pw.print(mBackupSourceBackupAllowed); - pw.println(); - } - pw.print(prefix); pw.print(" Last package update time: "); pw.print(mLastUpdateTime); diff --git a/com/android/server/pm/ShortcutPackageItem.java b/com/android/server/pm/ShortcutPackageItem.java index 689099cf..e59d69f4 100644 --- a/com/android/server/pm/ShortcutPackageItem.java +++ b/com/android/server/pm/ShortcutPackageItem.java @@ -17,7 +17,6 @@ package com.android.server.pm; import android.annotation.NonNull; import android.content.pm.PackageInfo; -import android.content.pm.ShortcutInfo; import android.util.Slog; import com.android.internal.util.Preconditions; @@ -102,42 +101,51 @@ abstract class ShortcutPackageItem { final ShortcutService s = mShortcutUser.mService; if (!s.isPackageInstalled(mPackageName, mPackageUserId)) { if (ShortcutService.DEBUG) { - Slog.d(TAG, String.format("Package still not installed: %s/u%d", + Slog.d(TAG, String.format("Package still not installed: %s user=%d", mPackageName, mPackageUserId)); } return; // Not installed, no need to restore yet. } - int restoreBlockReason; - int currentVersionCode = ShortcutInfo.VERSION_CODE_UNKNOWN; - + boolean blockRestore = false; if (!mPackageInfo.hasSignatures()) { - s.wtf("Attempted to restore package " + mPackageName + "/u" + mPackageUserId + s.wtf("Attempted to restore package " + mPackageName + ", user=" + mPackageUserId + " but signatures not found in the restore data."); - restoreBlockReason = ShortcutInfo.DISABLED_REASON_SIGNATURE_MISMATCH; - } else { + blockRestore = true; + } + if (!blockRestore) { final PackageInfo pi = s.getPackageInfoWithSignatures(mPackageName, mPackageUserId); - currentVersionCode = pi.versionCode; - restoreBlockReason = mPackageInfo.canRestoreTo(s, pi, canRestoreAnyVersion()); + if (!mPackageInfo.canRestoreTo(s, pi)) { + // Package is now installed, but can't restore. Let the subclass do the cleanup. + blockRestore = true; + } } + if (blockRestore) { + onRestoreBlocked(); + } else { + if (ShortcutService.DEBUG) { + Slog.d(TAG, String.format("Restored package: %s/%d on user %d", mPackageName, + mPackageUserId, getOwnerUserId())); + } - if (ShortcutService.DEBUG) { - Slog.d(TAG, String.format("Restoring package: %s/u%d (version=%d) %s for u%d", - mPackageName, mPackageUserId, currentVersionCode, - ShortcutInfo.getDisabledReasonDebugString(restoreBlockReason), - getOwnerUserId())); + onRestored(); } - onRestored(restoreBlockReason); - // Either way, it's no longer a shadow. mPackageInfo.setShadow(false); s.scheduleSaveUser(mPackageUserId); } - protected abstract boolean canRestoreAnyVersion(); + /** + * Called when the new package can't be restored because it has a lower version number + * or different signatures. + */ + protected abstract void onRestoreBlocked(); - protected abstract void onRestored(int restoreBlockReason); + /** + * Called when the new package is successfully restored. + */ + protected abstract void onRestored(); public abstract void saveToXml(@NonNull XmlSerializer out, boolean forBackup) throws IOException, XmlPullParserException; diff --git a/com/android/server/pm/ShortcutParser.java b/com/android/server/pm/ShortcutParser.java index 866c46c6..3cf4200b 100644 --- a/com/android/server/pm/ShortcutParser.java +++ b/com/android/server/pm/ShortcutParser.java @@ -337,9 +337,6 @@ public class ShortcutParser { (enabled ? ShortcutInfo.FLAG_MANIFEST : ShortcutInfo.FLAG_DISABLED) | ShortcutInfo.FLAG_IMMUTABLE | ((iconResId != 0) ? ShortcutInfo.FLAG_HAS_ICON_RES : 0); - final int disabledReason = - enabled ? ShortcutInfo.DISABLED_REASON_NOT_DISABLED - : ShortcutInfo.DISABLED_REASON_BY_APP; // Note we don't need to set resource names here yet. They'll be set when they're about // to be published. @@ -366,7 +363,6 @@ public class ShortcutParser { flags, iconResId, null, // icon res name - null, // bitmap path - disabledReason); + null); // bitmap path } } diff --git a/com/android/server/pm/ShortcutRequestPinProcessor.java b/com/android/server/pm/ShortcutRequestPinProcessor.java index 3e44de98..8a8128db 100644 --- a/com/android/server/pm/ShortcutRequestPinProcessor.java +++ b/com/android/server/pm/ShortcutRequestPinProcessor.java @@ -300,12 +300,10 @@ class ShortcutRequestPinProcessor { final ShortcutInfo existing = ps.findShortcutById(inShortcut.getId()); final boolean existsAlready = existing != null; - final boolean existingIsVisible = existsAlready && existing.isVisibleToPublisher(); if (DEBUG) { Slog.d(TAG, "requestPinnedShortcut: package=" + inShortcut.getPackage() + " existsAlready=" + existsAlready - + " existingIsVisible=" + existingIsVisible + " shortcut=" + inShortcut.toInsecureString()); } @@ -380,6 +378,7 @@ class ShortcutRequestPinProcessor { // manifest shortcut.) Preconditions.checkArgument(shortcutInfo.isEnabled(), "Shortcut ID=" + shortcutInfo + " already exists but disabled."); + } private boolean startRequestConfirmActivity(ComponentName activity, int launcherUserId, @@ -464,7 +463,7 @@ class ShortcutRequestPinProcessor { launcher.attemptToRestoreIfNeededAndSave(); if (launcher.hasPinned(original)) { if (DEBUG) { - Slog.d(TAG, "Shortcut " + original + " already pinned."); // This too. + Slog.d(TAG, "Shortcut " + original + " already pinned."); } return true; } @@ -498,7 +497,7 @@ class ShortcutRequestPinProcessor { if (original.getActivity() == null) { original.setActivity(mService.getDummyMainActivity(appPackageName)); } - ps.addOrReplaceDynamicShortcut(original); + ps.addOrUpdateDynamicShortcut(original); } // Pin the shortcut. @@ -506,14 +505,13 @@ class ShortcutRequestPinProcessor { Slog.d(TAG, "Pinning " + shortcutId); } - launcher.addPinnedShortcut(appPackageName, appUserId, shortcutId, - /*forPinRequest=*/ true); + launcher.addPinnedShortcut(appPackageName, appUserId, shortcutId); if (current == null) { if (DEBUG) { Slog.d(TAG, "Removing " + shortcutId + " as dynamic"); } - ps.deleteDynamicWithId(shortcutId, /*ignoreInvisible=*/ false); + ps.deleteDynamicWithId(shortcutId); } ps.adjustRanks(); // Shouldn't be needed, but just in case. diff --git a/com/android/server/pm/ShortcutService.java b/com/android/server/pm/ShortcutService.java index 1c002aa4..27560c5f 100644 --- a/com/android/server/pm/ShortcutService.java +++ b/com/android/server/pm/ShortcutService.java @@ -553,9 +553,6 @@ public class ShortcutService extends IShortcutService.Stub { public Lifecycle(Context context) { super(context); - if (DEBUG) { - Binder.LOG_RUNTIME_EXCEPTION = true; - } mService = new ShortcutService(context); } @@ -741,10 +738,6 @@ public class ShortcutService extends IShortcutService.Stub { return parseLongAttribute(parser, attribute) == 1; } - static boolean parseBooleanAttribute(XmlPullParser parser, String attribute, boolean def) { - return parseLongAttribute(parser, attribute, (def ? 1 : 0)) == 1; - } - static int parseIntAttribute(XmlPullParser parser, String attribute) { return (int) parseLongAttribute(parser, attribute); } @@ -842,8 +835,6 @@ public class ShortcutService extends IShortcutService.Stub { static void writeAttr(XmlSerializer out, String name, boolean value) throws IOException { if (value) { writeAttr(out, name, "1"); - } else { - writeAttr(out, name, "0"); } } @@ -1698,7 +1689,7 @@ public class ShortcutService extends IShortcutService.Stub { final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId); - ps.ensureImmutableShortcutsNotIncluded(newShortcuts, /*ignoreInvisible=*/ true); + ps.ensureImmutableShortcutsNotIncluded(newShortcuts); fillInDefaultActivity(newShortcuts); @@ -1718,12 +1709,12 @@ public class ShortcutService extends IShortcutService.Stub { } // First, remove all un-pinned; dynamic shortcuts - ps.deleteAllDynamicShortcuts(/*ignoreInvisible=*/ true); + ps.deleteAllDynamicShortcuts(); // Then, add/update all. We need to make sure to take over "pinned" flag. for (int i = 0; i < size; i++) { final ShortcutInfo newShortcut = newShortcuts.get(i); - ps.addOrReplaceDynamicShortcut(newShortcut); + ps.addOrUpdateDynamicShortcut(newShortcut); } // Lastly, adjust the ranks. @@ -1749,7 +1740,7 @@ public class ShortcutService extends IShortcutService.Stub { final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId); - ps.ensureImmutableShortcutsNotIncluded(newShortcuts, /*ignoreInvisible=*/ true); + ps.ensureImmutableShortcutsNotIncluded(newShortcuts); // For update, don't fill in the default activity. Having null activity means // "don't update the activity" here. @@ -1770,9 +1761,7 @@ public class ShortcutService extends IShortcutService.Stub { fixUpIncomingShortcutInfo(source, /* forUpdate= */ true); final ShortcutInfo target = ps.findShortcutById(source.getId()); - - // Invisible shortcuts can't be updated. - if (target == null || !target.isVisibleToPublisher()) { + if (target == null) { continue; } @@ -1819,7 +1808,7 @@ public class ShortcutService extends IShortcutService.Stub { } @Override - public boolean addDynamicShortcuts(String packageName, ParceledListSlice shortcutInfoList, + public boolean addDynamicShortcuts(String packageName, ParceledListSlice shortcutInfoList, @UserIdInt int userId) { verifyCaller(packageName, userId); @@ -1831,7 +1820,7 @@ public class ShortcutService extends IShortcutService.Stub { final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId); - ps.ensureImmutableShortcutsNotIncluded(newShortcuts, /*ignoreInvisible=*/ true); + ps.ensureImmutableShortcutsNotIncluded(newShortcuts); fillInDefaultActivity(newShortcuts); @@ -1856,7 +1845,7 @@ public class ShortcutService extends IShortcutService.Stub { newShortcut.setRankChanged(); // Add it. - ps.addOrReplaceDynamicShortcut(newShortcut); + ps.addOrUpdateDynamicShortcut(newShortcut); } // Lastly, adjust the ranks. @@ -1912,22 +1901,6 @@ public class ShortcutService extends IShortcutService.Stub { Preconditions.checkState(isUidForegroundLocked(injectBinderCallingUid()), "Calling application must have a foreground activity or a foreground service"); - // If it's a pin shortcut request, and there's already a shortcut with the same ID - // that's not visible to the caller (i.e. restore-blocked; meaning it's pinned by - // someone already), then we just replace the existing one with this new one, - // and then proceed the rest of the process. - if (shortcut != null) { - final ShortcutPackage ps = getPackageShortcutsForPublisherLocked( - packageName, userId); - final String id = shortcut.getId(); - if (ps.isShortcutExistsAndInvisibleToPublisher(id)) { - - ps.updateInvisibleShortcutForPinRequestWith(shortcut); - - packageShortcutsChanged(packageName, userId); - } - } - // Send request to the launcher, if supported. ret = mShortcutRequestPinProcessor.requestPinItemLocked(shortcut, appWidget, extras, userId, resultIntent); @@ -1949,21 +1922,15 @@ public class ShortcutService extends IShortcutService.Stub { final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId); - ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds, - /*ignoreInvisible=*/ true); + ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds); final String disabledMessageString = (disabledMessage == null) ? null : disabledMessage.toString(); for (int i = shortcutIds.size() - 1; i >= 0; i--) { - final String id = Preconditions.checkStringNotEmpty((String) shortcutIds.get(i)); - if (!ps.isShortcutExistsAndVisibleToPublisher(id)) { - continue; - } - ps.disableWithId(id, + ps.disableWithId(Preconditions.checkStringNotEmpty((String) shortcutIds.get(i)), disabledMessageString, disabledMessageResId, - /* overrideImmutable=*/ false, /*ignoreInvisible=*/ true, - ShortcutInfo.DISABLED_REASON_BY_APP); + /* overrideImmutable=*/ false); } // We may have removed dynamic shortcuts which may have left a gap, so adjust the ranks. @@ -1984,15 +1951,10 @@ public class ShortcutService extends IShortcutService.Stub { final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId); - ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds, - /*ignoreInvisible=*/ true); + ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds); for (int i = shortcutIds.size() - 1; i >= 0; i--) { - final String id = Preconditions.checkStringNotEmpty((String) shortcutIds.get(i)); - if (!ps.isShortcutExistsAndVisibleToPublisher(id)) { - continue; - } - ps.enableWithId(id); + ps.enableWithId((String) shortcutIds.get(i)); } } packageShortcutsChanged(packageName, userId); @@ -2011,15 +1973,11 @@ public class ShortcutService extends IShortcutService.Stub { final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId); - ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds, - /*ignoreInvisible=*/ true); + ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds); for (int i = shortcutIds.size() - 1; i >= 0; i--) { - final String id = Preconditions.checkStringNotEmpty((String) shortcutIds.get(i)); - if (!ps.isShortcutExistsAndVisibleToPublisher(id)) { - continue; - } - ps.deleteDynamicWithId(id, /*ignoreInvisible=*/ true); + ps.deleteDynamicWithId( + Preconditions.checkStringNotEmpty((String) shortcutIds.get(i))); } // We may have removed dynamic shortcuts which may have left a gap, so adjust the ranks. @@ -2038,7 +1996,7 @@ public class ShortcutService extends IShortcutService.Stub { throwIfUserLockedL(userId); final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId); - ps.deleteAllDynamicShortcuts(/*ignoreInvisible=*/ true); + ps.deleteAllDynamicShortcuts(); } packageShortcutsChanged(packageName, userId); @@ -2055,7 +2013,7 @@ public class ShortcutService extends IShortcutService.Stub { return getShortcutsWithQueryLocked( packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR, - ShortcutInfo::isDynamicVisible); + ShortcutInfo::isDynamic); } } @@ -2069,7 +2027,7 @@ public class ShortcutService extends IShortcutService.Stub { return getShortcutsWithQueryLocked( packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR, - ShortcutInfo::isManifestVisible); + ShortcutInfo::isManifestShortcut); } } @@ -2083,7 +2041,7 @@ public class ShortcutService extends IShortcutService.Stub { return getShortcutsWithQueryLocked( packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR, - ShortcutInfo::isPinnedVisible); + ShortcutInfo::isPinned); } } @@ -2232,11 +2190,7 @@ public class ShortcutService extends IShortcutService.Stub { } // We override this method in unit tests to do a simpler check. - boolean hasShortcutHostPermission(@NonNull String callingPackage, int userId, - int callingPid, int callingUid) { - if (injectCheckAccessShortcutsPermission(callingPid, callingUid)) { - return true; - } + boolean hasShortcutHostPermission(@NonNull String callingPackage, int userId) { final long start = injectElapsedRealtime(); try { return hasShortcutHostPermissionInner(callingPackage, userId); @@ -2245,14 +2199,6 @@ public class ShortcutService extends IShortcutService.Stub { } } - /** - * Returns true if the caller has the "ACCESS_SHORTCUTS" permission. - */ - boolean injectCheckAccessShortcutsPermission(int callingPid, int callingUid) { - return mContext.checkPermission(android.Manifest.permission.ACCESS_SHORTCUTS, - callingPid, callingUid) == PackageManager.PERMISSION_GRANTED; - } - // This method is extracted so we can directly call this method from unit tests, // even when hasShortcutPermission() is overridden. @VisibleForTesting @@ -2433,7 +2379,7 @@ public class ShortcutService extends IShortcutService.Stub { @NonNull String callingPackage, long changedSince, @Nullable String packageName, @Nullable List<String> shortcutIds, @Nullable ComponentName componentName, - int queryFlags, int userId, int callingPid, int callingUid) { + int queryFlags, int userId) { final ArrayList<ShortcutInfo> ret = new ArrayList<>(); final boolean cloneKeyFieldOnly = @@ -2454,15 +2400,13 @@ public class ShortcutService extends IShortcutService.Stub { if (packageName != null) { getShortcutsInnerLocked(launcherUserId, callingPackage, packageName, shortcutIds, changedSince, - componentName, queryFlags, userId, ret, cloneFlag, - callingPid, callingUid); + componentName, queryFlags, userId, ret, cloneFlag); } else { final List<String> shortcutIdsF = shortcutIds; getUserShortcutsLocked(userId).forAllPackages(p -> { getShortcutsInnerLocked(launcherUserId, callingPackage, p.getPackageName(), shortcutIdsF, changedSince, - componentName, queryFlags, userId, ret, cloneFlag, - callingPid, callingUid); + componentName, queryFlags, userId, ret, cloneFlag); }); } } @@ -2472,8 +2416,7 @@ public class ShortcutService extends IShortcutService.Stub { private void getShortcutsInnerLocked(int launcherUserId, @NonNull String callingPackage, @Nullable String packageName, @Nullable List<String> shortcutIds, long changedSince, @Nullable ComponentName componentName, int queryFlags, - int userId, ArrayList<ShortcutInfo> ret, int cloneFlag, - int callingPid, int callingUid) { + int userId, ArrayList<ShortcutInfo> ret, int cloneFlag) { final ArraySet<String> ids = shortcutIds == null ? null : new ArraySet<>(shortcutIds); @@ -2482,13 +2425,6 @@ public class ShortcutService extends IShortcutService.Stub { if (p == null) { return; // No need to instantiate ShortcutPackage. } - final boolean matchDynamic = (queryFlags & ShortcutQuery.FLAG_MATCH_DYNAMIC) != 0; - final boolean matchPinned = (queryFlags & ShortcutQuery.FLAG_MATCH_PINNED) != 0; - final boolean matchManifest = (queryFlags & ShortcutQuery.FLAG_MATCH_MANIFEST) != 0; - - final boolean getPinnedByAnyLauncher = - ((queryFlags & ShortcutQuery.FLAG_MATCH_ALL_PINNED) != 0) - && injectCheckAccessShortcutsPermission(callingPid, callingUid); p.findAll(ret, (ShortcutInfo si) -> { @@ -2504,17 +2440,20 @@ public class ShortcutService extends IShortcutService.Stub { return false; } } - if (matchDynamic && si.isDynamic()) { + if (((queryFlags & ShortcutQuery.FLAG_GET_DYNAMIC) != 0) + && si.isDynamic()) { return true; } - if ((matchPinned && si.isPinned()) || getPinnedByAnyLauncher) { + if (((queryFlags & ShortcutQuery.FLAG_GET_PINNED) != 0) + && si.isPinned()) { return true; } - if (matchManifest && si.isDeclaredInManifest()) { + if (((queryFlags & ShortcutQuery.FLAG_GET_MANIFEST) != 0) + && si.isManifestShortcut()) { return true; } return false; - }, cloneFlag, callingPackage, launcherUserId, getPinnedByAnyLauncher); + }, cloneFlag, callingPackage, launcherUserId); } @Override @@ -2531,16 +2470,14 @@ public class ShortcutService extends IShortcutService.Stub { .attemptToRestoreIfNeededAndSave(); final ShortcutInfo si = getShortcutInfoLocked( - launcherUserId, callingPackage, packageName, shortcutId, userId, - /*getPinnedByAnyLauncher=*/ false); + launcherUserId, callingPackage, packageName, shortcutId, userId); return si != null && si.isPinned(); } } private ShortcutInfo getShortcutInfoLocked( int launcherUserId, @NonNull String callingPackage, - @NonNull String packageName, @NonNull String shortcutId, int userId, - boolean getPinnedByAnyLauncher) { + @NonNull String packageName, @NonNull String shortcutId, int userId) { Preconditions.checkStringNotEmpty(packageName, "packageName"); Preconditions.checkStringNotEmpty(shortcutId, "shortcutId"); @@ -2556,7 +2493,7 @@ public class ShortcutService extends IShortcutService.Stub { final ArrayList<ShortcutInfo> list = new ArrayList<>(1); p.findAll(list, (ShortcutInfo si) -> shortcutId.equals(si.getId()), - /* clone flags=*/ 0, callingPackage, launcherUserId, getPinnedByAnyLauncher); + /* clone flags=*/ 0, callingPackage, launcherUserId); return list.size() == 0 ? null : list.get(0); } @@ -2576,7 +2513,7 @@ public class ShortcutService extends IShortcutService.Stub { getLauncherShortcutsLocked(callingPackage, userId, launcherUserId); launcher.attemptToRestoreIfNeededAndSave(); - launcher.pinShortcuts(userId, packageName, shortcutIds, /*forPinRequest=*/ false); + launcher.pinShortcuts(userId, packageName, shortcutIds); } packageShortcutsChanged(packageName, userId); @@ -2586,8 +2523,7 @@ public class ShortcutService extends IShortcutService.Stub { @Override public Intent[] createShortcutIntents(int launcherUserId, @NonNull String callingPackage, - @NonNull String packageName, @NonNull String shortcutId, int userId, - int callingPid, int callingUid) { + @NonNull String packageName, @NonNull String shortcutId, int userId) { // Calling permission must be checked by LauncherAppsImpl. Preconditions.checkStringNotEmpty(packageName, "packageName can't be empty"); Preconditions.checkStringNotEmpty(shortcutId, "shortcutId can't be empty"); @@ -2599,13 +2535,9 @@ public class ShortcutService extends IShortcutService.Stub { getLauncherShortcutsLocked(callingPackage, userId, launcherUserId) .attemptToRestoreIfNeededAndSave(); - final boolean getPinnedByAnyLauncher = - injectCheckAccessShortcutsPermission(callingPid, callingUid); - // Make sure the shortcut is actually visible to the launcher. final ShortcutInfo si = getShortcutInfoLocked( - launcherUserId, callingPackage, packageName, shortcutId, userId, - getPinnedByAnyLauncher); + launcherUserId, callingPackage, packageName, shortcutId, userId); // "si == null" should suffice here, but check the flags too just to make sure. if (si == null || !si.isEnabled() || !si.isAlive()) { Log.e(TAG, "Shortcut " + shortcutId + " does not exist or disabled"); @@ -2691,9 +2623,8 @@ public class ShortcutService extends IShortcutService.Stub { @Override public boolean hasShortcutHostPermission(int launcherUserId, - @NonNull String callingPackage, int callingPid, int callingUid) { - return ShortcutService.this.hasShortcutHostPermission(callingPackage, launcherUserId, - callingPid, callingUid); + @NonNull String callingPackage) { + return ShortcutService.this.hasShortcutHostPermission(callingPackage, launcherUserId); } @Override @@ -3412,7 +3343,7 @@ public class ShortcutService extends IShortcutService.Stub { return isApplicationFlagSet(packageName, userId, ApplicationInfo.FLAG_ALLOW_BACKUP); } - static boolean shouldBackupApp(PackageInfo pi) { + boolean shouldBackupApp(PackageInfo pi) { return (pi.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0; } @@ -3440,7 +3371,7 @@ public class ShortcutService extends IShortcutService.Stub { // Set the version code for the launchers. // We shouldn't do this for publisher packages, because we don't want to update the // version code without rescanning the manifest. - user.forAllLaunchers(launcher -> launcher.ensurePackageInfo()); + user.forAllLaunchers(launcher -> launcher.ensureVersionInfo()); // Save to the filesystem. scheduleSaveUser(userId); diff --git a/com/android/server/pm/ShortcutUser.java b/com/android/server/pm/ShortcutUser.java index 48eccd02..55e6d28a 100644 --- a/com/android/server/pm/ShortcutUser.java +++ b/com/android/server/pm/ShortcutUser.java @@ -364,6 +364,9 @@ class ShortcutUser { private void saveShortcutPackageItem(XmlSerializer out, ShortcutPackageItem spi, boolean forBackup) throws IOException, XmlPullParserException { if (forBackup) { + if (!mService.shouldBackupApp(spi.getPackageName(), spi.getPackageUserId())) { + return; // Don't save. + } if (spi.getPackageUserId() != spi.getOwnerUserId()) { return; // Don't save cross-user information. } diff --git a/com/android/server/pm/UserRestrictionsUtils.java b/com/android/server/pm/UserRestrictionsUtils.java index c18a71d3..a6b05d71 100644 --- a/com/android/server/pm/UserRestrictionsUtils.java +++ b/com/android/server/pm/UserRestrictionsUtils.java @@ -96,7 +96,6 @@ public class UserRestrictionsUtils { UserManager.DISALLOW_SMS, UserManager.DISALLOW_FUN, UserManager.DISALLOW_CREATE_WINDOWS, - UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS, UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE, UserManager.DISALLOW_OUTGOING_BEAM, UserManager.DISALLOW_WALLPAPER, @@ -157,7 +156,6 @@ public class UserRestrictionsUtils { private static final Set<String> GLOBAL_RESTRICTIONS = Sets.newArraySet( UserManager.DISALLOW_ADJUST_VOLUME, UserManager.DISALLOW_BLUETOOTH_SHARING, - UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS, UserManager.DISALLOW_RUN_IN_BACKGROUND, UserManager.DISALLOW_UNMUTE_MICROPHONE, UserManager.DISALLOW_UNMUTE_DEVICE diff --git a/com/android/server/pm/permission/BasePermission.java b/com/android/server/pm/permission/BasePermission.java index 71d3202d..09a6e9c0 100644 --- a/com/android/server/pm/permission/BasePermission.java +++ b/com/android/server/pm/permission/BasePermission.java @@ -48,7 +48,6 @@ import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; -import java.util.Collection; import java.util.Map; import java.util.Objects; import java.util.Set; @@ -78,7 +77,7 @@ public final class BasePermission { final String name; - final @PermissionType int type; + @PermissionType final int type; String sourcePackageName; @@ -253,12 +252,12 @@ public final class BasePermission { return changed; } - public void updateDynamicPermission(Collection<BasePermission> permissionTrees) { + public void updateDynamicPermission(Map<String, BasePermission> permissionTrees) { if (PackageManagerService.DEBUG_SETTINGS) Log.v(TAG, "Dynamic permission: name=" + getName() + " pkg=" + getSourcePackageName() + " info=" + pendingPermissionInfo); if (sourcePackageSetting == null && pendingPermissionInfo != null) { - final BasePermission tree = findPermissionTree(permissionTrees, name); + final BasePermission tree = findPermissionTreeLP(permissionTrees, name); if (tree != null && tree.perm != null) { sourcePackageSetting = tree.sourcePackageSetting; perm = new PackageParser.Permission(tree.perm.owner, @@ -270,8 +269,8 @@ public final class BasePermission { } } - static BasePermission createOrUpdate(@Nullable BasePermission bp, @NonNull Permission p, - @NonNull PackageParser.Package pkg, Collection<BasePermission> permissionTrees, + public static BasePermission createOrUpdate(@Nullable BasePermission bp, @NonNull Permission p, + @NonNull PackageParser.Package pkg, Map<String, BasePermission> permissionTrees, boolean chatty) { final PackageSettingBase pkgSetting = (PackageSettingBase) pkg.mExtras; // Allow system apps to redefine non-system permissions @@ -301,7 +300,7 @@ public final class BasePermission { if (bp.perm == null) { if (bp.sourcePackageName == null || bp.sourcePackageName.equals(p.info.packageName)) { - final BasePermission tree = findPermissionTree(permissionTrees, p.info.name); + final BasePermission tree = findPermissionTreeLP(permissionTrees, p.info.name); if (tree == null || tree.sourcePackageName.equals(p.info.packageName)) { bp.sourcePackageSetting = pkgSetting; @@ -346,12 +345,12 @@ public final class BasePermission { return bp; } - static BasePermission enforcePermissionTree( - Collection<BasePermission> permissionTrees, String permName, int callingUid) { + public static BasePermission enforcePermissionTreeLP( + Map<String, BasePermission> permissionTrees, String permName, int callingUid) { if (permName != null) { - BasePermission bp = findPermissionTree(permissionTrees, permName); + BasePermission bp = findPermissionTreeLP(permissionTrees, permName); if (bp != null) { - if (bp.uid == UserHandle.getAppId(callingUid)) { + if (bp.uid == UserHandle.getAppId(callingUid)) {//UserHandle.getAppId(Binder.getCallingUid())) { return bp; } throw new SecurityException("Calling uid " + callingUid @@ -374,9 +373,9 @@ public final class BasePermission { } } - private static BasePermission findPermissionTree( - Collection<BasePermission> permissionTrees, String permName) { - for (BasePermission bp : permissionTrees) { + private static BasePermission findPermissionTreeLP( + Map<String, BasePermission> permissionTrees, String permName) { + for (BasePermission bp : permissionTrees.values()) { if (permName.startsWith(bp.name) && permName.length() > bp.name.length() && permName.charAt(bp.name.length()) == '.') { diff --git a/com/android/server/pm/permission/PermissionManagerInternal.java b/com/android/server/pm/permission/PermissionManagerInternal.java index 8aac52ae..3b20b42b 100644 --- a/com/android/server/pm/permission/PermissionManagerInternal.java +++ b/com/android/server/pm/permission/PermissionManagerInternal.java @@ -31,7 +31,6 @@ import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Set; /** * Internal interfaces to be used by other components within the system server. @@ -82,26 +81,11 @@ public abstract class PermissionManagerInternal { @NonNull int[] allUserIds); - /** - * Add all permissions in the given package. - * <p> - * NOTE: argument {@code groupTEMP} is temporary until mPermissionGroups is moved to - * the permission settings. - */ - public abstract void addAllPermissions(@NonNull PackageParser.Package pkg, boolean chatty); - public abstract void removeAllPermissions(@NonNull PackageParser.Package pkg, boolean chatty); - public abstract boolean addDynamicPermission(@NonNull PermissionInfo info, boolean async, + public abstract boolean addPermission(@NonNull PermissionInfo info, boolean async, int callingUid, @Nullable PermissionCallback callback); - public abstract void removeDynamicPermission(@NonNull String permName, int callingUid, + public abstract void removePermission(@NonNull String permName, int callingUid, @Nullable PermissionCallback callback); - public abstract int updatePermissions(@Nullable String changingPkg, - @Nullable PackageParser.Package pkgInfo, int flags); - public abstract int updatePermissionTrees(@Nullable String changingPkg, - @Nullable PackageParser.Package pkgInfo, int flags); - - public abstract @Nullable String[] getAppOpPermissionPackages(@NonNull String permName); - public abstract int getPermissionFlags(@NonNull String permName, @NonNull String packageName, int callingUid, int userId); /** @@ -114,6 +98,8 @@ public abstract class PermissionManagerInternal { */ public abstract @Nullable List<PermissionInfo> getPermissionInfoByGroup(@NonNull String group, @PermissionInfoFlags int flags, int callingUid); + public abstract boolean isPermissionAppOp(@NonNull String permName); + public abstract boolean isPermissionInstant(@NonNull String permName); /** * Updates the flags associated with a permission by replacing the flags in diff --git a/com/android/server/pm/permission/PermissionManagerService.java b/com/android/server/pm/permission/PermissionManagerService.java index d2d857ca..6c031a6a 100644 --- a/com/android/server/pm/permission/PermissionManagerService.java +++ b/com/android/server/pm/permission/PermissionManagerService.java @@ -69,7 +69,6 @@ import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.List; -import java.util.Set; /** * Manages all permissions and handles permissions related tasks. @@ -261,7 +260,7 @@ public class PermissionManagerService { // } final ArrayList<PermissionInfo> out = new ArrayList<PermissionInfo>(10); - for (BasePermission bp : mSettings.mPermissions.values()) { + for (BasePermission bp : mSettings.getAllPermissionsLocked()) { final PermissionInfo pi = bp.generatePermissionInfo(groupName, flags); if (pi != null) { out.add(pi); @@ -306,98 +305,7 @@ public class PermissionManagerService { return protectionLevel; } - private void addAllPermissions(PackageParser.Package pkg, boolean chatty) { - final int N = pkg.permissions.size(); - for (int i=0; i<N; i++) { - PackageParser.Permission p = pkg.permissions.get(i); - - // Assume by default that we did not install this permission into the system. - p.info.flags &= ~PermissionInfo.FLAG_INSTALLED; - - // Now that permission groups have a special meaning, we ignore permission - // groups for legacy apps to prevent unexpected behavior. In particular, - // permissions for one app being granted to someone just because they happen - // to be in a group defined by another app (before this had no implications). - if (pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) { - p.group = mPackageManagerInt.getPermissionGroupTEMP(p.info.group); - // Warn for a permission in an unknown group. - if (PackageManagerService.DEBUG_PERMISSIONS - && p.info.group != null && p.group == null) { - Slog.i(TAG, "Permission " + p.info.name + " from package " - + p.info.packageName + " in an unknown group " + p.info.group); - } - } - - synchronized (PermissionManagerService.this.mLock) { - if (p.tree) { - final BasePermission bp = BasePermission.createOrUpdate( - mSettings.getPermissionTreeLocked(p.info.name), p, pkg, - mSettings.getAllPermissionTreesLocked(), chatty); - mSettings.putPermissionTreeLocked(p.info.name, bp); - } else { - final BasePermission bp = BasePermission.createOrUpdate( - mSettings.getPermissionLocked(p.info.name), - p, pkg, mSettings.getAllPermissionTreesLocked(), chatty); - mSettings.putPermissionLocked(p.info.name, bp); - } - } - } - } - - private void removeAllPermissions(PackageParser.Package pkg, boolean chatty) { - synchronized (mLock) { - int N = pkg.permissions.size(); - StringBuilder r = null; - for (int i=0; i<N; i++) { - PackageParser.Permission p = pkg.permissions.get(i); - BasePermission bp = (BasePermission) mSettings.mPermissions.get(p.info.name); - if (bp == null) { - bp = mSettings.mPermissionTrees.get(p.info.name); - } - if (bp != null && bp.isPermission(p)) { - bp.setPermission(null); - if (PackageManagerService.DEBUG_REMOVE && chatty) { - if (r == null) { - r = new StringBuilder(256); - } else { - r.append(' '); - } - r.append(p.info.name); - } - } - if (p.isAppOp()) { - ArraySet<String> appOpPkgs = - mSettings.mAppOpPermissionPackages.get(p.info.name); - if (appOpPkgs != null) { - appOpPkgs.remove(pkg.packageName); - } - } - } - if (r != null) { - if (PackageManagerService.DEBUG_REMOVE) Log.d(TAG, " Permissions: " + r); - } - - N = pkg.requestedPermissions.size(); - r = null; - for (int i=0; i<N; i++) { - String perm = pkg.requestedPermissions.get(i); - if (mSettings.isPermissionAppOp(perm)) { - ArraySet<String> appOpPkgs = mSettings.mAppOpPermissionPackages.get(perm); - if (appOpPkgs != null) { - appOpPkgs.remove(pkg.packageName); - if (appOpPkgs.isEmpty()) { - mSettings.mAppOpPermissionPackages.remove(perm); - } - } - } - } - if (r != null) { - if (PackageManagerService.DEBUG_REMOVE) Log.d(TAG, " Permissions: " + r); - } - } - } - - private boolean addDynamicPermission( + private boolean addPermission( PermissionInfo info, int callingUid, PermissionCallback callback) { if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) { throw new SecurityException("Instant apps can't add permissions"); @@ -405,7 +313,8 @@ public class PermissionManagerService { if (info.labelRes == 0 && info.nonLocalizedLabel == null) { throw new SecurityException("Label must be specified in permission"); } - final BasePermission tree = mSettings.enforcePermissionTree(info.name, callingUid); + final BasePermission tree = (BasePermission) mPackageManagerInt.enforcePermissionTreeTEMP( + info.name, callingUid); final boolean added; final boolean changed; synchronized (mLock) { @@ -417,8 +326,8 @@ public class PermissionManagerService { bp = new BasePermission(info.name, tree.getSourcePackageName(), BasePermission.TYPE_DYNAMIC); } else if (bp.isDynamic()) { - // TODO: switch this back to SecurityException - Slog.wtf(TAG, "Not allowed to modify non-dynamic permission " + throw new SecurityException( + "Not allowed to modify non-dynamic permission " + info.name); } changed = bp.addToTree(fixedLevel, info, tree); @@ -432,20 +341,21 @@ public class PermissionManagerService { return added; } - private void removeDynamicPermission( + private void removePermission( String permName, int callingUid, PermissionCallback callback) { if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) { throw new SecurityException("Instant applications don't have access to this method"); } - final BasePermission tree = mSettings.enforcePermissionTree(permName, callingUid); + final BasePermission tree = (BasePermission) mPackageManagerInt.enforcePermissionTreeTEMP( + permName, callingUid); synchronized (mLock) { final BasePermission bp = mSettings.getPermissionLocked(permName); if (bp == null) { return; } if (bp.isDynamic()) { - // TODO: switch this back to SecurityException - Slog.wtf(TAG, "Not allowed to modify non-dynamic permission " + throw new SecurityException( + "Not allowed to modify non-dynamic permission " + permName); } mSettings.removePermissionLocked(permName); @@ -803,21 +713,7 @@ public class PermissionManagerService { return runtimePermissionChangedUserIds; } - private String[] getAppOpPermissionPackages(String permName) { - if (mPackageManagerInt.getInstantAppPackageName(Binder.getCallingUid()) != null) { - return null; - } - synchronized (mLock) { - final ArraySet<String> pkgs = mSettings.mAppOpPermissionPackages.get(permName); - if (pkgs == null) { - return null; - } - return pkgs.toArray(new String[pkgs.size()]); - } - } - - private int getPermissionFlags( - String permName, String packageName, int callingUid, int userId) { + private int getPermissionFlags(String permName, String packageName, int callingUid, int userId) { if (!mUserManagerInt.exists(userId)) { return 0; } @@ -845,96 +741,6 @@ public class PermissionManagerService { return permissionsState.getPermissionFlags(permName, userId); } - private int updatePermissions(String packageName, PackageParser.Package pkgInfo, int flags) { - Set<BasePermission> needsUpdate = null; - synchronized (mLock) { - final Iterator<BasePermission> it = mSettings.mPermissions.values().iterator(); - while (it.hasNext()) { - final BasePermission bp = it.next(); - if (bp.isDynamic()) { - bp.updateDynamicPermission(mSettings.mPermissionTrees.values()); - } - if (bp.getSourcePackageSetting() != null) { - if (packageName != null && packageName.equals(bp.getSourcePackageName()) - && (pkgInfo == null || !hasPermission(pkgInfo, bp.getName()))) { - Slog.i(TAG, "Removing old permission tree: " + bp.getName() - + " from package " + bp.getSourcePackageName()); - flags |= PackageManagerService.UPDATE_PERMISSIONS_ALL; - it.remove(); - } - continue; - } - if (needsUpdate == null) { - needsUpdate = new ArraySet<>(mSettings.mPermissions.size()); - } - needsUpdate.add(bp); - } - } - if (needsUpdate != null) { - for (final BasePermission bp : needsUpdate) { - final PackageParser.Package pkg = - mPackageManagerInt.getPackage(bp.getSourcePackageName()); - synchronized (mLock) { - if (pkg != null && pkg.mExtras != null) { - final PackageSetting ps = (PackageSetting) pkg.mExtras; - if (bp.getSourcePackageSetting() == null) { - bp.setSourcePackageSetting(ps); - } - continue; - } - Slog.w(TAG, "Removing dangling permission: " + bp.getName() - + " from package " + bp.getSourcePackageName()); - mSettings.removePermissionLocked(bp.getName()); - } - } - } - return flags; - } - - private int updatePermissionTrees(String packageName, PackageParser.Package pkgInfo, - int flags) { - Set<BasePermission> needsUpdate = null; - synchronized (mLock) { - final Iterator<BasePermission> it = mSettings.mPermissionTrees.values().iterator(); - while (it.hasNext()) { - final BasePermission bp = it.next(); - if (bp.getSourcePackageSetting() != null) { - if (packageName != null && packageName.equals(bp.getSourcePackageName()) - && (pkgInfo == null || !hasPermission(pkgInfo, bp.getName()))) { - Slog.i(TAG, "Removing old permission tree: " + bp.getName() - + " from package " + bp.getSourcePackageName()); - flags |= PackageManagerService.UPDATE_PERMISSIONS_ALL; - it.remove(); - } - continue; - } - if (needsUpdate == null) { - needsUpdate = new ArraySet<>(mSettings.mPermissionTrees.size()); - } - needsUpdate.add(bp); - } - } - if (needsUpdate != null) { - for (final BasePermission bp : needsUpdate) { - final PackageParser.Package pkg = - mPackageManagerInt.getPackage(bp.getSourcePackageName()); - synchronized (mLock) { - if (pkg != null && pkg.mExtras != null) { - final PackageSetting ps = (PackageSetting) pkg.mExtras; - if (bp.getSourcePackageSetting() == null) { - bp.setSourcePackageSetting(ps); - } - continue; - } - Slog.w(TAG, "Removing dangling permission tree: " + bp.getName() - + " from package " + bp.getSourcePackageName()); - mSettings.removePermissionLocked(bp.getName()); - } - } - } - return flags; - } - private void updatePermissionFlags(String permName, String packageName, int flagMask, int flagValues, int callingUid, int userId, PermissionCallback callback) { if (!mUserManagerInt.exists(userId)) { @@ -1066,7 +872,7 @@ public class PermissionManagerService { private int calculateCurrentPermissionFootprintLocked(BasePermission tree) { int size = 0; - for (BasePermission perm : mSettings.mPermissions.values()) { + for (BasePermission perm : mSettings.getAllPermissionsLocked()) { size += tree.calculateFootprint(perm); } return size; @@ -1083,15 +889,6 @@ public class PermissionManagerService { } } - private static boolean hasPermission(PackageParser.Package pkgInfo, String permName) { - for (int i=pkgInfo.permissions.size()-1; i>=0; i--) { - if (pkgInfo.permissions.get(i).info.name.equals(permName)) { - return true; - } - } - return false; - } - /** * Get the first event id for the permission. * @@ -1154,22 +951,14 @@ public class PermissionManagerService { private class PermissionManagerInternalImpl extends PermissionManagerInternal { @Override - public void addAllPermissions(Package pkg, boolean chatty) { - PermissionManagerService.this.addAllPermissions(pkg, chatty); - } - @Override - public void removeAllPermissions(Package pkg, boolean chatty) { - PermissionManagerService.this.removeAllPermissions(pkg, chatty); - } - @Override - public boolean addDynamicPermission(PermissionInfo info, boolean async, int callingUid, + public boolean addPermission(PermissionInfo info, boolean async, int callingUid, PermissionCallback callback) { - return PermissionManagerService.this.addDynamicPermission(info, callingUid, callback); + return PermissionManagerService.this.addPermission(info, callingUid, callback); } @Override - public void removeDynamicPermission(String permName, int callingUid, + public void removePermission(String permName, int callingUid, PermissionCallback callback) { - PermissionManagerService.this.removeDynamicPermission(permName, callingUid, callback); + PermissionManagerService.this.removePermission(permName, callingUid, callback); } @Override public void grantRuntimePermission(String permName, String packageName, @@ -1204,26 +993,12 @@ public class PermissionManagerService { (SharedUserSetting) suSetting, allUserIds); } @Override - public String[] getAppOpPermissionPackages(String permName) { - return PermissionManagerService.this.getAppOpPermissionPackages(permName); - } - @Override public int getPermissionFlags(String permName, String packageName, int callingUid, int userId) { return PermissionManagerService.this.getPermissionFlags(permName, packageName, callingUid, userId); } @Override - public int updatePermissions(String packageName, - PackageParser.Package pkgInfo, int flags) { - return PermissionManagerService.this.updatePermissions(packageName, pkgInfo, flags); - } - @Override - public int updatePermissionTrees(String packageName, - PackageParser.Package pkgInfo, int flags) { - return PermissionManagerService.this.updatePermissionTrees(packageName, pkgInfo, flags); - } - @Override public void updatePermissionFlags(String permName, String packageName, int flagMask, int flagValues, int callingUid, int userId, PermissionCallback callback) { PermissionManagerService.this.updatePermissionFlags( @@ -1263,6 +1038,20 @@ public class PermissionManagerService { return PermissionManagerService.this.getPermissionInfoByGroup(group, flags, callingUid); } @Override + public boolean isPermissionInstant(String permName) { + synchronized (PermissionManagerService.this.mLock) { + final BasePermission bp = mSettings.getPermissionLocked(permName); + return (bp != null && bp.isInstant()); + } + } + @Override + public boolean isPermissionAppOp(String permName) { + synchronized (PermissionManagerService.this.mLock) { + final BasePermission bp = mSettings.getPermissionLocked(permName); + return (bp != null && bp.isAppOp()); + } + } + @Override public PermissionSettings getPermissionSettings() { return mSettings; } diff --git a/com/android/server/pm/permission/PermissionSettings.java b/com/android/server/pm/permission/PermissionSettings.java index 7d125c9e..7a2e5ecc 100644 --- a/com/android/server/pm/permission/PermissionSettings.java +++ b/com/android/server/pm/permission/PermissionSettings.java @@ -24,7 +24,6 @@ import android.util.ArraySet; import android.util.Log; import com.android.internal.R; -import com.android.internal.annotations.GuardedBy; import com.android.internal.util.XmlUtils; import com.android.server.pm.DumpState; import com.android.server.pm.PackageManagerService; @@ -36,7 +35,6 @@ import org.xmlpull.v1.XmlSerializer; import java.io.IOException; import java.io.PrintWriter; import java.util.Collection; -import java.util.Set; /** * Permissions and other related data. This class is not meant for @@ -51,25 +49,8 @@ public class PermissionSettings { * All of the permissions known to the system. The mapping is from permission * name to permission object. */ - @GuardedBy("mLock") - final ArrayMap<String, BasePermission> mPermissions = + private final ArrayMap<String, BasePermission> mPermissions = new ArrayMap<String, BasePermission>(); - - /** - * All permission trees known to the system. The mapping is from permission tree - * name to permission object. - */ - @GuardedBy("mLock") - final ArrayMap<String, BasePermission> mPermissionTrees = - new ArrayMap<String, BasePermission>(); - - /** - * Set of packages that request a particular app op. The mapping is from permission - * name to package names. - */ - @GuardedBy("mLock") - final ArrayMap<String, ArraySet<String>> mAppOpPermissionPackages = new ArrayMap<>(); - private final Object mLock; PermissionSettings(@NonNull Context context, @NonNull Object lock) { @@ -84,23 +65,15 @@ public class PermissionSettings { } } - public void addAppOpPackage(String permName, String packageName) { - ArraySet<String> pkgs = mAppOpPermissionPackages.get(permName); - if (pkgs == null) { - pkgs = new ArraySet<>(); - mAppOpPermissionPackages.put(permName, pkgs); - } - pkgs.add(packageName); - } - /** * Transfers ownership of permissions from one package to another. */ - public void transferPermissions(String origPackageName, String newPackageName) { + public void transferPermissions(String origPackageName, String newPackageName, + ArrayMap<String, BasePermission> permissionTrees) { synchronized (mLock) { for (int i=0; i<2; i++) { ArrayMap<String, BasePermission> permissions = - i == 0 ? mPermissionTrees : mPermissions; + i == 0 ? permissionTrees : mPermissions; for (BasePermission bp : permissions.values()) { bp.transfer(origPackageName, newPackageName); } @@ -121,26 +94,9 @@ public class PermissionSettings { } } - public void readPermissionTrees(XmlPullParser parser) - throws IOException, XmlPullParserException { - synchronized (mLock) { - readPermissions(mPermissionTrees, parser); - } - } - public void writePermissions(XmlSerializer serializer) throws IOException { - synchronized (mLock) { - for (BasePermission bp : mPermissions.values()) { - bp.writeLPr(serializer); - } - } - } - - public void writePermissionTrees(XmlSerializer serializer) throws IOException { - synchronized (mLock) { - for (BasePermission bp : mPermissionTrees.values()) { - bp.writeLPr(serializer); - } + for (BasePermission bp : mPermissions.values()) { + bp.writeLPr(serializer); } } @@ -172,22 +128,6 @@ public class PermissionSettings { printedSomething = bp.dumpPermissionsLPr(pw, packageName, permissionNames, externalStorageEnforced, printedSomething, dumpState); } - if (packageName == null && permissionNames == null) { - for (int iperm = 0; iperm<mAppOpPermissionPackages.size(); iperm++) { - if (iperm == 0) { - if (dumpState.onTitlePrinted()) - pw.println(); - pw.println("AppOp Permissions:"); - } - pw.print(" AppOp Permission "); - pw.print(mAppOpPermissionPackages.keyAt(iperm)); - pw.println(":"); - ArraySet<String> pkgs = mAppOpPermissionPackages.valueAt(iperm); - for (int ipkg=0; ipkg<pkgs.size(); ipkg++) { - pw.print(" "); pw.println(pkgs.valueAt(ipkg)); - } - } - } } } @@ -195,58 +135,15 @@ public class PermissionSettings { return mPermissions.get(permName); } - @Nullable BasePermission getPermissionTreeLocked(@NonNull String permName) { - return mPermissionTrees.get(permName); - } - void putPermissionLocked(@NonNull String permName, @NonNull BasePermission permission) { mPermissions.put(permName, permission); } - void putPermissionTreeLocked(@NonNull String permName, @NonNull BasePermission permission) { - mPermissionTrees.put(permName, permission); - } - void removePermissionLocked(@NonNull String permName) { mPermissions.remove(permName); } - void removePermissionTreeLocked(@NonNull String permName) { - mPermissionTrees.remove(permName); - } - - @NonNull Collection<BasePermission> getAllPermissionsLocked() { + Collection<BasePermission> getAllPermissionsLocked() { return mPermissions.values(); } - - @NonNull Collection<BasePermission> getAllPermissionTreesLocked() { - return mPermissionTrees.values(); - } - - /** - * Returns the permission tree for the given permission. - * @throws SecurityException If the calling UID is not allowed to add permissions to the - * found permission tree. - */ - @Nullable BasePermission enforcePermissionTree(@NonNull String permName, int callingUid) { - synchronized (mLock) { - return BasePermission.enforcePermissionTree( - mPermissionTrees.values(), permName, callingUid); - } - } - - public boolean isPermissionInstant(String permName) { - synchronized (mLock) { - final BasePermission bp = mPermissions.get(permName); - return (bp != null && bp.isInstant()); - } - } - - boolean isPermissionAppOp(String permName) { - synchronized (mLock) { - final BasePermission bp = mPermissions.get(permName); - return (bp != null && bp.isAppOp()); - } - } - } diff --git a/com/android/server/policy/GlobalActions.java b/com/android/server/policy/GlobalActions.java index 7a2e630c..342ec4b7 100644 --- a/com/android/server/policy/GlobalActions.java +++ b/com/android/server/policy/GlobalActions.java @@ -58,9 +58,6 @@ class GlobalActions implements GlobalActionsListener { public void showDialog(boolean keyguardShowing, boolean deviceProvisioned) { if (DEBUG) Slog.d(TAG, "showDialog " + keyguardShowing + " " + deviceProvisioned); - if (mStatusBarInternal.isGlobalActionsDisabled()) { - return; - } mKeyguardShowing = keyguardShowing; mDeviceProvisioned = deviceProvisioned; mShowing = true; diff --git a/com/android/server/policy/PhoneWindowManager.java b/com/android/server/policy/PhoneWindowManager.java index ceb0ad07..db7817ec 100644 --- a/com/android/server/policy/PhoneWindowManager.java +++ b/com/android/server/policy/PhoneWindowManager.java @@ -18,14 +18,13 @@ package com.android.server.policy; import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; import static android.Manifest.permission.SYSTEM_ALERT_WINDOW; +import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; +import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW; import static android.app.AppOpsManager.OP_TOAST_WINDOW; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; -import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; -import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; -import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.Context.CONTEXT_RESTRICTED; import static android.content.Context.DISPLAY_SERVICE; @@ -553,6 +552,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { int mUserRotationMode = WindowManagerPolicy.USER_ROTATION_FREE; int mUserRotation = Surface.ROTATION_0; + boolean mAccelerometerDefault; boolean mSupportAutoRotation; int mAllowAllRotations = -1; @@ -707,6 +707,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { Intent mVrHeadsetHomeIntent; boolean mSearchKeyShortcutPending; boolean mConsumeSearchKeyUp; + boolean mAssistKeyLongPressed; boolean mPendingMetaAction; boolean mPendingCapsLockToggle; int mMetaState; @@ -837,8 +838,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { private static final int MSG_DISPATCH_BACK_KEY_TO_AUTOFILL = 24; private static final int MSG_SYSTEM_KEY_PRESS = 25; private static final int MSG_HANDLE_ALL_APPS = 26; - private static final int MSG_LAUNCH_ASSIST = 27; - private static final int MSG_LAUNCH_ASSIST_LONG_PRESS = 28; private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0; private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1; @@ -880,16 +879,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { case MSG_HIDE_BOOT_MESSAGE: handleHideBootMessage(); break; - case MSG_LAUNCH_ASSIST: - final int deviceId = msg.arg1; - final String hint = (String) msg.obj; - launchAssistAction(hint, deviceId); - break; - case MSG_LAUNCH_ASSIST_LONG_PRESS: - launchAssistLongPressAction(); - break; case MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK: - launchVoiceAssistWithWakeLock(); + launchVoiceAssistWithWakeLock(msg.arg1 != 0); break; case MSG_POWER_DELAYED_PRESS: powerPress((Long)msg.obj, msg.arg1 != 0, msg.arg2); @@ -919,7 +910,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { disposeInputConsumer((InputConsumer) msg.obj); break; case MSG_BACK_DELAYED_PRESS: - backMultiPressAction(msg.arg1); + backMultiPressAction((Long) msg.obj, msg.arg1); finishBackKeyPress(); break; case MSG_ACCESSIBILITY_SHORTCUT: @@ -1423,7 +1414,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - private void backMultiPressAction(int count) { + private void backMultiPressAction(long eventTime, int count) { if (count >= PANIC_PRESS_BACK_COUNT) { switch (mPanicPressOnBackBehavior) { case PANIC_PRESS_BACK_NOTHING: @@ -1592,7 +1583,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - private void sleepPress() { + private void sleepPress(long eventTime) { if (mShortPressOnSleepBehavior == SHORT_PRESS_SLEEP_GO_TO_SLEEP_AND_GO_HOME) { launchHomeFromHotKey(false /* awakenDreams */, true /*respectKeyguard*/); } @@ -2279,11 +2270,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Only force the default orientation if the screen is xlarge, at least 960dp x 720dp, per // http://developer.android.com/guide/practices/screens_support.html#range - // For car, ignore the dp limitation. It's physically impossible to rotate the car's screen - // so if the orientation is forced, we need to respect that no matter what. - boolean isCar = mContext.getPackageManager().hasSystemFeature( - PackageManager.FEATURE_AUTOMOTIVE); - mForceDefaultOrientation = ((longSizeDp >= 960 && shortSizeDp >= 720) || isCar) && + mForceDefaultOrientation = longSizeDp >= 960 && shortSizeDp >= 720 && res.getBoolean(com.android.internal.R.bool.config_forceDefaultOrientation) && // For debug purposes the next line turns this feature off with: // $ adb shell setprop config.override_forced_orient true @@ -2857,7 +2844,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean keyguardLocked = isKeyguardLocked(); boolean hideDockDivider = attrs.type == TYPE_DOCK_DIVIDER - && !mWindowManagerInternal.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); + && !mWindowManagerInternal.isStackVisible(DOCKED_STACK_ID); return (keyguardLocked && !allowWhenLocked && win.getDisplayId() == DEFAULT_DISPLAY) || hideDockDivider; } @@ -3550,11 +3537,44 @@ public class PhoneWindowManager implements WindowManagerPolicy { toggleKeyboardShortcutsMenu(event.getDeviceId()); } } else if (keyCode == KeyEvent.KEYCODE_ASSIST) { - Slog.wtf(TAG, "KEYCODE_ASSIST should be handled in interceptKeyBeforeQueueing"); + if (down) { + if (repeatCount == 0) { + mAssistKeyLongPressed = false; + } else if (repeatCount == 1) { + mAssistKeyLongPressed = true; + if (!keyguardOn) { + launchAssistLongPressAction(); + } + } + } else { + if (mAssistKeyLongPressed) { + mAssistKeyLongPressed = false; + } else { + if (!keyguardOn) { + launchAssistAction(null, event.getDeviceId()); + } + } + } return -1; } else if (keyCode == KeyEvent.KEYCODE_VOICE_ASSIST) { - Slog.wtf(TAG, "KEYCODE_VOICE_ASSIST should be handled in interceptKeyBeforeQueueing"); - return -1; + if (!down) { + Intent voiceIntent; + if (!keyguardOn) { + voiceIntent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH); + } else { + IDeviceIdleController dic = IDeviceIdleController.Stub.asInterface( + ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER)); + if (dic != null) { + try { + dic.exitIdle("voice-search"); + } catch (RemoteException e) { + } + } + voiceIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE); + voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE, true); + } + startActivityAsUser(voiceIntent, UserHandle.CURRENT_OR_SELF); + } } else if (keyCode == KeyEvent.KEYCODE_SYSRQ) { if (down && repeatCount == 0) { mScreenshotRunnable.setScreenshotType(TAKE_SCREENSHOT_FULLSCREEN); @@ -5425,10 +5445,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean appWindow = attrs.type >= FIRST_APPLICATION_WINDOW && attrs.type < FIRST_SYSTEM_WINDOW; - final int windowingMode = win.getWindowingMode(); - final boolean inFullScreenOrSplitScreenSecondaryWindowingMode = - windowingMode == WINDOWING_MODE_FULLSCREEN - || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; + final int stackId = win.getStackId(); if (mTopFullscreenOpaqueWindowState == null && affectsSystemUi) { if ((fl & FLAG_FORCE_NOT_FULLSCREEN) != 0) { mForceStatusBar = true; @@ -5447,7 +5464,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // represent should be hidden or if we should hide the lockscreen. For attached app // windows we defer the decision to the window it is attached to. if (appWindow && attached == null) { - if (attrs.isFullscreen() && inFullScreenOrSplitScreenSecondaryWindowingMode) { + if (attrs.isFullscreen() && StackId.normallyFullscreenWindows(stackId)) { if (DEBUG_LAYOUT) Slog.v(TAG, "Fullscreen window: " + win); mTopFullscreenOpaqueWindowState = win; if (mTopFullscreenOpaqueOrDimmingWindowState == null) { @@ -5478,7 +5495,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Keep track of the window if it's dimming but not necessarily fullscreen. if (mTopFullscreenOpaqueOrDimmingWindowState == null && affectsSystemUi - && win.isDimming() && inFullScreenOrSplitScreenSecondaryWindowingMode) { + && win.isDimming() && StackId.normallyFullscreenWindows(stackId)) { mTopFullscreenOpaqueOrDimmingWindowState = win; } @@ -5486,7 +5503,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // separately, because both the "real fullscreen" opaque window and the one for the docked // stack can control View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR. if (mTopDockedOpaqueWindowState == null && affectsSystemUi && appWindow && attached == null - && attrs.isFullscreen() && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { + && attrs.isFullscreen() && stackId == DOCKED_STACK_ID) { mTopDockedOpaqueWindowState = win; if (mTopDockedOpaqueOrDimmingWindowState == null) { mTopDockedOpaqueOrDimmingWindowState = win; @@ -5496,7 +5513,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Also keep track of any windows that are dimming but not necessarily fullscreen in the // docked stack. if (mTopDockedOpaqueOrDimmingWindowState == null && affectsSystemUi && win.isDimming() - && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { + && stackId == DOCKED_STACK_ID) { mTopDockedOpaqueOrDimmingWindowState = win; } @@ -5591,9 +5608,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { changes |= FINISH_LAYOUT_REDO_LAYOUT; } } else if (topIsFullscreen - && !mWindowManagerInternal.isStackVisible(WINDOWING_MODE_FREEFORM) - && !mWindowManagerInternal.isStackVisible( - WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) { + && !mWindowManagerInternal.isStackVisible(FREEFORM_WORKSPACE_STACK_ID) + && !mWindowManagerInternal.isStackVisible(DOCKED_STACK_ID)) { if (DEBUG_LAYOUT) Slog.v(TAG, "** HIDING status bar"); if (mStatusBarController.setBarShowingLw(false)) { changes |= FINISH_LAYOUT_REDO_LAYOUT; @@ -6175,7 +6191,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { useHapticFeedback = false; // suppress feedback if already non-interactive } if (down) { - sleepPress(); + sleepPress(event.getEventTime()); } else { sleepRelease(event.getEventTime()); } @@ -6246,30 +6262,18 @@ public class PhoneWindowManager implements WindowManagerPolicy { } break; } - case KeyEvent.KEYCODE_ASSIST: { - final boolean longPressed = event.getRepeatCount() > 0; - if (down && longPressed) { - Message msg = mHandler.obtainMessage(MSG_LAUNCH_ASSIST_LONG_PRESS); - msg.setAsynchronous(true); - msg.sendToTarget(); - } - if (!down && !longPressed) { - Message msg = mHandler.obtainMessage(MSG_LAUNCH_ASSIST, event.getDeviceId(), - 0 /* unused */, null /* hint */); - msg.setAsynchronous(true); - msg.sendToTarget(); - } - result &= ~ACTION_PASS_TO_USER; - break; - } case KeyEvent.KEYCODE_VOICE_ASSIST: { - if (!down) { + // Only do this if we would otherwise not pass it to the user. In that case, + // interceptKeyBeforeDispatching would apply a similar but different policy in + // order to invoke voice assist actions. Note that we need to make a copy of the + // key event here because the original key event will be recycled when we return. + if ((result & ACTION_PASS_TO_USER) == 0 && !down) { mBroadcastWakeLock.acquire(); - Message msg = mHandler.obtainMessage(MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK); + Message msg = mHandler.obtainMessage(MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK, + keyguardActive ? 1 : 0, 0); msg.setAsynchronous(true); msg.sendToTarget(); } - result &= ~ACTION_PASS_TO_USER; break; } case KeyEvent.KEYCODE_WINDOW: { @@ -6538,22 +6542,18 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - void launchVoiceAssistWithWakeLock() { - final Intent voiceIntent; - if (!keyguardOn()) { - voiceIntent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH); - } else { - IDeviceIdleController dic = IDeviceIdleController.Stub.asInterface( - ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER)); - if (dic != null) { - try { - dic.exitIdle("voice-search"); - } catch (RemoteException e) { - } + void launchVoiceAssistWithWakeLock(boolean keyguardActive) { + IDeviceIdleController dic = IDeviceIdleController.Stub.asInterface( + ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER)); + if (dic != null) { + try { + dic.exitIdle("voice-search"); + } catch (RemoteException e) { } - voiceIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE); - voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE, true); } + Intent voiceIntent = + new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE); + voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE, keyguardActive); startActivityAsUser(voiceIntent, UserHandle.CURRENT_OR_SELF); mBroadcastWakeLock.release(); } @@ -8009,10 +8009,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { } private int updateSystemBarsLw(WindowState win, int oldVis, int vis) { - final boolean dockedStackVisible = - mWindowManagerInternal.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); + final boolean dockedStackVisible = mWindowManagerInternal.isStackVisible(DOCKED_STACK_ID); final boolean freeformStackVisible = - mWindowManagerInternal.isStackVisible(WINDOWING_MODE_FREEFORM); + mWindowManagerInternal.isStackVisible(FREEFORM_WORKSPACE_STACK_ID); final boolean resizing = mWindowManagerInternal.isDockedDividerResizing(); // We need to force system bars when the docked stack is visible, when the freeform stack diff --git a/com/android/server/stats/StatsCompanionService.java b/com/android/server/stats/StatsCompanionService.java index ca3dd058..f1fb3e7b 100644 --- a/com/android/server/stats/StatsCompanionService.java +++ b/com/android/server/stats/StatsCompanionService.java @@ -20,25 +20,15 @@ import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.UserInfo; -import android.content.IntentFilter; import android.os.Binder; -import android.os.Bundle; import android.os.IBinder; import android.os.IStatsCompanionService; import android.os.IStatsManager; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; -import android.os.UserHandle; -import android.os.UserManager; import android.util.Slog; -import java.util.ArrayList; -import java.util.List; import com.android.internal.annotations.GuardedBy; import com.android.internal.os.KernelWakelockReader; import com.android.internal.os.KernelWakelockStats; @@ -63,8 +53,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { private final PendingIntent mAnomalyAlarmIntent; private final PendingIntent mPollingAlarmIntent; - private final BroadcastReceiver mAppUpdateReceiver; - private final BroadcastReceiver mUserUpdateReceiver; public StatsCompanionService(Context context) { super(); @@ -75,113 +63,8 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { new Intent(mContext, AnomalyAlarmReceiver.class), 0); mPollingAlarmIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(mContext, PollingAlarmReceiver.class), 0); - mAppUpdateReceiver = new AppUpdateReceiver(); - mUserUpdateReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - synchronized (sStatsdLock) { - sStatsd = fetchStatsdService(); - if (sStatsd == null) { - Slog.w(TAG, "Could not access statsd"); - return; - } - try { - // Pull the latest state of UID->app name, version mapping. - // Needed since the new user basically has a version of every app. - informAllUidsLocked(context); - } catch (RemoteException e) { - Slog.e(TAG, "Failed to inform statsd that statscompanion is ready", e); - forgetEverything(); - } - } - } - }; - Slog.w(TAG, "Registered receiver for ACTION_PACKAGE_REPLACE AND ADDED."); } - private final static int[] toIntArray(List<Integer> list){ - int[] ret = new int[list.size()]; - for(int i = 0;i < ret.length;i++) { - ret[i] = list.get(i); - } - return ret; - } - - // Assumes that sStatsdLock is held. - private final void informAllUidsLocked(Context context) throws RemoteException { - UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); - PackageManager pm = context.getPackageManager(); - final List<UserInfo> users = um.getUsers(true); - if (DEBUG) { - Slog.w(TAG, "Iterating over "+users.size() + " profiles."); - } - - List<Integer> uids = new ArrayList(); - List<Integer> versions = new ArrayList(); - List<String> apps = new ArrayList(); - - // Add in all the apps for every user/profile. - for (UserInfo profile : users) { - List<PackageInfo> pi = pm.getInstalledPackagesAsUser(0, profile.id); - for (int j = 0; j < pi.size(); j++) { - if (pi.get(j).applicationInfo != null) { - uids.add(pi.get(j).applicationInfo.uid); - versions.add(pi.get(j).versionCode); - apps.add(pi.get(j).packageName); - } - } - } - sStatsd.informAllUidData(toIntArray(uids), toIntArray(versions), apps.toArray(new - String[apps.size()])); - if (DEBUG) { - Slog.w(TAG, "Sent data for "+uids.size() +" apps"); - } - } - - public final static class AppUpdateReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - Slog.i(TAG, "StatsCompanionService noticed an app was updated."); - /** - * App updates actually consist of REMOVE, ADD, and then REPLACE broadcasts. To avoid - * waste, we ignore the REMOVE and ADD broadcasts that contain the replacing flag. - */ - if (!intent.getAction().equals(Intent.ACTION_PACKAGE_REPLACED) && - intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { - return; // Keep only replacing or normal add and remove. - } - synchronized (sStatsdLock) { - if (sStatsd == null) { - Slog.w(TAG, "Could not access statsd to inform it of anomaly alarm firing"); - return; - } - try { - if (intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED)) { - Bundle b = intent.getExtras(); - int uid = b.getInt(Intent.EXTRA_UID); - boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); - if (!replacing) { - // Don't bother sending an update if we're right about to get another - // intent for the new version that's added. - PackageManager pm = context.getPackageManager(); - String app = intent.getData().getSchemeSpecificPart(); - sStatsd.informOnePackageRemoved(app, uid); - } - } else { - PackageManager pm = context.getPackageManager(); - Bundle b = intent.getExtras(); - int uid = b.getInt(Intent.EXTRA_UID); - String app = intent.getData().getSchemeSpecificPart(); - PackageInfo pi = pm.getPackageInfo(app, PackageManager.MATCH_ANY_USER); - sStatsd.informOnePackage(app, uid, pi.versionCode); - } - } catch (Exception e) { - Slog.w(TAG, "Failed to inform statsd of an app update", e); - } - } - } - }; - public final static class AnomalyAlarmReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { @@ -392,23 +275,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { Slog.e(TAG, "linkToDeath(StatsdDeathRecipient) failed", e); forgetEverything(); } - // Setup broadcast receiver for updates - IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REPLACED); - filter.addAction(Intent.ACTION_PACKAGE_ADDED); - filter.addAction(Intent.ACTION_PACKAGE_REMOVED); - filter.addDataScheme("package"); - mContext.registerReceiverAsUser(mAppUpdateReceiver, UserHandle.ALL, filter, null, - null); - - // Setup receiver for user initialize (which happens once for a new user) and - // if a user is removed. - filter = new IntentFilter(Intent.ACTION_USER_INITIALIZE); - filter.addAction(Intent.ACTION_USER_REMOVED); - mContext.registerReceiverAsUser(mUserUpdateReceiver, UserHandle.ALL, - filter, null, null); - - // Pull the latest state of UID->app name, version mapping when statsd starts. - informAllUidsLocked(mContext); } catch (RemoteException e) { Slog.e(TAG, "Failed to inform statsd that statscompanion is ready", e); forgetEverything(); @@ -427,8 +293,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { private void forgetEverything() { synchronized (sStatsdLock) { sStatsd = null; - mContext.unregisterReceiver(mAppUpdateReceiver); - mContext.unregisterReceiver(mUserUpdateReceiver); cancelAnomalyAlarm(); cancelPollingAlarms(); } diff --git a/com/android/server/statusbar/StatusBarManagerInternal.java b/com/android/server/statusbar/StatusBarManagerInternal.java index b07fe98d..08846784 100644 --- a/com/android/server/statusbar/StatusBarManagerInternal.java +++ b/com/android/server/statusbar/StatusBarManagerInternal.java @@ -77,7 +77,6 @@ public interface StatusBarManagerInternal { void setCurrentUser(int newUserId); - boolean isGlobalActionsDisabled(); void setGlobalActionsListener(GlobalActionsListener listener); void showGlobalActions(); diff --git a/com/android/server/statusbar/StatusBarManagerService.java b/com/android/server/statusbar/StatusBarManagerService.java index c78a3406..bdfbe481 100644 --- a/com/android/server/statusbar/StatusBarManagerService.java +++ b/com/android/server/statusbar/StatusBarManagerService.java @@ -16,8 +16,6 @@ package com.android.server.statusbar; -import static android.app.StatusBarManager.DISABLE2_GLOBAL_ACTIONS; - import android.app.ActivityThread; import android.app.StatusBarManager; import android.content.ComponentName; @@ -365,11 +363,6 @@ public class StatusBarManagerService extends IStatusBarService.Stub { } @Override - public boolean isGlobalActionsDisabled() { - return (mDisabled2 & DISABLE2_GLOBAL_ACTIONS) != 0; - } - - @Override public void setGlobalActionsListener(GlobalActionsListener listener) { mGlobalActionListener = listener; mGlobalActionListener.onStatusBarConnectedChanged(mBar != null); diff --git a/com/android/server/tv/TvInputHardwareManager.java b/com/android/server/tv/TvInputHardwareManager.java index c1607e94..6117da7b 100644 --- a/com/android/server/tv/TvInputHardwareManager.java +++ b/com/android/server/tv/TvInputHardwareManager.java @@ -1022,6 +1022,20 @@ class TvInputHardwareManager implements TvInputHal.Callback { } } + @Override + public boolean dispatchKeyEventToHdmi(KeyEvent event) throws RemoteException { + synchronized (mImplLock) { + if (mReleased) { + throw new IllegalStateException("Device already released."); + } + } + if (mInfo.getType() != TvInputHardwareInfo.TV_INPUT_TYPE_HDMI) { + return false; + } + // TODO(hdmi): mHdmiClient.sendKeyEvent(event); + return false; + } + private boolean startCapture(Surface surface, TvStreamConfig config) { synchronized (mImplLock) { if (mReleased) { diff --git a/com/android/server/usb/UsbAlsaManager.java b/com/android/server/usb/UsbAlsaManager.java index d359b704..acc27bee 100644 --- a/com/android/server/usb/UsbAlsaManager.java +++ b/com/android/server/usb/UsbAlsaManager.java @@ -132,9 +132,7 @@ public final class UsbAlsaManager { mHasMidiFeature = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_MIDI); // initial scan - if (mCardsParser.scan() != AlsaCardsParser.SCANSTATUS_SUCCESS) { - Slog.e(TAG, "Error scanning ASLA cards file."); - } + mCardsParser.scan(); } public void systemReady() { @@ -316,7 +314,7 @@ public final class UsbAlsaManager { return null; } - if (mDevicesParser.scan() != AlsaDevicesParser.SCANSTATUS_SUCCESS) { + if (!mDevicesParser.scan()) { Slog.e(TAG, "Error parsing ALSA devices file."); return null; } @@ -532,9 +530,6 @@ public final class UsbAlsaManager { // // called by UsbService.dump public void dump(IndentingPrintWriter pw) { - pw.println("Parsers Scan Status:"); - pw.println(" Cards Parser: " + mCardsParser.getScanStatus()); - pw.println(" Devices Parser: " + mDevicesParser.getScanStatus()); pw.println("USB Audio Devices:"); for (UsbDevice device : mAudioDevices.keySet()) { pw.println(" " + device.getDeviceName() + ": " + mAudioDevices.get(device)); diff --git a/com/android/server/usb/UsbHostManager.java b/com/android/server/usb/UsbHostManager.java index 095fdc63..c657a1b4 100644 --- a/com/android/server/usb/UsbHostManager.java +++ b/com/android/server/usb/UsbHostManager.java @@ -376,8 +376,6 @@ public class UsbHostManager { } } } - - mUsbAlsaManager.dump(pw); } private native void monitorUsbHostBus(); diff --git a/com/android/server/wifi/SelfRecovery.java b/com/android/server/wifi/SelfRecovery.java index e39e0d5b..21a3e0ac 100644 --- a/com/android/server/wifi/SelfRecovery.java +++ b/com/android/server/wifi/SelfRecovery.java @@ -72,7 +72,7 @@ public class SelfRecovery { Log.e(TAG, "Invalid trigger reason. Ignoring..."); return; } - Log.e(TAG, "Triggering recovery for reason: " + REASON_STRINGS[reason]); + Log.wtf(TAG, "Triggering recovery for reason: " + REASON_STRINGS[reason]); if (reason == REASON_WIFICOND_CRASH || reason == REASON_HAL_CRASH) { trimPastRestartTimes(); // Ensure there haven't been too many restarts within MAX_RESTARTS_TIME_WINDOW diff --git a/com/android/server/wifi/WifiNative.java b/com/android/server/wifi/WifiNative.java index 35dec2e7..0b1719db 100644 --- a/com/android/server/wifi/WifiNative.java +++ b/com/android/server/wifi/WifiNative.java @@ -16,7 +16,6 @@ package com.android.server.wifi; -import android.annotation.NonNull; import android.annotation.Nullable; import android.net.apf.ApfCapabilities; import android.net.wifi.IApInterface; @@ -110,12 +109,12 @@ public class WifiNative { * @return Pair of <Integer, IClientInterface> to indicate the status and the associated wificond * client interface binder handler (will be null on failure). */ - public Pair<Integer, IClientInterface> setupForClientMode(@NonNull String ifaceName) { + public Pair<Integer, IClientInterface> setupForClientMode() { if (!startHalIfNecessary(true)) { Log.e(mTAG, "Failed to start HAL for client mode"); return Pair.create(SETUP_FAILURE_HAL, null); } - IClientInterface iClientInterface = mWificondControl.setupDriverForClientMode(ifaceName); + IClientInterface iClientInterface = mWificondControl.setupDriverForClientMode(); if (iClientInterface == null) { return Pair.create(SETUP_FAILURE_WIFICOND, null); } @@ -131,12 +130,12 @@ public class WifiNative { * @return Pair of <Integer, IApInterface> to indicate the status and the associated wificond * AP interface binder handler (will be null on failure). */ - public Pair<Integer, IApInterface> setupForSoftApMode(@NonNull String ifaceName) { + public Pair<Integer, IApInterface> setupForSoftApMode() { if (!startHalIfNecessary(false)) { Log.e(mTAG, "Failed to start HAL for AP mode"); return Pair.create(SETUP_FAILURE_HAL, null); } - IApInterface iApInterface = mWificondControl.setupDriverForSoftApMode(ifaceName); + IApInterface iApInterface = mWificondControl.setupDriverForSoftApMode(); if (iApInterface == null) { return Pair.create(SETUP_FAILURE_WIFICOND, null); } diff --git a/com/android/server/wifi/WifiStateMachine.java b/com/android/server/wifi/WifiStateMachine.java index 0c2cc32f..1f6cada7 100644 --- a/com/android/server/wifi/WifiStateMachine.java +++ b/com/android/server/wifi/WifiStateMachine.java @@ -4165,7 +4165,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss switch (message.what) { case CMD_START_SUPPLICANT: Pair<Integer, IClientInterface> statusAndInterface = - mWifiNative.setupForClientMode(mInterfaceName); + mWifiNative.setupForClientMode(); if (statusAndInterface.first == WifiNative.SETUP_SUCCESS) { mClientInterface = statusAndInterface.second; } else { @@ -6954,8 +6954,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss mMode = config.getTargetMode(); IApInterface apInterface = null; - Pair<Integer, IApInterface> statusAndInterface = - mWifiNative.setupForSoftApMode(mInterfaceName); + Pair<Integer, IApInterface> statusAndInterface = mWifiNative.setupForSoftApMode(); if (statusAndInterface.first == WifiNative.SETUP_SUCCESS) { apInterface = statusAndInterface.second; } else { diff --git a/com/android/server/wifi/WifiStateMachinePrime.java b/com/android/server/wifi/WifiStateMachinePrime.java index cd1948f1..20068849 100644 --- a/com/android/server/wifi/WifiStateMachinePrime.java +++ b/com/android/server/wifi/WifiStateMachinePrime.java @@ -290,8 +290,7 @@ public class WifiStateMachinePrime { } try { - mApInterface = mWificond.createApInterface( - mWifiInjector.getWifiNative().getInterfaceName()); + mApInterface = mWificond.createApInterface(); } catch (RemoteException e1) { } if (mApInterface == null) { diff --git a/com/android/server/wifi/WificondControl.java b/com/android/server/wifi/WificondControl.java index df4e785b..b6104a8c 100644 --- a/com/android/server/wifi/WificondControl.java +++ b/com/android/server/wifi/WificondControl.java @@ -16,7 +16,6 @@ package com.android.server.wifi; -import android.annotation.NonNull; import android.net.wifi.IApInterface; import android.net.wifi.IClientInterface; import android.net.wifi.IPnoScanEvent; @@ -134,7 +133,7 @@ public class WificondControl { * @return An IClientInterface as wificond client interface binder handler. * Returns null on failure. */ - public IClientInterface setupDriverForClientMode(@NonNull String ifaceName) { + public IClientInterface setupDriverForClientMode() { Log.d(TAG, "Setting up driver for client mode"); mWificond = mWifiInjector.makeWificond(); if (mWificond == null) { @@ -144,7 +143,7 @@ public class WificondControl { IClientInterface clientInterface = null; try { - clientInterface = mWificond.createClientInterface(ifaceName); + clientInterface = mWificond.createClientInterface(); } catch (RemoteException e1) { Log.e(TAG, "Failed to get IClientInterface due to remote exception"); return null; @@ -182,7 +181,7 @@ public class WificondControl { * @return An IApInterface as wificond Ap interface binder handler. * Returns null on failure. */ - public IApInterface setupDriverForSoftApMode(@NonNull String ifaceName) { + public IApInterface setupDriverForSoftApMode() { Log.d(TAG, "Setting up driver for soft ap mode"); mWificond = mWifiInjector.makeWificond(); if (mWificond == null) { @@ -192,7 +191,7 @@ public class WificondControl { IApInterface apInterface = null; try { - apInterface = mWificond.createApInterface(ifaceName); + apInterface = mWificond.createApInterface(); } catch (RemoteException e1) { Log.e(TAG, "Failed to get IApInterface due to remote exception"); return null; diff --git a/com/android/server/wifi/scanner/WificondScannerImpl.java b/com/android/server/wifi/scanner/WificondScannerImpl.java index 10fc8e3e..fb878e67 100644 --- a/com/android/server/wifi/scanner/WificondScannerImpl.java +++ b/com/android/server/wifi/scanner/WificondScannerImpl.java @@ -167,12 +167,12 @@ public class WificondScannerImpl extends WifiScannerImpl implements Handler.Call + ",eventHandler=" + eventHandler); return false; } + if (mPendingSingleScanSettings != null + || (mLastScanSettings != null && mLastScanSettings.singleScanActive)) { + Log.w(TAG, "A single scan is already running"); + return false; + } synchronized (mSettingsLock) { - if (mPendingSingleScanSettings != null - || (mLastScanSettings != null && mLastScanSettings.singleScanActive)) { - Log.w(TAG, "A single scan is already running"); - return false; - } mPendingSingleScanSettings = settings; mPendingSingleScanEventHandler = eventHandler; processPendingScans(); @@ -518,10 +518,8 @@ public class WificondScannerImpl extends WifiScannerImpl implements Handler.Call } private boolean isHwPnoScanRequired() { - synchronized (mSettingsLock) { - if (mPnoSettings == null) return false; - return isHwPnoScanRequired(mPnoSettings.isConnected); - } + if (mPnoSettings == null) return false; + return isHwPnoScanRequired(mPnoSettings.isConnected); } @Override diff --git a/com/android/server/wifi/util/InformationElementUtil.java b/com/android/server/wifi/util/InformationElementUtil.java index 14912b5f..c8f9ca34 100644 --- a/com/android/server/wifi/util/InformationElementUtil.java +++ b/com/android/server/wifi/util/InformationElementUtil.java @@ -247,10 +247,6 @@ public class InformationElementUtil { "Bad Interworking element length: " + ie.bytes.length); } - if (ie.bytes.length == 3 || ie.bytes.length == 9) { - int venueInfo = (int) ByteBufferReader.readInteger(data, ByteOrder.BIG_ENDIAN, 2); - } - if (ie.bytes.length == 7 || ie.bytes.length == 9) { hessid = ByteBufferReader.readInteger(data, ByteOrder.BIG_ENDIAN, 6); } diff --git a/com/android/server/wm/AppWindowToken.java b/com/android/server/wm/AppWindowToken.java index 5d034935..a1eeff84 100644 --- a/com/android/server/wm/AppWindowToken.java +++ b/com/android/server/wm/AppWindowToken.java @@ -823,7 +823,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree // For freeform windows, we can't freeze the bounds at the moment because this would make // the resizing unresponsive. - if (task == null || task.inFreeformWindowingMode()) { + if (task == null || task.inFreeformWorkspace()) { return false; } @@ -1310,7 +1310,8 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree // Notify the pinned stack upon all windows drawn. If there was an animation in // progress then this signal will resume that animation. - final TaskStack pinnedStack = mDisplayContent.getPinnedStack(); + final TaskStack pinnedStack = + mDisplayContent.getStack(WINDOWING_MODE_PINNED); if (pinnedStack != null) { pinnedStack.onAllWindowsDrawn(); } diff --git a/com/android/server/wm/BlackFrame.java b/com/android/server/wm/BlackFrame.java index d206554c..5c29a0aa 100644 --- a/com/android/server/wm/BlackFrame.java +++ b/com/android/server/wm/BlackFrame.java @@ -18,6 +18,7 @@ package com.android.server.wm; import static android.graphics.PixelFormat.OPAQUE; import static android.view.SurfaceControl.FX_SURFACE_DIM; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -50,8 +51,14 @@ public class BlackFrame { int w = r-l; int h = b-t; - surface = new SurfaceControl(session, "BlackSurface", - w, h, OPAQUE, FX_SURFACE_DIM | SurfaceControl.HIDDEN); + if (DEBUG_SURFACE_TRACE) { + surface = new WindowSurfaceController.SurfaceTrace(session, "BlackSurface(" + + l + ", " + t + ")", + w, h, OPAQUE, FX_SURFACE_DIM | SurfaceControl.HIDDEN); + } else { + surface = new SurfaceControl(session, "BlackSurface", + w, h, OPAQUE, FX_SURFACE_DIM | SurfaceControl.HIDDEN); + } surface.setAlpha(1); surface.setLayerStack(layerStack); diff --git a/com/android/server/wm/CircularDisplayMask.java b/com/android/server/wm/CircularDisplayMask.java index 85f468b5..ae415413 100644 --- a/com/android/server/wm/CircularDisplayMask.java +++ b/com/android/server/wm/CircularDisplayMask.java @@ -17,6 +17,7 @@ package com.android.server.wm; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -66,9 +67,14 @@ class CircularDisplayMask { SurfaceControl ctrl = null; try { - ctrl = new SurfaceControl(session, "CircularDisplayMask", mScreenSize.x, - mScreenSize.y, PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN); - + if (DEBUG_SURFACE_TRACE) { + ctrl = new WindowSurfaceController.SurfaceTrace(session, "CircularDisplayMask", + mScreenSize.x, mScreenSize.y, PixelFormat.TRANSLUCENT, + SurfaceControl.HIDDEN); + } else { + ctrl = new SurfaceControl(session, "CircularDisplayMask", mScreenSize.x, + mScreenSize.y, PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN); + } ctrl.setLayerStack(display.getLayerStack()); ctrl.setLayer(zOrder); ctrl.setPosition(0, 0); diff --git a/com/android/server/wm/ConfigurationContainer.java b/com/android/server/wm/ConfigurationContainer.java index 5bfea989..9e028d38 100644 --- a/com/android/server/wm/ConfigurationContainer.java +++ b/com/android/server/wm/ConfigurationContainer.java @@ -21,9 +21,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; -import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; -import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; @@ -184,11 +182,6 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> { return windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; } - public boolean inSplitScreenPrimaryWindowingMode() { - return mFullConfiguration.windowConfiguration.getWindowingMode() - == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; - } - /** * Returns true if this container can be put in either * {@link WindowConfiguration#WINDOWING_MODE_SPLIT_SCREEN_PRIMARY} or @@ -199,14 +192,6 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> { return mFullConfiguration.windowConfiguration.supportSplitScreenWindowingMode(); } - public boolean inPinnedWindowingMode() { - return mFullConfiguration.windowConfiguration.getWindowingMode() == WINDOWING_MODE_PINNED; - } - - public boolean inFreeformWindowingMode() { - return mFullConfiguration.windowConfiguration.getWindowingMode() == WINDOWING_MODE_FREEFORM; - } - /** Returns the activity type associated with the the configuration container. */ /*@WindowConfiguration.ActivityType*/ public int getActivityType() { diff --git a/com/android/server/wm/DimLayer.java b/com/android/server/wm/DimLayer.java index 48181d30..708973d5 100644 --- a/com/android/server/wm/DimLayer.java +++ b/com/android/server/wm/DimLayer.java @@ -17,6 +17,7 @@ package com.android.server.wm; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DIM_LAYER; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; @@ -104,10 +105,16 @@ public class DimLayer { private void constructSurface(WindowManagerService service) { service.openSurfaceTransaction(); try { - mDimSurface = new SurfaceControl(service.mFxSession, mName, + if (DEBUG_SURFACE_TRACE) { + mDimSurface = new WindowSurfaceController.SurfaceTrace(service.mFxSession, + "DimSurface", 16, 16, PixelFormat.OPAQUE, SurfaceControl.FX_SURFACE_DIM | SurfaceControl.HIDDEN); - + } else { + mDimSurface = new SurfaceControl(service.mFxSession, mName, + 16, 16, PixelFormat.OPAQUE, + SurfaceControl.FX_SURFACE_DIM | SurfaceControl.HIDDEN); + } if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(TAG, " DIM " + mDimSurface + ": CREATE"); mDimSurface.setLayerStack(mDisplayId); diff --git a/com/android/server/wm/DisplayContent.java b/com/android/server/wm/DisplayContent.java index 03fdc968..0e68a8f6 100644 --- a/com/android/server/wm/DisplayContent.java +++ b/com/android/server/wm/DisplayContent.java @@ -16,9 +16,10 @@ package com.android.server.wm; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; +import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; +import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; +import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; -import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; @@ -117,7 +118,7 @@ import static com.android.server.wm.proto.DisplayProto.WINDOW_CONTAINER; import android.annotation.CallSuper; import android.annotation.NonNull; -import android.content.pm.PackageManager; +import android.app.ActivityManager.StackId; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.graphics.Bitmap; @@ -296,6 +297,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo /** Window tokens that are in the process of exiting, but still on screen for animations. */ final ArrayList<WindowToken> mExitingTokens = new ArrayList<>(); + /** A special TaskStack with id==HOME_STACK_ID that moves to the bottom whenever any TaskStack + * (except a future lockscreen TaskStack) moves to the top. */ + private TaskStack mHomeStack = null; + /** Detect user tapping outside of current focused task bounds .*/ TaskTapPointerEventListener mTapDetector; @@ -974,8 +979,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } // In the presence of the PINNED stack or System Alert - // windows we unfortunately can not seamlessly rotate. - if (hasPinnedStack()) { + // windows we unforuntately can not seamlessly rotate. + if (getStackById(PINNED_STACK_ID) != null) { mayRotateSeamlessly = false; } for (int i = 0; i < mService.mSessions.size(); i++) { @@ -1446,31 +1451,20 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } TaskStack getHomeStack() { - return mTaskStackContainers.getHomeStack(); - } - - /** - * @return The primary split-screen stack, but only if it is visible, and {@code null} otherwise. - */ - TaskStack getSplitScreenPrimaryStackStack() { - TaskStack stack = mTaskStackContainers.getSplitScreenPrimaryStackStack(); - return (stack != null && stack.isVisible()) ? stack : null; - } - - /** - * Like {@link #getSplitScreenPrimaryStackStack}, but also returns the stack if it's currently - * not visible. - */ - TaskStack getSplitScreenPrimaryStackStackIgnoringVisibility() { - return mTaskStackContainers.getSplitScreenPrimaryStackStack(); - } - - TaskStack getPinnedStack() { - return mTaskStackContainers.getPinnedStack(); + if (mHomeStack == null && mDisplayId == DEFAULT_DISPLAY) { + Slog.e(TAG_WM, "getHomeStack: Returning null from this=" + this); + } + return mHomeStack; } - private boolean hasPinnedStack() { - return mTaskStackContainers.getPinnedStack() != null; + TaskStack getStackById(int stackId) { + for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) { + final TaskStack stack = mTaskStackContainers.get(i); + if (stack.mStackId == stackId) { + return stack; + } + } + return null; } /** @@ -1486,16 +1480,29 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo * activity type. Null is no compatible stack on the display. */ TaskStack getStack(int windowingMode, int activityType) { - return mTaskStackContainers.getStack(windowingMode, activityType); + for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) { + final TaskStack stack = mTaskStackContainers.get(i); + if (stack.isCompatible(windowingMode, activityType)) { + return stack; + } + } + return null; } @VisibleForTesting - TaskStack getTopStack() { - return mTaskStackContainers.getTopStack(); + int getStackCount() { + return mTaskStackContainers.size(); } - void onStackWindowingModeChanged(TaskStack stack) { - mTaskStackContainers.onStackWindowingModeChanged(stack); + @VisibleForTesting + int getStackPosition(int windowingMode, int activityType) { + for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) { + final TaskStack stack = mTaskStackContainers.get(i); + if (stack.isCompatible(windowingMode, activityType)) { + return i; + } + } + return -1; } @Override @@ -1516,8 +1523,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo * bounds were updated. */ void updateStackBoundsAfterConfigChange(@NonNull List<Integer> changedStackList) { - for (int i = mTaskStackContainers.getChildCount() - 1; i >= 0; --i) { - final TaskStack stack = mTaskStackContainers.getChildAt(i); + for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) { + final TaskStack stack = mTaskStackContainers.get(i); if (stack.updateBoundsAfterConfigChange()) { changedStackList.add(stack.mStackId); } @@ -1526,7 +1533,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo // If there was no pinned stack, we still need to notify the controller of the display info // update as a result of the config change. We do this here to consolidate the flow between // changes when there is and is not a stack. - if (!hasPinnedStack()) { + if (getStack(WINDOWING_MODE_PINNED) == null) { mPinnedStackControllerLocked.onDisplayInfoChanged(); } } @@ -1625,8 +1632,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo mDisplay.getDisplayInfo(mDisplayInfo); mDisplay.getMetrics(mDisplayMetrics); - for (int i = mTaskStackContainers.getChildCount() - 1; i >= 0; --i) { - mTaskStackContainers.getChildAt(i).updateDisplayInfo(null); + for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) { + mTaskStackContainers.get(i).updateDisplayInfo(null); } } @@ -1747,14 +1754,26 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo out.set(mContentRect); } - TaskStack createStack(int stackId, boolean onTop, StackWindowController controller) { + TaskStack addStackToDisplay(int stackId, boolean onTop, StackWindowController controller) { if (DEBUG_STACK) Slog.d(TAG_WM, "Create new stackId=" + stackId + " on displayId=" + mDisplayId); - final TaskStack stack = new TaskStack(mService, stackId, controller); - mTaskStackContainers.addStackToDisplay(stack, onTop); + TaskStack stack = getStackById(stackId); + if (stack != null) { + // It's already attached to the display...clear mDeferRemoval, set controller, and move + // stack to appropriate z-order on display as needed. + stack.mDeferRemoval = false; + stack.setController(controller); + // We're not moving the display to front when we're adding stacks, only when + // requested to change the position of stack explicitly. + mTaskStackContainers.positionChildAt(onTop ? POSITION_TOP : POSITION_BOTTOM, stack, + false /* includingParents */); + } else { + stack = new TaskStack(mService, stackId, controller); + mTaskStackContainers.addStackToDisplay(stack, onTop); + } - if (stack.inSplitScreenPrimaryWindowingMode()) { + if (stackId == DOCKED_STACK_ID) { mDividerControllerLocked.notifyDockedStackExistsChanged(true); } return stack; @@ -1771,7 +1790,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo + " to its current displayId=" + mDisplayId); } - prevDc.mTaskStackContainers.removeChild(stack); + prevDc.mTaskStackContainers.removeStackFromDisplay(stack); mTaskStackContainers.addStackToDisplay(stack, onTop); } @@ -1805,8 +1824,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } int taskIdFromPoint(int x, int y) { - for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final TaskStack stack = mTaskStackContainers.getChildAt(stackNdx); + for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) { + final TaskStack stack = mTaskStackContainers.get(stackNdx); final int taskId = stack.taskIdFromPoint(x, y); if (taskId != -1) { return taskId; @@ -1822,8 +1841,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo Task findTaskForResizePoint(int x, int y) { final int delta = dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics); mTmpTaskForResizePointSearchResult.reset(); - for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final TaskStack stack = mTaskStackContainers.getChildAt(stackNdx); + for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) { + final TaskStack stack = mTaskStackContainers.get(stackNdx); if (!stack.getWindowConfiguration().canResizeTask()) { return null; } @@ -1845,8 +1864,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo mTouchExcludeRegion.set(mBaseDisplayRect); final int delta = dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics); mTmpRect2.setEmpty(); - for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final TaskStack stack = mTaskStackContainers.getChildAt(stackNdx); + for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) { + final TaskStack stack = mTaskStackContainers.get(stackNdx); stack.setTouchExcludeRegion( focusedTask, delta, mTouchExcludeRegion, mContentRect, mTmpRect2); } @@ -1877,7 +1896,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo mTouchExcludeRegion.op(mTmpRegion, Region.Op.UNION); } // TODO(multi-display): Support docked stacks on secondary displays. - if (mDisplayId == DEFAULT_DISPLAY && getSplitScreenPrimaryStackStack() != null) { + if (mDisplayId == DEFAULT_DISPLAY && getDockedStackLocked() != null) { mDividerControllerLocked.getTouchRegion(mTmpRect); mTmpRegion.set(mTmpRect); mTouchExcludeRegion.op(mTmpRegion, Op.UNION); @@ -1894,8 +1913,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } private void resetAnimationBackgroundAnimator() { - for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - mTaskStackContainers.getChildAt(stackNdx).resetAnimationBackgroundAnimator(); + for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) { + mTaskStackContainers.get(stackNdx).resetAnimationBackgroundAnimator(); } } @@ -1966,8 +1985,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo float dividerAnimationTarget) { boolean updated = false; - for (int i = mTaskStackContainers.getChildCount() - 1; i >= 0; --i) { - final TaskStack stack = mTaskStackContainers.getChildAt(i); + for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) { + final TaskStack stack = mTaskStackContainers.get(i); if (stack == null || !stack.isAdjustedForIme()) { continue; } @@ -1995,8 +2014,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo boolean clearImeAdjustAnimation() { boolean changed = false; - for (int i = mTaskStackContainers.getChildCount() - 1; i >= 0; --i) { - final TaskStack stack = mTaskStackContainers.getChildAt(i); + for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) { + final TaskStack stack = mTaskStackContainers.get(i); if (stack != null && stack.isAdjustedForIme()) { stack.resetAdjustedForIme(true /* adjustBoundsNow */); changed = true; @@ -2006,8 +2025,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } void beginImeAdjustAnimation() { - for (int i = mTaskStackContainers.getChildCount() - 1; i >= 0; --i) { - final TaskStack stack = mTaskStackContainers.getChildAt(i); + for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) { + final TaskStack stack = mTaskStackContainers.get(i); if (stack.isVisible() && stack.isAdjustedForIme()) { stack.beginImeAdjustAnimation(); } @@ -2018,7 +2037,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo final WindowState imeWin = mService.mInputMethodWindow; final boolean imeVisible = imeWin != null && imeWin.isVisibleLw() && imeWin.isDisplayedLw() && !mDividerControllerLocked.isImeHideRequested(); - final boolean dockVisible = isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); + final boolean dockVisible = isStackVisible(DOCKED_STACK_ID); final TaskStack imeTargetStack = mService.getImeFocusStackLocked(); final int imeDockSide = (dockVisible && imeTargetStack != null) ? imeTargetStack.getDockSide() : DOCKED_INVALID; @@ -2036,8 +2055,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo // - If IME is not visible, divider is not moved and is normal width. if (imeVisible && dockVisible && (imeOnTop || imeOnBottom) && !dockMinimized) { - for (int i = mTaskStackContainers.getChildCount() - 1; i >= 0; --i) { - final TaskStack stack = mTaskStackContainers.getChildAt(i); + for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) { + final TaskStack stack = mTaskStackContainers.get(i); final boolean isDockedOnBottom = stack.getDockSide() == DOCKED_BOTTOM; if (stack.isVisible() && (imeOnBottom || isDockedOnBottom) && stack.inSplitScreenWindowingMode()) { @@ -2049,8 +2068,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo mDividerControllerLocked.setAdjustedForIme( imeOnBottom /*ime*/, true /*divider*/, true /*animate*/, imeWin, imeHeight); } else { - for (int i = mTaskStackContainers.getChildCount() - 1; i >= 0; --i) { - final TaskStack stack = mTaskStackContainers.getChildAt(i); + for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) { + final TaskStack stack = mTaskStackContainers.get(i); stack.resetAdjustedForIme(!dockVisible); } mDividerControllerLocked.setAdjustedForIme( @@ -2081,8 +2100,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } void prepareFreezingTaskBounds() { - for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final TaskStack stack = mTaskStackContainers.getChildAt(stackNdx); + for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) { + final TaskStack stack = mTaskStackContainers.get(stackNdx); stack.prepareFreezingTaskBounds(); } } @@ -2141,22 +2160,22 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo final long token = proto.start(fieldId); super.writeToProto(proto, WINDOW_CONTAINER); proto.write(ID, mDisplayId); - for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final TaskStack stack = mTaskStackContainers.getChildAt(stackNdx); + for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) { + final TaskStack stack = mTaskStackContainers.get(stackNdx); stack.writeToProto(proto, STACKS); } mDividerControllerLocked.writeToProto(proto, DOCKED_STACK_DIVIDER_CONTROLLER); mPinnedStackControllerLocked.writeToProto(proto, PINNED_STACK_CONTROLLER); - for (int i = mAboveAppWindowsContainers.getChildCount() - 1; i >= 0; --i) { - final WindowToken windowToken = mAboveAppWindowsContainers.getChildAt(i); + for (int i = mAboveAppWindowsContainers.size() - 1; i >= 0; --i) { + final WindowToken windowToken = mAboveAppWindowsContainers.get(i); windowToken.writeToProto(proto, ABOVE_APP_WINDOWS); } - for (int i = mBelowAppWindowsContainers.getChildCount() - 1; i >= 0; --i) { - final WindowToken windowToken = mBelowAppWindowsContainers.getChildAt(i); + for (int i = mBelowAppWindowsContainers.size() - 1; i >= 0; --i) { + final WindowToken windowToken = mBelowAppWindowsContainers.get(i); windowToken.writeToProto(proto, BELOW_APP_WINDOWS); } - for (int i = mImeWindowsContainers.getChildCount() - 1; i >= 0; --i) { - final WindowToken windowToken = mImeWindowsContainers.getChildAt(i); + for (int i = mImeWindowsContainers.size() - 1; i >= 0; --i) { + final WindowToken windowToken = mImeWindowsContainers.get(i); windowToken.writeToProto(proto, IME_WINDOWS); } proto.write(DPI, mBaseDisplayDensity); @@ -2202,8 +2221,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo pw.println(); pw.println(prefix + "Application tokens in top down Z order:"); - for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final TaskStack stack = mTaskStackContainers.getChildAt(stackNdx); + for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) { + final TaskStack stack = mTaskStackContainers.get(stackNdx); stack.dump(prefix + " ", pw); } @@ -2222,22 +2241,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo pw.println(); mDimLayerController.dump(prefix, pw); pw.println(); - - // Dump stack references - final TaskStack homeStack = getHomeStack(); - if (homeStack != null) { - pw.println(prefix + "homeStack=" + homeStack.getName()); - } - final TaskStack pinnedStack = getPinnedStack(); - if (pinnedStack != null) { - pw.println(prefix + "pinnedStack=" + pinnedStack.getName()); - } - final TaskStack splitScreenPrimaryStack = getSplitScreenPrimaryStackStack(); - if (splitScreenPrimaryStack != null) { - pw.println(prefix + "splitScreenPrimaryStack=" + splitScreenPrimaryStack.getName()); - } - - pw.println(); mDividerControllerLocked.dump(prefix, pw); pw.println(); mPinnedStackControllerLocked.dump(prefix, pw); @@ -2257,10 +2260,26 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo return "Display " + mDisplayId + " name=\"" + mDisplayInfo.name + "\""; } - /** Returns true if the stack in the windowing mode is visible. */ - boolean isStackVisible(int windowingMode) { - final TaskStack stack = getStack(windowingMode); - return stack != null && stack.isVisible(); + /** Checks if stack with provided id is visible on this display. */ + boolean isStackVisible(int stackId) { + final TaskStack stack = getStackById(stackId); + return (stack != null && stack.isVisible()); + } + + /** + * @return The docked stack, but only if it is visible, and {@code null} otherwise. + */ + TaskStack getDockedStackLocked() { + final TaskStack stack = getStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); + return (stack != null && stack.isVisible()) ? stack : null; + } + + /** + * Like {@link #getDockedStackLocked}, but also returns the docked stack if it's currently not + * visible. + */ + TaskStack getDockedStackIgnoringVisibility() { + return getStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); } /** Find the visible, touch-deliverable window under the given point */ @@ -3339,6 +3358,14 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo */ static class DisplayChildWindowContainer<E extends WindowContainer> extends WindowContainer<E> { + int size() { + return mChildren.size(); + } + + E get(int index) { + return mChildren.get(index); + } + @Override boolean fillsParent() { return true; @@ -3356,108 +3383,25 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo */ private final class TaskStackContainers extends DisplayChildWindowContainer<TaskStack> { - // Cached reference to some special stacks we tend to get a lot so we don't need to loop - // through the list to find them. - private TaskStack mHomeStack = null; - private TaskStack mPinnedStack = null; - private TaskStack mSplitScreenPrimaryStack = null; - - /** - * Returns the topmost stack on the display that is compatible with the input windowing mode - * and activity type. Null is no compatible stack on the display. - */ - TaskStack getStack(int windowingMode, int activityType) { - if (activityType == ACTIVITY_TYPE_HOME) { - return mHomeStack; - } - if (windowingMode == WINDOWING_MODE_PINNED) { - return mPinnedStack; - } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { - return mSplitScreenPrimaryStack; - } - for (int i = mTaskStackContainers.getChildCount() - 1; i >= 0; --i) { - final TaskStack stack = mTaskStackContainers.getChildAt(i); - if (stack.isCompatible(windowingMode, activityType)) { - return stack; - } - } - return null; - } - - @VisibleForTesting - TaskStack getTopStack() { - return mTaskStackContainers.getChildCount() > 0 - ? mTaskStackContainers.getChildAt(mTaskStackContainers.getChildCount() - 1) : null; - } - - TaskStack getHomeStack() { - if (mHomeStack == null && mDisplayId == DEFAULT_DISPLAY) { - Slog.e(TAG_WM, "getHomeStack: Returning null from this=" + this); - } - return mHomeStack; - } - - TaskStack getPinnedStack() { - return mPinnedStack; - } - - TaskStack getSplitScreenPrimaryStackStack() { - return mSplitScreenPrimaryStack; - } - /** * Adds the stack to this container. - * @see DisplayContent#createStack(int, boolean, StackWindowController) + * @see WindowManagerService#addStackToDisplay(int, int, boolean) */ void addStackToDisplay(TaskStack stack, boolean onTop) { - addStackReferenceIfNeeded(stack); - addChild(stack, onTop); - stack.onDisplayChanged(DisplayContent.this); - } - - void onStackWindowingModeChanged(TaskStack stack) { - removeStackReferenceIfNeeded(stack); - addStackReferenceIfNeeded(stack); - if (stack == mPinnedStack && getTopStack() != stack) { - // Looks like this stack changed windowing mode to pinned. Move it to the top. - positionChildAt(POSITION_TOP, stack, false /* includingParents */); - } - } - - private void addStackReferenceIfNeeded(TaskStack stack) { if (stack.isActivityTypeHome()) { if (mHomeStack != null) { - throw new IllegalArgumentException("addStackReferenceIfNeeded: home stack=" - + mHomeStack + " already exist on display=" + this + " stack=" + stack); + throw new IllegalArgumentException("attachStack: HOME_STACK_ID (0) not first."); } mHomeStack = stack; } - final int windowingMode = stack.getWindowingMode(); - if (windowingMode == WINDOWING_MODE_PINNED) { - if (mPinnedStack != null) { - throw new IllegalArgumentException("addStackReferenceIfNeeded: pinned stack=" - + mPinnedStack + " already exist on display=" + this - + " stack=" + stack); - } - mPinnedStack = stack; - } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { - if (mSplitScreenPrimaryStack != null) { - throw new IllegalArgumentException("addStackReferenceIfNeeded:" - + " split-screen-primary" + " stack=" + mSplitScreenPrimaryStack - + " already exist on display=" + this + " stack=" + stack); - } - mSplitScreenPrimaryStack = stack; - } + addChild(stack, onTop); + stack.onDisplayChanged(DisplayContent.this); } - private void removeStackReferenceIfNeeded(TaskStack stack) { - if (stack == mHomeStack) { - mHomeStack = null; - } else if (stack == mPinnedStack) { - mPinnedStack = null; - } else if (stack == mSplitScreenPrimaryStack) { - mSplitScreenPrimaryStack = null; - } + /** Removes the stack from its container and prepare for changing the parent. */ + void removeStackFromDisplay(TaskStack stack) { + removeChild(stack); + stack.onRemovedFromDisplay(); } private void addChild(TaskStack stack, boolean toTop) { @@ -3467,11 +3411,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo setLayoutNeeded(); } - @Override - protected void removeChild(TaskStack stack) { - super.removeChild(stack); - removeStackReferenceIfNeeded(stack); - } @Override boolean isOnTop() { @@ -3514,7 +3453,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo : requestedPosition >= topChildPosition; int targetPosition = requestedPosition; - if (toTop && stack.getWindowingMode() != WINDOWING_MODE_PINNED && hasPinnedStack()) { + if (toTop && stack.getWindowingMode() != WINDOWING_MODE_PINNED + && getStack(WINDOWING_MODE_PINNED) != null) { // The pinned stack is always the top most stack (always-on-top) when it is present. TaskStack topStack = mChildren.get(topChildPosition); if (topStack.getWindowingMode() != WINDOWING_MODE_PINNED) { @@ -3616,8 +3556,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo @Override int getOrientation() { - if (isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) - || isStackVisible(WINDOWING_MODE_FREEFORM)) { + if (isStackVisible(DOCKED_STACK_ID) || isStackVisible(FREEFORM_WORKSPACE_STACK_ID)) { // Apps and their containers are not allowed to specify an orientation while the // docked or freeform stack is visible...except for the home stack/task if the // docked stack is minimized and it actually set something. @@ -3632,16 +3571,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } final int orientation = super.getOrientation(); - boolean isCar = mService.mContext.getPackageManager().hasSystemFeature( - PackageManager.FEATURE_AUTOMOTIVE); - if (isCar) { - // In a car, you cannot physically rotate the screen, so it doesn't make sense to - // allow anything but the default orientation. - if (DEBUG_ORIENTATION) Slog.v(TAG_WM, - "Forcing UNSPECIFIED orientation in car. Ignoring " + orientation); - return SCREEN_ORIENTATION_UNSPECIFIED; - } - if (orientation != SCREEN_ORIENTATION_UNSET && orientation != SCREEN_ORIENTATION_BEHIND) { if (DEBUG_ORIENTATION) Slog.v(TAG_WM, diff --git a/com/android/server/wm/DockedStackDividerController.java b/com/android/server/wm/DockedStackDividerController.java index 52526e2f..6f441b98 100644 --- a/com/android/server/wm/DockedStackDividerController.java +++ b/com/android/server/wm/DockedStackDividerController.java @@ -16,6 +16,9 @@ package com.android.server.wm; +import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; +import static android.app.ActivityManager.StackId.INVALID_STACK_ID; +import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; @@ -319,7 +322,7 @@ public class DockedStackDividerController implements DimLayerUser { if (mWindow == null) { return; } - TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackStackIgnoringVisibility(); + TaskStack stack = mDisplayContent.getDockedStackIgnoringVisibility(); // If the stack is invisible, we policy force hide it in WindowAnimator.shouldForceHide final boolean visible = stack != null; @@ -359,7 +362,7 @@ public class DockedStackDividerController implements DimLayerUser { } void positionDockedStackedDivider(Rect frame) { - TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackStack(); + TaskStack stack = mDisplayContent.getDockedStackLocked(); if (stack == null) { // Unfortunately we might end up with still having a divider, even though the underlying // stack was already removed. This is because we are on AM thread and the removal of the @@ -456,7 +459,7 @@ public class DockedStackDividerController implements DimLayerUser { long animDuration = 0; if (animate) { final TaskStack stack = - mDisplayContent.getSplitScreenPrimaryStackStackIgnoringVisibility(); + mDisplayContent.getStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); final long transitionDuration = isAnimationMaximizing() ? mService.mAppTransition.getLastClipRevealTransitionDuration() : DEFAULT_APP_TRANSITION_DURATION; @@ -510,8 +513,7 @@ public class DockedStackDividerController implements DimLayerUser { void registerDockedStackListener(IDockedStackListener listener) { mDockedStackListeners.register(listener); notifyDockedDividerVisibilityChanged(wasVisible()); - notifyDockedStackExistsChanged( - mDisplayContent.getSplitScreenPrimaryStackStackIgnoringVisibility() != null); + notifyDockedStackExistsChanged(mDisplayContent.getDockedStackIgnoringVisibility() != null); notifyDockedStackMinimizedChanged(mMinimizedDock, false /* animate */, isHomeStackResizable()); notifyAdjustedForImeChanged(mAdjustedForIme, 0 /* animDuration */); @@ -530,7 +532,7 @@ public class DockedStackDividerController implements DimLayerUser { final TaskStack stack = targetWindowingMode != WINDOWING_MODE_UNDEFINED ? mDisplayContent.getStack(targetWindowingMode) : null; - final TaskStack dockedStack = mDisplayContent.getSplitScreenPrimaryStackStack(); + final TaskStack dockedStack = mDisplayContent.getDockedStackLocked(); boolean visibleAndValid = visible && stack != null && dockedStack != null; if (visibleAndValid) { stack.getDimBounds(mTmpRect); @@ -586,7 +588,7 @@ public class DockedStackDividerController implements DimLayerUser { private boolean containsAppInDockedStack(ArraySet<AppWindowToken> apps) { for (int i = apps.size() - 1; i >= 0; i--) { final AppWindowToken token = apps.valueAt(i); - if (token.getTask() != null && token.inSplitScreenPrimaryWindowingMode()) { + if (token.getTask() != null && token.getTask().mStack.mStackId == DOCKED_STACK_ID) { return true; } } @@ -598,7 +600,7 @@ public class DockedStackDividerController implements DimLayerUser { } private void checkMinimizeChanged(boolean animate) { - if (mDisplayContent.getSplitScreenPrimaryStackStackIgnoringVisibility() == null) { + if (mDisplayContent.getDockedStackIgnoringVisibility() == null) { return; } final TaskStack homeStack = mDisplayContent.getHomeStack(); @@ -760,7 +762,7 @@ public class DockedStackDividerController implements DimLayerUser { } private boolean setMinimizedDockedStack(boolean minimized) { - final TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackStackIgnoringVisibility(); + final TaskStack stack = mDisplayContent.getDockedStackIgnoringVisibility(); notifyDockedStackMinimizedChanged(minimized, false /* animate */, isHomeStackResizable()); return stack != null && stack.setAdjustedForMinimizedDock(minimized ? 1f : 0f); } @@ -811,7 +813,8 @@ public class DockedStackDividerController implements DimLayerUser { } private boolean animateForMinimizedDockedStack(long now) { - final TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackStackIgnoringVisibility(); + final TaskStack stack = + mDisplayContent.getStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); if (!mAnimationStarted) { mAnimationStarted = true; mAnimationStartTime = now; diff --git a/com/android/server/wm/EmulatorDisplayOverlay.java b/com/android/server/wm/EmulatorDisplayOverlay.java index 19bd8e9d..3186d3dc 100644 --- a/com/android/server/wm/EmulatorDisplayOverlay.java +++ b/com/android/server/wm/EmulatorDisplayOverlay.java @@ -17,6 +17,7 @@ package com.android.server.wm; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -56,8 +57,14 @@ class EmulatorDisplayOverlay { SurfaceControl ctrl = null; try { - ctrl = new SurfaceControl(session, "EmulatorDisplayOverlay", mScreenSize.x, - mScreenSize.y, PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN); + if (DEBUG_SURFACE_TRACE) { + ctrl = new WindowSurfaceController.SurfaceTrace(session, "EmulatorDisplayOverlay", + mScreenSize.x, mScreenSize.y, PixelFormat.TRANSLUCENT, + SurfaceControl.HIDDEN); + } else { + ctrl = new SurfaceControl(session, "EmulatorDisplayOverlay", mScreenSize.x, + mScreenSize.y, PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN); + } ctrl.setLayerStack(display.getLayerStack()); ctrl.setLayer(zOrder); ctrl.setPosition(0, 0); diff --git a/com/android/server/wm/InputMonitor.java b/com/android/server/wm/InputMonitor.java index 238cb9f1..5057f632 100644 --- a/com/android/server/wm/InputMonitor.java +++ b/com/android/server/wm/InputMonitor.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION; import static android.view.WindowManager.INPUT_CONSUMER_PIP; @@ -649,7 +650,7 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks { final boolean hasFocus = w == mInputFocus; final boolean isVisible = w.isVisibleLw(); - if (w.inPinnedWindowingMode()) { + if (w.getStackId() == PINNED_STACK_ID) { if (mAddPipInputConsumerHandle && (inputWindowHandle.layer <= pipInputConsumer.mWindowHandle.layer)) { // Update the bounds of the Pip input consumer to match the Pinned stack diff --git a/com/android/server/wm/PinnedStackController.java b/com/android/server/wm/PinnedStackController.java index 365366ad..ef31598f 100644 --- a/com/android/server/wm/PinnedStackController.java +++ b/com/android/server/wm/PinnedStackController.java @@ -417,7 +417,8 @@ class PinnedStackController { false /* useCurrentMinEdgeSize */); } final Rect animatingBounds = mTmpAnimatingBoundsRect; - final TaskStack pinnedStack = mDisplayContent.getPinnedStack(); + final TaskStack pinnedStack = + mDisplayContent.getStack(WINDOWING_MODE_PINNED); if (pinnedStack != null) { pinnedStack.getAnimationOrCurrentBounds(animatingBounds); } else { diff --git a/com/android/server/wm/RootWindowContainer.java b/com/android/server/wm/RootWindowContainer.java index fd574709..7832f5de 100644 --- a/com/android/server/wm/RootWindowContainer.java +++ b/com/android/server/wm/RootWindowContainer.java @@ -411,6 +411,17 @@ class RootWindowContainer extends WindowContainer<DisplayContent> { } } + TaskStack getStackById(int stackId) { + for (int i = mChildren.size() - 1; i >= 0; i--) { + final DisplayContent dc = mChildren.get(i); + final TaskStack stack = dc.getStackById(stackId); + if (stack != null) { + return stack; + } + } + return null; + } + TaskStack getStack(int windowingMode, int activityType) { for (int i = mChildren.size() - 1; i >= 0; i--) { final DisplayContent dc = mChildren.get(i); diff --git a/com/android/server/wm/ScreenRotationAnimation.java b/com/android/server/wm/ScreenRotationAnimation.java index 8e99be83..d5b6d246 100644 --- a/com/android/server/wm/ScreenRotationAnimation.java +++ b/com/android/server/wm/ScreenRotationAnimation.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS; @@ -23,6 +24,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER; import static com.android.server.wm.WindowStateAnimator.WINDOW_FREEZE_LAYER; +import static com.android.server.wm.WindowSurfaceController.SurfaceTrace; import static com.android.server.wm.proto.ScreenRotationAnimationProto.ANIMATION_RUNNING; import static com.android.server.wm.proto.ScreenRotationAnimationProto.STARTED; @@ -274,10 +276,17 @@ class ScreenRotationAnimation { flags |= SurfaceControl.SECURE; } - mSurfaceControl = new SurfaceControl(session, "ScreenshotSurface", - mWidth, mHeight, - PixelFormat.OPAQUE, flags); - + if (DEBUG_SURFACE_TRACE) { + mSurfaceControl = new SurfaceTrace(session, "ScreenshotSurface", + mWidth, mHeight, + PixelFormat.OPAQUE, flags); + Slog.w(TAG, "ScreenRotationAnimation ctor: displayOffset=" + + mOriginalDisplayRect.toShortString()); + } else { + mSurfaceControl = new SurfaceControl(session, "ScreenshotSurface", + mWidth, mHeight, + PixelFormat.OPAQUE, flags); + } // capture a screenshot into the surface we just created Surface sur = new Surface(); sur.copyFrom(mSurfaceControl); diff --git a/com/android/server/wm/StackWindowController.java b/com/android/server/wm/StackWindowController.java index 1fda832d..c0a4cb72 100644 --- a/com/android/server/wm/StackWindowController.java +++ b/com/android/server/wm/StackWindowController.java @@ -16,6 +16,8 @@ package com.android.server.wm; +import static android.app.ActivityManager.StackId.PINNED_STACK_ID; + import android.content.res.Configuration; import android.graphics.Rect; import android.os.Handler; @@ -43,7 +45,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; public class StackWindowController extends WindowContainerController<TaskStack, StackWindowListener> { - private final int mStackId; + final int mStackId; private final H mHandler; @@ -72,7 +74,7 @@ public class StackWindowController + " to unknown displayId=" + displayId); } - dc.createStack(stackId, onTop, this); + dc.addStackToDisplay(stackId, onTop, this); getRawBounds(outBounds); } } @@ -278,9 +280,8 @@ public class StackWindowController if (stack.getWindowConfiguration().tasksAreFloating()) { // Floating tasks should not be resized to the screen's bounds. - if (stack.inPinnedWindowingMode() - && bounds.width() == mTmpDisplayBounds.width() - && bounds.height() == mTmpDisplayBounds.height()) { + if (mStackId == PINNED_STACK_ID && bounds.width() == mTmpDisplayBounds.width() && + bounds.height() == mTmpDisplayBounds.height()) { // If the bounds we are animating is the same as the fullscreen stack // dimensions, then apply the same inset calculations that we normally do for // the fullscreen stack, without intersecting it with the display bounds diff --git a/com/android/server/wm/Task.java b/com/android/server/wm/Task.java index 891d637a..7e8d1308 100644 --- a/com/android/server/wm/Task.java +++ b/com/android/server/wm/Task.java @@ -17,6 +17,8 @@ package com.android.server.wm; import static android.app.ActivityManager.RESIZE_MODE_SYSTEM_SCREEN_ROTATION; +import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; +import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY; import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY; import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION; @@ -211,7 +213,7 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU // then we want to preserve our insets so that there will not // be a jump in the area covered by system decorations. We rely // on the pinned animation to later unset this value. - if (stack.inPinnedWindowingMode()) { + if (stack.mStackId == PINNED_STACK_ID) { mPreserveNonFloatingState = true; } else { mPreserveNonFloatingState = false; @@ -419,7 +421,7 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU return mFillsParent || !inSplitScreenSecondaryWindowingMode() || displayContent == null - || displayContent.getSplitScreenPrimaryStackStackIgnoringVisibility() != null; + || displayContent.getDockedStackIgnoringVisibility() != null; } /** Original bounds of the task if applicable, otherwise fullscreen rect. */ @@ -490,7 +492,7 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU final boolean dockedResizing = displayContent != null && displayContent.mDividerControllerLocked.isResizing(); if (useCurrentBounds()) { - if (inFreeformWindowingMode() && getMaxVisibleBounds(out)) { + if (inFreeformWorkspace() && getMaxVisibleBounds(out)) { return; } @@ -596,6 +598,14 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU return (tokensCount != 0) && mChildren.get(tokensCount - 1).mShowForAllUsers; } + boolean inFreeformWorkspace() { + return mStack != null && mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID; + } + + boolean inPinnedWorkspace() { + return mStack != null && mStack.mStackId == PINNED_STACK_ID; + } + /** * When we are in a floating stack (Freeform, Pinned, ...) we calculate * insets differently. However if we are animating to the fullscreen stack diff --git a/com/android/server/wm/TaskPositioner.java b/com/android/server/wm/TaskPositioner.java index 87de1514..c58212cd 100644 --- a/com/android/server/wm/TaskPositioner.java +++ b/com/android/server/wm/TaskPositioner.java @@ -20,6 +20,7 @@ import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIG import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; import static android.app.ActivityManager.RESIZE_MODE_USER; import static android.app.ActivityManager.RESIZE_MODE_USER_FORCED; +import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION; @@ -648,7 +649,7 @@ class TaskPositioner implements DimLayer.DimLayerUser { * shouldn't be shown. */ private int getDimSide(int x) { - if (!mTask.mStack.inFreeformWindowingMode() + if (mTask.mStack.mStackId != FREEFORM_WORKSPACE_STACK_ID || !mTask.mStack.fillsParent() || mTask.mStack.getConfiguration().orientation != ORIENTATION_LANDSCAPE) { return CTRL_NONE; diff --git a/com/android/server/wm/TaskSnapshotController.java b/com/android/server/wm/TaskSnapshotController.java index 54ef0651..bff24f6e 100644 --- a/com/android/server/wm/TaskSnapshotController.java +++ b/com/android/server/wm/TaskSnapshotController.java @@ -294,9 +294,7 @@ class TaskSnapshotController { decorPainter.drawDecors(c, null /* statusBarExcludeFrame */); node.end(c); final Bitmap hwBitmap = ThreadedRenderer.createHardwareBitmap(node, width, height); - if (hwBitmap == null) { - return null; - } + return new TaskSnapshot(hwBitmap.createGraphicBufferHandle(), topChild.getConfiguration().orientation, mainWindow.mStableInsets, ActivityManager.isLowRamDeviceStatic() /* reduced */, 1.0f /* scale */); diff --git a/com/android/server/wm/TaskStack.java b/com/android/server/wm/TaskStack.java index d170b6f2..65278837 100644 --- a/com/android/server/wm/TaskStack.java +++ b/com/android/server/wm/TaskStack.java @@ -18,6 +18,8 @@ package com.android.server.wm; import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT; +import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; +import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; @@ -294,7 +296,7 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye if (mFillsParent || !inSplitScreenSecondaryWindowingMode() || mDisplayContent == null - || mDisplayContent.getSplitScreenPrimaryStackStack() != null) { + || mDisplayContent.getDockedStackLocked() != null) { return true; } return false; @@ -407,7 +409,7 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye return false; } - if (inPinnedWindowingMode()) { + if (mStackId == PINNED_STACK_ID) { getAnimationOrCurrentBounds(mTmpRect2); boolean updated = mDisplayContent.mPinnedStackControllerLocked.onTaskStackBoundsChanged( mTmpRect2, mTmpRect3); @@ -441,19 +443,21 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye mTmpRect2.set(mBounds); mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2); - if (inSplitScreenPrimaryWindowingMode()) { - repositionDockedStackAfterRotation(mTmpRect2); - snapDockedStackAfterRotation(mTmpRect2); - final int newDockSide = getDockSide(mTmpRect2); - - // Update the dock create mode and clear the dock create bounds, these - // might change after a rotation and the original values will be invalid. - mService.setDockedStackCreateStateLocked( - (newDockSide == DOCKED_LEFT || newDockSide == DOCKED_TOP) - ? DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT - : DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT, - null); - mDisplayContent.getDockedDividerController().notifyDockSideChanged(newDockSide); + switch (mStackId) { + case DOCKED_STACK_ID: + repositionDockedStackAfterRotation(mTmpRect2); + snapDockedStackAfterRotation(mTmpRect2); + final int newDockSide = getDockSide(mTmpRect2); + + // Update the dock create mode and clear the dock create bounds, these + // might change after a rotation and the original values will be invalid. + mService.setDockedStackCreateStateLocked( + (newDockSide == DOCKED_LEFT || newDockSide == DOCKED_TOP) + ? DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT + : DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT, + null); + mDisplayContent.getDockedDividerController().notifyDockSideChanged(newDockSide); + break; } mBoundsAfterRotation.set(mTmpRect2); @@ -673,16 +677,6 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye } } - @Override - public void onConfigurationChanged(Configuration newParentConfig) { - final int prevWindowingMode = getWindowingMode(); - super.onConfigurationChanged(newParentConfig); - if (mDisplayContent != null && prevWindowingMode != getWindowingMode()) { - mDisplayContent.onStackWindowingModeChanged(this); - } - } - - @Override void onDisplayChanged(DisplayContent dc) { if (mDisplayContent != null) { throw new IllegalStateException("onDisplayChanged: Already attached"); @@ -693,8 +687,8 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye "animation background stackId=" + mStackId); Rect bounds = null; - final TaskStack dockedStack = dc.getSplitScreenPrimaryStackStackIgnoringVisibility(); - if (inSplitScreenPrimaryWindowingMode() + final TaskStack dockedStack = dc.getDockedStackIgnoringVisibility(); + if (mStackId == DOCKED_STACK_ID || (dockedStack != null && inSplitScreenSecondaryWindowingMode() && !dockedStack.fillsParent())) { // The existence of a docked stack affects the size of other static stack created since @@ -709,10 +703,10 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye } final boolean dockedOnTopOrLeft = mService.mDockedStackCreateMode == DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; - getStackDockedModeBounds(mTmpRect, bounds, mTmpRect2, + getStackDockedModeBounds(mTmpRect, bounds, mStackId, mTmpRect2, mDisplayContent.mDividerControllerLocked.getContentWidth(), dockedOnTopOrLeft); - } else if (inPinnedWindowingMode()) { + } else if (mStackId == PINNED_STACK_ID) { // Update the bounds based on any changes to the display info getAnimationOrCurrentBounds(mTmpRect2); boolean updated = mDisplayContent.mPinnedStackControllerLocked.onTaskStackBoundsChanged( @@ -772,8 +766,7 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye return; } - final TaskStack dockedStack = - mDisplayContent.getSplitScreenPrimaryStackStackIgnoringVisibility(); + final TaskStack dockedStack = mDisplayContent.getDockedStackIgnoringVisibility(); if (dockedStack == null) { // Not sure why you are calling this method when there is no docked stack... throw new IllegalStateException( @@ -798,7 +791,7 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye mDisplayContent.getLogicalDisplayRect(mTmpRect); dockedStack.getRawBounds(mTmpRect2); final boolean dockedOnTopOrLeft = dockedSide == DOCKED_TOP || dockedSide == DOCKED_LEFT; - getStackDockedModeBounds(mTmpRect, outStackBounds, mTmpRect2, + getStackDockedModeBounds(mTmpRect, outStackBounds, mStackId, mTmpRect2, mDisplayContent.mDividerControllerLocked.getContentWidth(), dockedOnTopOrLeft); } @@ -807,15 +800,16 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye * Outputs the bounds a stack should be given the presence of a docked stack on the display. * @param displayRect The bounds of the display the docked stack is on. * @param outBounds Output bounds that should be used for the stack. + * @param stackId Id of stack we are calculating the bounds for. * @param dockedBounds Bounds of the docked stack. * @param dockDividerWidth We need to know the width of the divider make to the output bounds * close to the side of the dock. * @param dockOnTopOrLeft If the docked stack is on the top or left side of the screen. */ private void getStackDockedModeBounds( - Rect displayRect, Rect outBounds, Rect dockedBounds, int dockDividerWidth, + Rect displayRect, Rect outBounds, int stackId, Rect dockedBounds, int dockDividerWidth, boolean dockOnTopOrLeft) { - final boolean dockedStack = inSplitScreenPrimaryWindowingMode(); + final boolean dockedStack = stackId == DOCKED_STACK_ID; final boolean splitHorizontally = displayRect.width() > displayRect.height(); outBounds.set(displayRect); @@ -872,7 +866,7 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye } void resetDockedStackToMiddle() { - if (inSplitScreenPrimaryWindowingMode()) { + if (mStackId != DOCKED_STACK_ID) { throw new IllegalStateException("Not a docked stack=" + this); } @@ -900,12 +894,17 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye } @Override - void onParentSet() { - if (getParent() != null || mDisplayContent == null) { - return; - } + void removeImmediately() { + super.removeImmediately(); + + onRemovedFromDisplay(); + } - // Looks like the stack was removed from the display. Go ahead and clean things up. + /** + * Removes the stack it from its current parent, so it can be either destroyed completely or + * re-parented. + */ + void onRemovedFromDisplay() { mDisplayContent.mDimLayerController.removeDimLayerUser(this); EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId); @@ -914,7 +913,7 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye mAnimationBackgroundSurface = null; } - if (inSplitScreenPrimaryWindowingMode()) { + if (mStackId == DOCKED_STACK_ID) { mDisplayContent.mDividerControllerLocked.notifyDockedStackExistsChanged(false); } @@ -1036,8 +1035,8 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye } boolean shouldIgnoreInput() { - return isAdjustedForMinimizedDockedStack() || - (inSplitScreenPrimaryWindowingMode() && isMinimizedDockAndHomeStackResizable()); + return isAdjustedForMinimizedDockedStack() || mStackId == DOCKED_STACK_ID && + isMinimizedDockAndHomeStackResizable(); } /** @@ -1472,7 +1471,7 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye postExclude.set(mTmpRect); } - final boolean isFreeformed = task.inFreeformWindowingMode(); + final boolean isFreeformed = task.inFreeformWorkspace(); if (task != focusedTask || isFreeformed) { if (isFreeformed) { // If the task is freeformed, enlarge the area to account for outside @@ -1530,7 +1529,7 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye } } - if (inPinnedWindowingMode()) { + if (mStackId == PINNED_STACK_ID) { try { mService.mActivityManager.notifyPinnedStackAnimationStarted(); } catch (RemoteException e) { @@ -1562,7 +1561,7 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye mService.requestTraversal(); } - if (inPinnedWindowingMode()) { + if (mStackId == PINNED_STACK_ID) { // Update to the final bounds if requested. This is done here instead of in the bounds // animator to allow us to coordinate this after we notify the PiP mode changed @@ -1596,7 +1595,7 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye * bounds and we have a deferred PiP mode changed callback set with the animation. */ public boolean deferScheduleMultiWindowModeChanged() { - if (inPinnedWindowingMode()) { + if (mStackId == PINNED_STACK_ID) { return (mBoundsAnimatingRequested || mBoundsAnimating); } return false; diff --git a/com/android/server/wm/WallpaperController.java b/com/android/server/wm/WallpaperController.java index 629cc868..7213c951 100644 --- a/com/android/server/wm/WallpaperController.java +++ b/com/android/server/wm/WallpaperController.java @@ -18,7 +18,7 @@ package com.android.server.wm; import com.android.internal.util.ToBooleanFunction; -import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; +import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; @@ -447,7 +447,7 @@ class WallpaperController { private void findWallpaperTarget(DisplayContent dc) { mFindResults.reset(); - if (dc.isStackVisible(WINDOWING_MODE_FREEFORM)) { + if (dc.isStackVisible(FREEFORM_WORKSPACE_STACK_ID)) { // In freeform mode we set the wallpaper as its own target, so we don't need an // additional window to make it visible. mFindResults.setUseTopWallpaperAsTarget(true); diff --git a/com/android/server/wm/WindowContainer.java b/com/android/server/wm/WindowContainer.java index 1b0825e5..40923c82 100644 --- a/com/android/server/wm/WindowContainer.java +++ b/com/android/server/wm/WindowContainer.java @@ -73,12 +73,12 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< @Override - protected int getChildCount() { + final protected int getChildCount() { return mChildren.size(); } @Override - protected E getChildAt(int index) { + final protected E getChildAt(int index) { return mChildren.get(index); } diff --git a/com/android/server/wm/WindowManagerDebugConfig.java b/com/android/server/wm/WindowManagerDebugConfig.java index 9d9805ab..6d5673e2 100644 --- a/com/android/server/wm/WindowManagerDebugConfig.java +++ b/com/android/server/wm/WindowManagerDebugConfig.java @@ -60,6 +60,7 @@ public class WindowManagerDebugConfig { static final boolean DEBUG_SCREENSHOT = false; static final boolean DEBUG_BOOT = false; static final boolean DEBUG_LAYOUT_REPEATS = false; + static final boolean DEBUG_SURFACE_TRACE = false; static final boolean DEBUG_WINDOW_TRACE = false; static final boolean DEBUG_TASK_MOVEMENT = false; static final boolean DEBUG_TASK_POSITIONING = false; diff --git a/com/android/server/wm/WindowManagerService.java b/com/android/server/wm/WindowManagerService.java index b133bd45..1fb21887 100644 --- a/com/android/server/wm/WindowManagerService.java +++ b/com/android/server/wm/WindowManagerService.java @@ -2384,7 +2384,7 @@ public class WindowManagerService extends IWindowManager.Stub final Rect insets = new Rect(); final Rect stableInsets = new Rect(); Rect surfaceInsets = null; - final boolean freeform = win != null && win.inFreeformWindowingMode(); + final boolean freeform = win != null && win.inFreeformWorkspace(); if (win != null) { // Containing frame will usually cover the whole screen, including dialog windows. // For freeform workspace windows it will not cover the whole screen and it also @@ -2794,7 +2794,7 @@ public class WindowManagerService extends IWindowManager.Stub for (final WindowState win : mWindowMap.values()) { final Task task = win.getTask(); if (task != null && mTmpTaskIds.get(task.mTaskId, -1) != -1 - && task.inFreeformWindowingMode()) { + && task.inFreeformWorkspace()) { final AppWindowToken appToken = win.mAppToken; if (appToken != null && appToken.mAppAnimator != null) { appToken.mAppAnimator.startProlongAnimation(scaleUp ? @@ -3391,8 +3391,7 @@ public class WindowManagerService extends IWindowManager.Stub // Notify whether the docked stack exists for the current user final DisplayContent displayContent = getDefaultDisplayContentLocked(); - final TaskStack stack = - displayContent.getSplitScreenPrimaryStackStackIgnoringVisibility(); + final TaskStack stack = displayContent.getDockedStackIgnoringVisibility(); displayContent.mDividerControllerLocked.notifyDockedStackExistsChanged( stack != null && stack.hasTaskForUser(newUserId)); @@ -6899,6 +6898,11 @@ public class WindowManagerService extends IWindowManager.Stub dumpSessionsLocked(pw, true); } return; + } else if ("surfaces".equals(cmd)) { + synchronized(mWindowMap) { + WindowSurfaceController.SurfaceTrace.dumpAllSurfaces(pw, null); + } + return; } else if ("displays".equals(cmd) || "d".equals(cmd)) { synchronized(mWindowMap) { mRoot.dumpDisplayContents(pw); @@ -6963,6 +6967,10 @@ public class WindowManagerService extends IWindowManager.Stub if (dumpAll) { pw.println("-------------------------------------------------------------------------------"); } + WindowSurfaceController.SurfaceTrace.dumpAllSurfaces(pw, dumpAll ? + "-------------------------------------------------------------------------------" + : null); + pw.println(); if (dumpAll) { pw.println("-------------------------------------------------------------------------------"); } @@ -7124,7 +7132,7 @@ public class WindowManagerService extends IWindowManager.Stub public int getDockedStackSide() { synchronized (mWindowMap) { final TaskStack dockedStack = getDefaultDisplayContentLocked() - .getSplitScreenPrimaryStackStackIgnoringVisibility(); + .getDockedStackIgnoringVisibility(); return dockedStack == null ? DOCKED_INVALID : dockedStack.getDockSide(); } } @@ -7596,10 +7604,10 @@ public class WindowManagerService extends IWindowManager.Stub } @Override - public boolean isStackVisible(int windowingMode) { + public boolean isStackVisible(int stackId) { synchronized (mWindowMap) { final DisplayContent dc = getDefaultDisplayContentLocked(); - return dc.isStackVisible(windowingMode); + return dc.isStackVisible(stackId); } } diff --git a/com/android/server/wm/WindowState.java b/com/android/server/wm/WindowState.java index e1715284..4ff0f391 100644 --- a/com/android/server/wm/WindowState.java +++ b/com/android/server/wm/WindowState.java @@ -16,7 +16,10 @@ package com.android.server.wm; +import static android.app.ActivityManager.StackId; +import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; +import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT; @@ -80,6 +83,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_POWER; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RESIZE; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; @@ -811,12 +815,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP final WindowState imeWin = mService.mInputMethodWindow; // IME is up and obscuring this window. Adjust the window position so it is visible. if (imeWin != null && imeWin.isVisibleNow() && mService.mInputMethodTarget == this) { - if (inFreeformWindowingMode() + final int stackId = getStackId(); + if (stackId == FREEFORM_WORKSPACE_STACK_ID && mContainingFrame.bottom > contentFrame.bottom) { // In freeform we want to move the top up directly. // TODO: Investigate why this is contentFrame not parentFrame. mContainingFrame.top -= mContainingFrame.bottom - contentFrame.bottom; - } else if (!inPinnedWindowingMode() + } else if (stackId != PINNED_STACK_ID && mContainingFrame.bottom > parentFrame.bottom) { // But in docked we want to behave like fullscreen and behave as if the task // were given smaller bounds for the purposes of layout. Skip adjustments for @@ -893,7 +898,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // For pinned workspace the frame isn't limited in any particular // way since SystemUI controls the bounds. For freeform however // we want to keep things inside the content frame. - final Rect limitFrame = task.inPinnedWindowingMode() ? mFrame : mContentFrame; + final Rect limitFrame = task.inPinnedWorkspace() ? mFrame : mContentFrame; // Keep the frame out of the blocked system area, limit it in size to the content area // and make sure that there is always a minimum visible so that the user can drag it // into a usable area.. @@ -1205,7 +1210,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // application when it has finished drawing. if (getOrientationChanging() || dragResizingChanged || isResizedWhileNotDragResizing()) { - if (DEBUG_ANIM || DEBUG_ORIENTATION || DEBUG_RESIZE) { + if (DEBUG_SURFACE_TRACE || DEBUG_ANIM || DEBUG_ORIENTATION || DEBUG_RESIZE) { Slog.v(TAG_WM, "Orientation or resize start waiting for draw" + ", mDrawState=DRAW_PENDING in " + this + ", surfaceController " + winAnimator.mSurfaceController); @@ -1657,9 +1662,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // // Anyway we don't need to synchronize position and content updates for these // windows since they aren't at the base layer and could be moved around anyway. - if (!computeDragResizing() && mAttrs.type == TYPE_BASE_APPLICATION - && !mWinAnimator.isForceScaled() && !isGoneForLayoutLw() - && !getTask().inPinnedWindowingMode()) { + if (!computeDragResizing() && mAttrs.type == TYPE_BASE_APPLICATION && + !mWinAnimator.isForceScaled() && !isGoneForLayoutLw() && + !getTask().inPinnedWorkspace()) { setResizedWhileNotDragResizing(true); } } @@ -2191,6 +2196,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } } + // TODO: Strange usage of word workspace here and above. + boolean inPinnedWorkspace() { + final Task task = getTask(); + return task != null && task.inPinnedWorkspace(); + } + void applyAdjustForImeIfNeeded() { final Task task = getTask(); if (task != null && task.mStack != null && task.mStack.isAdjustedForIme()) { @@ -2224,7 +2235,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } else { getVisibleBounds(mTmpRect); } - if (inFreeformWindowingMode()) { + if (inFreeformWorkspace()) { // For freeform windows we the touch region to include the whole surface for the // shadows. final DisplayMetrics displayMetrics = getDisplayContent().getDisplayMetrics(); @@ -2360,8 +2371,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // just in case they have the divider at an unstable position. Better // also reset drag resizing state, because the owner can't do it // anymore. - final TaskStack stack = - dc.getSplitScreenPrimaryStackStackIgnoringVisibility(); + final TaskStack stack = dc.getDockedStackIgnoringVisibility(); if (stack != null) { stack.resetDockedStackToMiddle(); } @@ -2928,7 +2938,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return mTmpRect; } - private int getStackId() { + @Override + public int getStackId() { final TaskStack stack = getStack(); if (stack == null) { return INVALID_STACK_ID; @@ -2972,6 +2983,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } } + boolean inFreeformWorkspace() { + final Task task = getTask(); + return task != null && task.inFreeformWorkspace(); + } + @Override public boolean isInMultiWindowMode() { final Task task = getTask(); @@ -3089,7 +3105,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // background. return (getDisplayContent().mDividerControllerLocked.isResizing() || mAppToken != null && !mAppToken.mFrozenBounds.isEmpty()) && - !task.inFreeformWindowingMode() && !isGoneForLayoutLw(); + !task.inFreeformWorkspace() && !isGoneForLayoutLw(); } @@ -3679,7 +3695,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // Force the show in the next prepareSurfaceLocked() call. mWinAnimator.mLastAlpha = -1; - if (DEBUG_ANIM) Slog.v(TAG, + if (DEBUG_SURFACE_TRACE || DEBUG_ANIM) Slog.v(TAG, "performShowLocked: mDrawState=HAS_DRAWN in " + this); mWinAnimator.mDrawState = HAS_DRAWN; mService.scheduleAnimationLocked(); @@ -3740,7 +3756,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP windowInfo.accessibilityIdOfAnchor = mAttrs.accessibilityIdOfAnchor; windowInfo.focused = isFocused(); Task task = getTask(); - windowInfo.inPictureInPicture = (task != null) && task.inPinnedWindowingMode(); + windowInfo.inPictureInPicture = (task != null) && task.inPinnedWorkspace(); if (mIsChildWindow) { windowInfo.parentToken = getParentWindow().mClient.asBinder(); @@ -4203,7 +4219,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // If a freeform window is animating from a position where it would be cutoff, it would be // cutoff during the animation. We don't want that, so for the duration of the animation // we ignore the decor cropping and depend on layering to position windows correctly. - final boolean cropToDecor = !(inFreeformWindowingMode() && isAnimatingLw()); + final boolean cropToDecor = !(inFreeformWorkspace() && isAnimatingLw()); if (cropToDecor) { // Intersect with the decor rect, offsetted by window position. systemDecorRect.intersect(decorRect.left - left, decorRect.top - top, @@ -4287,7 +4303,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // scale for the animation using the source hint rect // (see WindowStateAnimator#setSurfaceBoundariesLocked()). if (isDragResizeChanged() || isResizedWhileNotDragResizing() - || (surfaceInsetsChanging() && !inPinnedWindowingMode())) { + || (surfaceInsetsChanging() && !inPinnedWorkspace())) { mLastSurfaceInsets.set(mAttrs.surfaceInsets); setDragResizing(); diff --git a/com/android/server/wm/WindowStateAnimator.java b/com/android/server/wm/WindowStateAnimator.java index 52669031..1b7e5278 100644 --- a/com/android/server/wm/WindowStateAnimator.java +++ b/com/android/server/wm/WindowStateAnimator.java @@ -31,6 +31,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEAT import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_CROP; @@ -508,7 +509,7 @@ class WindowStateAnimator { boolean layoutNeeded = false; if (mDrawState == DRAW_PENDING) { - if (DEBUG_ANIM || SHOW_TRANSACTIONS || DEBUG_ORIENTATION) + if (DEBUG_SURFACE_TRACE || DEBUG_ANIM || SHOW_TRANSACTIONS || DEBUG_ORIENTATION) Slog.v(TAG, "finishDrawingLocked: mDrawState=COMMIT_DRAW_PENDING " + mWin + " in " + mSurfaceController); if (DEBUG_STARTING_WINDOW && startingWindow) { @@ -531,7 +532,7 @@ class WindowStateAnimator { if (mDrawState != COMMIT_DRAW_PENDING && mDrawState != READY_TO_SHOW) { return false; } - if (DEBUG_ANIM) { + if (DEBUG_SURFACE_TRACE || DEBUG_ANIM) { Slog.i(TAG, "commitFinishDrawingLocked: mDrawState=READY_TO_SHOW " + mSurfaceController); } mDrawState = READY_TO_SHOW; @@ -1032,7 +1033,7 @@ class WindowStateAnimator { //Slog.i(TAG_WM, "Not applying alpha transform"); } - if ((DEBUG_ANIM || WindowManagerService.localLOGV) + if ((DEBUG_SURFACE_TRACE || WindowManagerService.localLOGV) && (mShownAlpha == 1.0 || mShownAlpha == 0.0)) Slog.v( TAG, "computeShownFrameLocked: Animating " + this + " mAlpha=" + mAlpha + " self=" + (selfTransformation ? mTransformation.getAlpha() : "null") @@ -1111,7 +1112,7 @@ class WindowStateAnimator { */ private boolean useFinalClipRect() { return (isAnimationSet() && resolveStackClip() == STACK_CLIP_AFTER_ANIM) - || mDestroyPreservedSurfaceUponRedraw || mWin.inPinnedWindowingMode(); + || mDestroyPreservedSurfaceUponRedraw || mWin.inPinnedWorkspace(); } /** @@ -1176,7 +1177,7 @@ class WindowStateAnimator { return false; } - if (w.inPinnedWindowingMode()) { + if (w.inPinnedWorkspace()) { return false; } diff --git a/com/android/server/wm/WindowSurfaceController.java b/com/android/server/wm/WindowSurfaceController.java index d56df55d..2e1e3f76 100644 --- a/com/android/server/wm/WindowSurfaceController.java +++ b/com/android/server/wm/WindowSurfaceController.java @@ -22,6 +22,7 @@ import static android.view.Surface.SCALING_MODE_SCALE_TO_WINDOW; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -564,4 +565,262 @@ class WindowSurfaceController { public String toString() { return mSurfaceControl.toString(); } + + static class SurfaceTrace extends SurfaceControl { + private final static String SURFACE_TAG = TAG_WITH_CLASS_NAME ? "SurfaceTrace" : TAG_WM; + private final static boolean LOG_SURFACE_TRACE = DEBUG_SURFACE_TRACE; + final static ArrayList<SurfaceTrace> sSurfaces = new ArrayList<SurfaceTrace>(); + + private float mSurfaceTraceAlpha = 0; + private int mLayer; + private final PointF mPosition = new PointF(); + private final Point mSize = new Point(); + private final Rect mWindowCrop = new Rect(); + private final Rect mFinalCrop = new Rect(); + private boolean mShown = false; + private int mLayerStack; + private boolean mIsOpaque; + private float mDsdx, mDtdx, mDsdy, mDtdy; + private final String mName; + + public SurfaceTrace(SurfaceSession s, String name, int w, int h, int format, int flags, + int windowType, int ownerUid) + throws OutOfResourcesException { + super(s, name, w, h, format, flags, windowType, ownerUid); + mName = name != null ? name : "Not named"; + mSize.set(w, h); + if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "ctor: " + this + ". Called by " + + Debug.getCallers(3)); + synchronized (sSurfaces) { + sSurfaces.add(0, this); + } + } + + public SurfaceTrace(SurfaceSession s, + String name, int w, int h, int format, int flags) { + super(s, name, w, h, format, flags); + mName = name != null ? name : "Not named"; + mSize.set(w, h); + if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "ctor: " + this + ". Called by " + + Debug.getCallers(3)); + synchronized (sSurfaces) { + sSurfaces.add(0, this); + } + } + + @Override + public void setAlpha(float alpha) { + if (mSurfaceTraceAlpha != alpha) { + if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "setAlpha(" + alpha + "): OLD:" + this + + ". Called by " + Debug.getCallers(3)); + mSurfaceTraceAlpha = alpha; + } + super.setAlpha(alpha); + } + + @Override + public void setLayer(int zorder) { + if (zorder != mLayer) { + if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "setLayer(" + zorder + "): OLD:" + this + + ". Called by " + Debug.getCallers(3)); + mLayer = zorder; + } + super.setLayer(zorder); + + synchronized (sSurfaces) { + sSurfaces.remove(this); + int i; + for (i = sSurfaces.size() - 1; i >= 0; i--) { + SurfaceTrace s = sSurfaces.get(i); + if (s.mLayer < zorder) { + break; + } + } + sSurfaces.add(i + 1, this); + } + } + + @Override + public void setPosition(float x, float y) { + if (x != mPosition.x || y != mPosition.y) { + if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "setPosition(" + x + "," + y + "): OLD:" + + this + ". Called by " + Debug.getCallers(3)); + mPosition.set(x, y); + } + super.setPosition(x, y); + } + + @Override + public void setGeometryAppliesWithResize() { + if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "setGeometryAppliesWithResize(): OLD: " + + this + ". Called by" + Debug.getCallers(3)); + super.setGeometryAppliesWithResize(); + } + + @Override + public void setSize(int w, int h) { + if (w != mSize.x || h != mSize.y) { + if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "setSize(" + w + "," + h + "): OLD:" + + this + ". Called by " + Debug.getCallers(3)); + mSize.set(w, h); + } + super.setSize(w, h); + } + + @Override + public void setWindowCrop(Rect crop) { + if (crop != null) { + if (!crop.equals(mWindowCrop)) { + if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "setWindowCrop(" + + crop.toShortString() + "): OLD:" + this + ". Called by " + + Debug.getCallers(3)); + mWindowCrop.set(crop); + } + } + super.setWindowCrop(crop); + } + + @Override + public void setFinalCrop(Rect crop) { + if (crop != null) { + if (!crop.equals(mFinalCrop)) { + if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "setFinalCrop(" + + crop.toShortString() + "): OLD:" + this + ". Called by " + + Debug.getCallers(3)); + mFinalCrop.set(crop); + } + } + super.setFinalCrop(crop); + } + + @Override + public void setLayerStack(int layerStack) { + if (layerStack != mLayerStack) { + if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "setLayerStack(" + layerStack + "): OLD:" + + this + ". Called by " + Debug.getCallers(3)); + mLayerStack = layerStack; + } + super.setLayerStack(layerStack); + } + + @Override + public void setOpaque(boolean isOpaque) { + if (isOpaque != mIsOpaque) { + if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "setOpaque(" + isOpaque + "): OLD:" + + this + ". Called by " + Debug.getCallers(3)); + mIsOpaque = isOpaque; + } + super.setOpaque(isOpaque); + } + + @Override + public void setSecure(boolean isSecure) { + super.setSecure(isSecure); + } + + @Override + public void setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) { + if (dsdx != mDsdx || dtdx != mDtdx || dsdy != mDsdy || dtdy != mDtdy) { + if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "setMatrix(" + dsdx + "," + dtdx + "," + + dsdy + "," + dtdy + "): OLD:" + this + ". Called by " + + Debug.getCallers(3)); + mDsdx = dsdx; + mDtdx = dtdx; + mDsdy = dsdy; + mDtdy = dtdy; + } + super.setMatrix(dsdx, dtdx, dsdy, dtdy); + } + + @Override + public void hide() { + if (mShown) { + if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "hide: OLD:" + this + ". Called by " + + Debug.getCallers(3)); + mShown = false; + } + super.hide(); + } + + @Override + public void show() { + if (!mShown) { + if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "show: OLD:" + this + ". Called by " + + Debug.getCallers(3)); + mShown = true; + } + super.show(); + } + + @Override + public void destroy() { + super.destroy(); + if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "destroy: " + this + ". Called by " + + Debug.getCallers(3)); + synchronized (sSurfaces) { + sSurfaces.remove(this); + } + } + + @Override + public void release() { + super.release(); + if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "release: " + this + ". Called by " + + Debug.getCallers(3)); + synchronized (sSurfaces) { + sSurfaces.remove(this); + } + } + + @Override + public void setTransparentRegionHint(Region region) { + if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "setTransparentRegionHint(" + region + + "): OLD: " + this + " . Called by " + Debug.getCallers(3)); + super.setTransparentRegionHint(region); + } + + static void dumpAllSurfaces(PrintWriter pw, String header) { + synchronized (sSurfaces) { + final int N = sSurfaces.size(); + if (N <= 0) { + return; + } + if (header != null) { + pw.println(header); + } + pw.println("WINDOW MANAGER SURFACES (dumpsys window surfaces)"); + for (int i = 0; i < N; i++) { + SurfaceTrace s = sSurfaces.get(i); + pw.print(" Surface #"); pw.print(i); pw.print(": #"); + pw.print(Integer.toHexString(System.identityHashCode(s))); + pw.print(" "); pw.println(s.mName); + pw.print(" mLayerStack="); pw.print(s.mLayerStack); + pw.print(" mLayer="); pw.println(s.mLayer); + pw.print(" mShown="); pw.print(s.mShown); pw.print(" mAlpha="); + pw.print(s.mSurfaceTraceAlpha); pw.print(" mIsOpaque="); + pw.println(s.mIsOpaque); + pw.print(" mPosition="); pw.print(s.mPosition.x); pw.print(","); + pw.print(s.mPosition.y); + pw.print(" mSize="); pw.print(s.mSize.x); pw.print("x"); + pw.println(s.mSize.y); + pw.print(" mCrop="); s.mWindowCrop.printShortString(pw); pw.println(); + pw.print(" mFinalCrop="); s.mFinalCrop.printShortString(pw); pw.println(); + pw.print(" Transform: ("); pw.print(s.mDsdx); pw.print(", "); + pw.print(s.mDtdx); pw.print(", "); pw.print(s.mDsdy); + pw.print(", "); pw.print(s.mDtdy); pw.println(")"); + } + } + } + + @Override + public String toString() { + return "Surface " + Integer.toHexString(System.identityHashCode(this)) + " " + + mName + " (" + mLayerStack + "): shown=" + mShown + " layer=" + mLayer + + " alpha=" + mSurfaceTraceAlpha + " " + mPosition.x + "," + mPosition.y + + " " + mSize.x + "x" + mSize.y + + " crop=" + mWindowCrop.toShortString() + + " opaque=" + mIsOpaque + + " (" + mDsdx + "," + mDtdx + "," + mDsdy + "," + mDtdy + ")"; + } + } } diff --git a/com/android/server/wm/WindowSurfacePlacer.java b/com/android/server/wm/WindowSurfacePlacer.java index fa33fe8f..af1fa2fe 100644 --- a/com/android/server/wm/WindowSurfacePlacer.java +++ b/com/android/server/wm/WindowSurfacePlacer.java @@ -449,9 +449,6 @@ class WindowSurfacePlacer { // animating? wtoken.setVisibility(animLp, false, transit, false, voiceInteraction); wtoken.updateReportedVisibilityLocked(); - // setAllAppWinAnimators so the windows get onExitAnimationDone once the animation is - // done. - wtoken.setAllAppWinAnimators(); // Force the allDrawn flag, because we want to start // this guy's animations regardless of whether it's // gotten drawn. |