diff options
68 files changed, 1708 insertions, 954 deletions
diff --git a/Android.mk b/Android.mk index f544620b993f..f318a5a754c1 100644 --- a/Android.mk +++ b/Android.mk @@ -265,6 +265,7 @@ LOCAL_SRC_FILES += \ core/java/android/security/IKeystoreService.aidl \ core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl \ core/java/android/service/autofill/IAutoFillService.aidl \ + core/java/android/service/autofill/IAutoFillServiceConnection.aidl \ core/java/android/service/autofill/IFillCallback.aidl \ core/java/android/service/autofill/ISaveCallback.aidl \ core/java/android/service/carrier/ICarrierService.aidl \ diff --git a/api/current.txt b/api/current.txt index cf6c925a6efe..6e054fc5f240 100644 --- a/api/current.txt +++ b/api/current.txt @@ -3911,8 +3911,9 @@ package android.app { method public void readFromParcel(android.os.Parcel); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.app.ActivityManager.RunningAppProcessInfo> CREATOR; - field public static final int IMPORTANCE_BACKGROUND = 400; // 0x190 - field public static final int IMPORTANCE_EMPTY = 500; // 0x1f4 + field public static final deprecated int IMPORTANCE_BACKGROUND = 400; // 0x190 + field public static final int IMPORTANCE_CACHED = 400; // 0x190 + field public static final deprecated int IMPORTANCE_EMPTY = 500; // 0x1f4 field public static final int IMPORTANCE_FOREGROUND = 100; // 0x64 field public static final int IMPORTANCE_FOREGROUND_SERVICE = 125; // 0x7d field public static final int IMPORTANCE_GONE = 1000; // 0x3e8 @@ -36471,6 +36472,7 @@ package android.service.autofill { public abstract class AutoFillService extends android.app.Service { ctor public AutoFillService(); + method public final void disableSelf(); method public final android.os.IBinder onBind(android.content.Intent); method public void onConnected(); method public void onDisconnected(); @@ -36533,6 +36535,7 @@ package android.service.autofill { method public android.service.autofill.SaveInfo.Builder addSavableIds(android.view.autofill.AutoFillId...); method public android.service.autofill.SaveInfo build(); method public android.service.autofill.SaveInfo.Builder setDescription(java.lang.CharSequence); + method public android.service.autofill.SaveInfo.Builder setNegativeAction(java.lang.CharSequence, android.content.IntentSender); } } diff --git a/api/system-current.txt b/api/system-current.txt index 7ef4db8d894b..cfcc40a618cd 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -4049,8 +4049,9 @@ package android.app { method public void readFromParcel(android.os.Parcel); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.app.ActivityManager.RunningAppProcessInfo> CREATOR; - field public static final int IMPORTANCE_BACKGROUND = 400; // 0x190 - field public static final int IMPORTANCE_EMPTY = 500; // 0x1f4 + field public static final deprecated int IMPORTANCE_BACKGROUND = 400; // 0x190 + field public static final int IMPORTANCE_CACHED = 400; // 0x190 + field public static final deprecated int IMPORTANCE_EMPTY = 500; // 0x1f4 field public static final int IMPORTANCE_FOREGROUND = 100; // 0x64 field public static final int IMPORTANCE_FOREGROUND_SERVICE = 125; // 0x7d field public static final int IMPORTANCE_GONE = 1000; // 0x3e8 @@ -6946,26 +6947,64 @@ package android.app.backup { public class BackupManagerMonitor { ctor public BackupManagerMonitor(); method public void onEvent(android.os.Bundle); + field public static final java.lang.String EXTRA_LOG_CANCEL_ALL = "android.app.backup.extra.LOG_CANCEL_ALL"; field public static final java.lang.String EXTRA_LOG_EVENT_CATEGORY = "android.app.backup.extra.LOG_EVENT_CATEGORY"; field public static final java.lang.String EXTRA_LOG_EVENT_ID = "android.app.backup.extra.LOG_EVENT_ID"; field public static final java.lang.String EXTRA_LOG_EVENT_PACKAGE_NAME = "android.app.backup.extra.LOG_EVENT_PACKAGE_NAME"; field public static final java.lang.String EXTRA_LOG_EVENT_PACKAGE_VERSION = "android.app.backup.extra.LOG_EVENT_PACKAGE_VERSION"; + field public static final java.lang.String EXTRA_LOG_EXCEPTION_FULL_BACKUP = "android.app.backup.extra.LOG_EXCEPTION_FULL_BACKUP"; + field public static final java.lang.String EXTRA_LOG_ILLEGAL_KEY = "android.app.backup.extra.LOG_ILLEGAL_KEY"; + field public static final java.lang.String EXTRA_LOG_MANIFEST_PACKAGE_NAME = "android.app.backup.extra.LOG_MANIFEST_PACKAGE_NAME"; field public static final java.lang.String EXTRA_LOG_OLD_VERSION = "android.app.backup.extra.LOG_OLD_VERSION"; + field public static final java.lang.String EXTRA_LOG_POLICY_ALLOW_APKS = "android.app.backup.extra.LOG_POLICY_ALLOW_APKS"; + field public static final java.lang.String EXTRA_LOG_PREFLIGHT_ERROR = "android.app.backup.extra.LOG_PREFLIGHT_ERROR"; + field public static final java.lang.String EXTRA_LOG_RESTORE_ANYWAY = "android.app.backup.extra.LOG_RESTORE_ANYWAY"; + field public static final java.lang.String EXTRA_LOG_RESTORE_VERSION = "android.app.backup.extra.LOG_RESTORE_VERSION"; + field public static final java.lang.String EXTRA_LOG_WIDGET_PACKAGE_NAME = "android.app.backup.extra.LOG_WIDGET_PACKAGE_NAME"; field public static final int LOG_EVENT_CATEGORY_AGENT = 2; // 0x2 field public static final int LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY = 3; // 0x3 field public static final int LOG_EVENT_CATEGORY_TRANSPORT = 1; // 0x1 + field public static final int LOG_EVENT_ID_APK_NOT_INSTALLED = 40; // 0x28 field public static final int LOG_EVENT_ID_APP_HAS_NO_AGENT = 28; // 0x1c + field public static final int LOG_EVENT_ID_BACKUP_DISABLED = 13; // 0xd + field public static final int LOG_EVENT_ID_CANNOT_RESTORE_WITHOUT_APK = 41; // 0x29 field public static final int LOG_EVENT_ID_CANT_FIND_AGENT = 30; // 0x1e - field public static final int LOG_EVENT_ID_FULL_BACKUP_TIMEOUT = 4; // 0x4 + field public static final int LOG_EVENT_ID_CORRUPT_MANIFEST = 46; // 0x2e + field public static final int LOG_EVENT_ID_DEVICE_NOT_PROVISIONED = 14; // 0xe + field public static final int LOG_EVENT_ID_ERROR_PREFLIGHT = 16; // 0x10 + field public static final int LOG_EVENT_ID_EXCEPTION_FULL_BACKUP = 19; // 0x13 + field public static final int LOG_EVENT_ID_EXPECTED_DIFFERENT_PACKAGE = 43; // 0x2b + field public static final int LOG_EVENT_ID_FULL_BACKUP_CANCEL = 4; // 0x4 + field public static final int LOG_EVENT_ID_FULL_RESTORE_ALLOW_BACKUP_FALSE = 39; // 0x27 + field public static final int LOG_EVENT_ID_FULL_RESTORE_SIGNATURE_MISMATCH = 37; // 0x25 field public static final int LOG_EVENT_ID_FULL_RESTORE_TIMEOUT = 45; // 0x2d - field public static final int LOG_EVENT_ID_KEY_VALUE_BACKUP_TIMEOUT = 21; // 0x15 + field public static final int LOG_EVENT_ID_ILLEGAL_KEY = 5; // 0x5 + field public static final int LOG_EVENT_ID_KEY_VALUE_BACKUP_CANCEL = 21; // 0x15 field public static final int LOG_EVENT_ID_KEY_VALUE_RESTORE_TIMEOUT = 31; // 0x1f + field public static final int LOG_EVENT_ID_LOST_TRANSPORT = 25; // 0x19 + field public static final int LOG_EVENT_ID_MISSING_SIGNATURE = 42; // 0x2a + field public static final int LOG_EVENT_ID_NO_DATA_TO_SEND = 7; // 0x7 field public static final int LOG_EVENT_ID_NO_PACKAGES = 49; // 0x31 + field public static final int LOG_EVENT_ID_NO_PM_METADATA_RECEIVED = 23; // 0x17 field public static final int LOG_EVENT_ID_NO_RESTORE_METADATA_AVAILABLE = 22; // 0x16 + field public static final int LOG_EVENT_ID_PACKAGE_INELIGIBLE = 9; // 0x9 + field public static final int LOG_EVENT_ID_PACKAGE_KEY_VALUE_PARTICIPANT = 10; // 0xa field public static final int LOG_EVENT_ID_PACKAGE_NOT_FOUND = 12; // 0xc field public static final int LOG_EVENT_ID_PACKAGE_NOT_PRESENT = 26; // 0x1a + field public static final int LOG_EVENT_ID_PACKAGE_STOPPED = 11; // 0xb field public static final int LOG_EVENT_ID_PACKAGE_TRANSPORT_NOT_PRESENT = 15; // 0xf + field public static final int LOG_EVENT_ID_PM_AGENT_HAS_NO_METADATA = 24; // 0x18 + field public static final int LOG_EVENT_ID_QUOTA_HIT_PREFLIGHT = 18; // 0x12 + field public static final int LOG_EVENT_ID_RESTORE_ANY_VERSION = 34; // 0x22 + field public static final int LOG_EVENT_ID_RESTORE_VERSION_HIGHER = 27; // 0x1b + field public static final int LOG_EVENT_ID_SIGNATURE_MISMATCH = 29; // 0x1d + field public static final int LOG_EVENT_ID_SYSTEM_APP_NO_AGENT = 38; // 0x26 + field public static final int LOG_EVENT_ID_TRANSPORT_IS_NULL = 50; // 0x32 + field public static final int LOG_EVENT_ID_UNKNOWN_VERSION = 44; // 0x2c + field public static final int LOG_EVENT_ID_VERSIONS_MATCH = 35; // 0x23 field public static final int LOG_EVENT_ID_VERSION_OF_BACKUP_OLDER = 36; // 0x24 + field public static final int LOG_EVENT_ID_WIDGET_METADATA_MISMATCH = 47; // 0x2f + field public static final int LOG_EVENT_ID_WIDGET_UNKNOWN_VERSION = 48; // 0x30 } public abstract class BackupObserver { @@ -39394,6 +39433,7 @@ package android.service.autofill { public abstract class AutoFillService extends android.app.Service { ctor public AutoFillService(); + method public final void disableSelf(); method public final android.os.IBinder onBind(android.content.Intent); method public void onConnected(); method public void onDisconnected(); @@ -39456,6 +39496,7 @@ package android.service.autofill { method public android.service.autofill.SaveInfo.Builder addSavableIds(android.view.autofill.AutoFillId...); method public android.service.autofill.SaveInfo build(); method public android.service.autofill.SaveInfo.Builder setDescription(java.lang.CharSequence); + method public android.service.autofill.SaveInfo.Builder setNegativeAction(java.lang.CharSequence, android.content.IntentSender); } } diff --git a/api/test-current.txt b/api/test-current.txt index 5e4911c39e39..478a3ed42444 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -3920,8 +3920,9 @@ package android.app { method public void readFromParcel(android.os.Parcel); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.app.ActivityManager.RunningAppProcessInfo> CREATOR; - field public static final int IMPORTANCE_BACKGROUND = 400; // 0x190 - field public static final int IMPORTANCE_EMPTY = 500; // 0x1f4 + field public static final deprecated int IMPORTANCE_BACKGROUND = 400; // 0x190 + field public static final int IMPORTANCE_CACHED = 400; // 0x190 + field public static final deprecated int IMPORTANCE_EMPTY = 500; // 0x1f4 field public static final int IMPORTANCE_FOREGROUND = 100; // 0x64 field public static final int IMPORTANCE_FOREGROUND_SERVICE = 125; // 0x7d field public static final int IMPORTANCE_GONE = 1000; // 0x3e8 @@ -36610,6 +36611,7 @@ package android.service.autofill { public abstract class AutoFillService extends android.app.Service { ctor public AutoFillService(); + method public final void disableSelf(); method public final android.os.IBinder onBind(android.content.Intent); method public void onConnected(); method public void onDisconnected(); @@ -36672,6 +36674,7 @@ package android.service.autofill { method public android.service.autofill.SaveInfo.Builder addSavableIds(android.view.autofill.AutoFillId...); method public android.service.autofill.SaveInfo build(); method public android.service.autofill.SaveInfo.Builder setDescription(java.lang.CharSequence); + method public android.service.autofill.SaveInfo.Builder setNegativeAction(java.lang.CharSequence, android.content.IntentSender); } } diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index fda99660ff74..cae37c6d3762 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -3024,14 +3024,22 @@ public class ActivityManager { /** * Constant for {@link #importance}: This process process contains - * background code that is expendable. + * cached code that is expendable, not actively running any app components + * we care about. */ - public static final int IMPORTANCE_BACKGROUND = 400; + public static final int IMPORTANCE_CACHED = 400; + + /** + * @deprecated Renamed to {@link #IMPORTANCE_CACHED}. + */ + public static final int IMPORTANCE_BACKGROUND = IMPORTANCE_CACHED; /** * Constant for {@link #importance}: This process is empty of any * actively running code. + * @deprecated This value is no longer reported, use {@link #IMPORTANCE_CACHED} instead. */ + @Deprecated public static final int IMPORTANCE_EMPTY = 500; /** @@ -3044,7 +3052,7 @@ public class ActivityManager { if (procState == PROCESS_STATE_NONEXISTENT) { return IMPORTANCE_GONE; } else if (procState >= PROCESS_STATE_HOME) { - return IMPORTANCE_BACKGROUND; + return IMPORTANCE_CACHED; } else if (procState >= PROCESS_STATE_SERVICE) { return IMPORTANCE_SERVICE; } else if (procState > PROCESS_STATE_HEAVY_WEIGHT) { @@ -3066,7 +3074,7 @@ public class ActivityManager { public static int importanceToProcState(int importance) { if (importance == IMPORTANCE_GONE) { return PROCESS_STATE_NONEXISTENT; - } else if (importance >= IMPORTANCE_BACKGROUND) { + } else if (importance >= IMPORTANCE_CACHED) { return PROCESS_STATE_HOME; } else if (importance >= IMPORTANCE_SERVICE) { return PROCESS_STATE_SERVICE; @@ -3088,8 +3096,8 @@ public class ActivityManager { /** * The relative importance level that the system places on this * process. May be one of {@link #IMPORTANCE_FOREGROUND}, - * {@link #IMPORTANCE_VISIBLE}, {@link #IMPORTANCE_SERVICE}, - * {@link #IMPORTANCE_BACKGROUND}, or {@link #IMPORTANCE_EMPTY}. These + * {@link #IMPORTANCE_VISIBLE}, {@link #IMPORTANCE_SERVICE}, or + * {@link #IMPORTANCE_CACHED}. These * constants are numbered so that "more important" values are always * smaller than "less important" values. */ @@ -3101,7 +3109,7 @@ public class ActivityManager { * utility of processes within a category. This number means nothing * except that a smaller values are more recently used (and thus * more important). Currently an LRU value is only maintained for - * the {@link #IMPORTANCE_BACKGROUND} category, though others may + * the {@link #IMPORTANCE_CACHED} category, though others may * be maintained in the future. */ public int lru; diff --git a/core/java/android/app/backup/BackupManagerMonitor.java b/core/java/android/app/backup/BackupManagerMonitor.java index d2a623e0b13a..ebad16e0bc3d 100644 --- a/core/java/android/app/backup/BackupManagerMonitor.java +++ b/core/java/android/app/backup/BackupManagerMonitor.java @@ -54,26 +54,118 @@ public class BackupManagerMonitor { public static final String EXTRA_LOG_EVENT_CATEGORY = "android.app.backup.extra.LOG_EVENT_CATEGORY"; + + /** + * boolean: when we have an event with id LOG_EVENT_ID_KEY_VALUE_BACKUP_CANCEL we record if + * the call was to cancel backup of all packages + */ + public static final String EXTRA_LOG_CANCEL_ALL = "android.app.backup.extra.LOG_CANCEL_ALL"; + + /** + * string: when we have an event with id LOG_EVENT_ID_ILLEGAL_KEY we send the key that was used + * by the app + */ + public static final String EXTRA_LOG_ILLEGAL_KEY = "android.app.backup.extra.LOG_ILLEGAL_KEY"; + + /** + * long: when we have an event with id LOG_EVENT_ID_ERROR_PREFLIGHT we send the error code that + * was returned by the transport during preflight + */ + public static final String EXTRA_LOG_PREFLIGHT_ERROR = + "android.app.backup.extra.LOG_PREFLIGHT_ERROR"; + + /** + * string: when we have an event with id LOG_EVENT_ID_EXCEPTION_FULL_BACKUP we send the + * exception's stacktrace + */ + public static final String EXTRA_LOG_EXCEPTION_FULL_BACKUP = + "android.app.backup.extra.LOG_EXCEPTION_FULL_BACKUP"; + + /** + * int: when we have an event with id LOG_EVENT_ID_RESTORE_VERSION_HIGHER we send the + * restore package version + */ + public static final String EXTRA_LOG_RESTORE_VERSION = + "android.app.backup.extra.LOG_RESTORE_VERSION"; + + /** + * boolean: when we have an event with id LOG_EVENT_ID_RESTORE_VERSION_HIGHER we record if + * ApplicationInfo.FLAG_RESTORE_ANY_VERSION flag is set + */ + public static final String EXTRA_LOG_RESTORE_ANYWAY = + "android.app.backup.extra.LOG_RESTORE_ANYWAY"; + + + /** + * boolean: when we have an event with id LOG_EVENT_ID_APK_NOT_INSTALLED we record if + * the policy allows to install apks provided with the dataset + */ + public static final String EXTRA_LOG_POLICY_ALLOW_APKS = + "android.app.backup.extra.LOG_POLICY_ALLOW_APKS"; + + + /** + * string: when we have an event with id LOG_EVENT_ID_EXPECTED_DIFFERENT_PACKAGE we record the + * package name provided in the restore manifest + */ + public static final String EXTRA_LOG_MANIFEST_PACKAGE_NAME = + "android.app.backup.extra.LOG_MANIFEST_PACKAGE_NAME"; + + /** + * string: when we have an event with id LOG_EVENT_ID_WIDGET_METADATA_MISMATCH we record the + * package name provided in the widget metadata + */ + public static final String EXTRA_LOG_WIDGET_PACKAGE_NAME = + "android.app.backup.extra.LOG_WIDGET_PACKAGE_NAME"; + /** - * string: when we have event of id LOG_EVENT_ID_VERSION_OF_BACKUP_OLDER we send the version + * int: when we have event of id LOG_EVENT_ID_VERSION_OF_BACKUP_OLDER we send the version * of the backup. */ - public static final String EXTRA_LOG_OLD_VERSION = - "android.app.backup.extra.LOG_OLD_VERSION"; + public static final String EXTRA_LOG_OLD_VERSION = "android.app.backup.extra.LOG_OLD_VERSION"; // TODO complete this list with all log messages. And document properly. - public static final int LOG_EVENT_ID_FULL_BACKUP_TIMEOUT = 4; + public static final int LOG_EVENT_ID_FULL_BACKUP_CANCEL = 4; + public static final int LOG_EVENT_ID_ILLEGAL_KEY = 5; + public static final int LOG_EVENT_ID_NO_DATA_TO_SEND = 7; + public static final int LOG_EVENT_ID_PACKAGE_INELIGIBLE = 9; + public static final int LOG_EVENT_ID_PACKAGE_KEY_VALUE_PARTICIPANT = 10; + public static final int LOG_EVENT_ID_PACKAGE_STOPPED = 11; public static final int LOG_EVENT_ID_PACKAGE_NOT_FOUND = 12; + public static final int LOG_EVENT_ID_BACKUP_DISABLED = 13; + public static final int LOG_EVENT_ID_DEVICE_NOT_PROVISIONED = 14; public static final int LOG_EVENT_ID_PACKAGE_TRANSPORT_NOT_PRESENT = 15; - public static final int LOG_EVENT_ID_KEY_VALUE_BACKUP_TIMEOUT = 21; + public static final int LOG_EVENT_ID_ERROR_PREFLIGHT = 16; + public static final int LOG_EVENT_ID_QUOTA_HIT_PREFLIGHT = 18; + public static final int LOG_EVENT_ID_EXCEPTION_FULL_BACKUP = 19; + public static final int LOG_EVENT_ID_KEY_VALUE_BACKUP_CANCEL = 21; public static final int LOG_EVENT_ID_NO_RESTORE_METADATA_AVAILABLE = 22; + public static final int LOG_EVENT_ID_NO_PM_METADATA_RECEIVED = 23; + public static final int LOG_EVENT_ID_PM_AGENT_HAS_NO_METADATA = 24; + public static final int LOG_EVENT_ID_LOST_TRANSPORT = 25; public static final int LOG_EVENT_ID_PACKAGE_NOT_PRESENT = 26; + public static final int LOG_EVENT_ID_RESTORE_VERSION_HIGHER = 27; public static final int LOG_EVENT_ID_APP_HAS_NO_AGENT = 28; + public static final int LOG_EVENT_ID_SIGNATURE_MISMATCH = 29; public static final int LOG_EVENT_ID_CANT_FIND_AGENT = 30; public static final int LOG_EVENT_ID_KEY_VALUE_RESTORE_TIMEOUT = 31; + public static final int LOG_EVENT_ID_RESTORE_ANY_VERSION = 34; + public static final int LOG_EVENT_ID_VERSIONS_MATCH = 35; public static final int LOG_EVENT_ID_VERSION_OF_BACKUP_OLDER = 36; + public static final int LOG_EVENT_ID_FULL_RESTORE_SIGNATURE_MISMATCH = 37; + public static final int LOG_EVENT_ID_SYSTEM_APP_NO_AGENT = 38; + public static final int LOG_EVENT_ID_FULL_RESTORE_ALLOW_BACKUP_FALSE = 39; + public static final int LOG_EVENT_ID_APK_NOT_INSTALLED = 40; + public static final int LOG_EVENT_ID_CANNOT_RESTORE_WITHOUT_APK = 41; + public static final int LOG_EVENT_ID_MISSING_SIGNATURE = 42; + public static final int LOG_EVENT_ID_EXPECTED_DIFFERENT_PACKAGE = 43; + public static final int LOG_EVENT_ID_UNKNOWN_VERSION = 44; public static final int LOG_EVENT_ID_FULL_RESTORE_TIMEOUT = 45; + public static final int LOG_EVENT_ID_CORRUPT_MANIFEST = 46; + public static final int LOG_EVENT_ID_WIDGET_METADATA_MISMATCH = 47; + public static final int LOG_EVENT_ID_WIDGET_UNKNOWN_VERSION = 48; public static final int LOG_EVENT_ID_NO_PACKAGES = 49; + public static final int LOG_EVENT_ID_TRANSPORT_IS_NULL = 50; diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index 817cb5bb9add..0610499dbce4 100644 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -275,7 +275,7 @@ public class Build { * Magic version number for a current development build, which has * not yet turned into an official release. */ - public static final int CUR_DEVELOPMENT = 10000; + public static final int CUR_DEVELOPMENT = VMRuntime.SDK_VERSION_CUR_DEVELOPMENT; /** * October 2008: The original, first, version of Android. Yay! diff --git a/core/java/android/os/SystemProperties.java b/core/java/android/os/SystemProperties.java index 78820b537606..b525193c1b9c 100644 --- a/core/java/android/os/SystemProperties.java +++ b/core/java/android/os/SystemProperties.java @@ -35,7 +35,6 @@ public class SystemProperties { private static final String TAG = "SystemProperties"; private static final boolean TRACK_KEY_ACCESS = false; - public static final int PROP_NAME_MAX = 31; public static final int PROP_VALUE_MAX = 91; private static final ArrayList<Runnable> sChangeCallbacks = new ArrayList<Runnable>(); @@ -82,12 +81,8 @@ public class SystemProperties { /** * Get the value for the given key. * @return an empty string if the key isn't found - * @throws IllegalArgumentException if the key exceeds 32 characters */ public static String get(String key) { - if (key.length() > PROP_NAME_MAX) { - throw newKeyTooLargeException(key); - } if (TRACK_KEY_ACCESS) onKeyAccess(key); return native_get(key); } @@ -95,12 +90,8 @@ public class SystemProperties { /** * Get the value for the given key. * @return if the key isn't found, return def if it isn't null, or an empty string otherwise - * @throws IllegalArgumentException if the key exceeds 32 characters */ public static String get(String key, String def) { - if (key.length() > PROP_NAME_MAX) { - throw newKeyTooLargeException(key); - } if (TRACK_KEY_ACCESS) onKeyAccess(key); return native_get(key, def); } @@ -111,12 +102,8 @@ public class SystemProperties { * @param def a default value to return * @return the key parsed as an integer, or def if the key isn't found or * cannot be parsed - * @throws IllegalArgumentException if the key exceeds 32 characters */ public static int getInt(String key, int def) { - if (key.length() > PROP_NAME_MAX) { - throw newKeyTooLargeException(key); - } if (TRACK_KEY_ACCESS) onKeyAccess(key); return native_get_int(key, def); } @@ -127,12 +114,8 @@ public class SystemProperties { * @param def a default value to return * @return the key parsed as a long, or def if the key isn't found or * cannot be parsed - * @throws IllegalArgumentException if the key exceeds 32 characters */ public static long getLong(String key, long def) { - if (key.length() > PROP_NAME_MAX) { - throw newKeyTooLargeException(key); - } if (TRACK_KEY_ACCESS) onKeyAccess(key); return native_get_long(key, def); } @@ -148,25 +131,17 @@ public class SystemProperties { * @param def a default value to return * @return the key parsed as a boolean, or def if the key isn't found or is * not able to be parsed as a boolean. - * @throws IllegalArgumentException if the key exceeds 32 characters */ public static boolean getBoolean(String key, boolean def) { - if (key.length() > PROP_NAME_MAX) { - throw newKeyTooLargeException(key); - } if (TRACK_KEY_ACCESS) onKeyAccess(key); return native_get_boolean(key, def); } /** * Set the value for the given key. - * @throws IllegalArgumentException if the key exceeds 32 characters * @throws IllegalArgumentException if the value exceeds 92 characters */ public static void set(String key, String val) { - if (key.length() > PROP_NAME_MAX) { - throw newKeyTooLargeException(key); - } if (val != null && val.length() > PROP_VALUE_MAX) { throw newValueTooLargeException(key, val); } @@ -196,11 +171,6 @@ public class SystemProperties { } } - private static IllegalArgumentException newKeyTooLargeException(String key) { - return new IllegalArgumentException("system property key '" + key + "' is longer than " - + PROP_NAME_MAX + " characters"); - } - private static IllegalArgumentException newValueTooLargeException(String key, String value) { return new IllegalArgumentException("value of system property '" + key + "' is longer than " + PROP_VALUE_MAX + " characters: " + value); diff --git a/core/java/android/service/autofill/AutoFillService.java b/core/java/android/service/autofill/AutoFillService.java index 4099f59ec9ef..3c211eb972e7 100644 --- a/core/java/android/service/autofill/AutoFillService.java +++ b/core/java/android/service/autofill/AutoFillService.java @@ -15,9 +15,12 @@ */ package android.service.autofill; +import android.accessibilityservice.IAccessibilityServiceConnection; import android.annotation.NonNull; import android.annotation.Nullable; +import android.os.Message; import android.os.RemoteException; +import android.view.accessibility.AccessibilityInteractionClient; import com.android.internal.os.HandlerCaller; import android.annotation.SdkConstant; import android.app.Activity; @@ -79,6 +82,15 @@ public abstract class AutoFillService extends Service { private final IAutoFillService mInterface = new IAutoFillService.Stub() { @Override + public void onInit(IAutoFillServiceConnection connection) { + if (connection != null) { + mHandlerCaller.obtainMessageO(MSG_CONNECT, connection).sendToTarget(); + } else { + mHandlerCaller.obtainMessage(MSG_DISCONNECT).sendToTarget(); + } + } + + @Override public void onFillRequest(AssistStructure structure, Bundle extras, IFillCallback callback) { ICancellationSignal transport = CancellationSignal.createTransport(); @@ -98,21 +110,12 @@ public abstract class AutoFillService extends Service { mHandlerCaller.obtainMessageOOO(MSG_ON_SAVE_REQUEST, structure, extras, callback).sendToTarget(); } - - @Override - public void onConnected() { - mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_CONNECT)); - } - - @Override - public void onDisconnected() { - mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_DISCONNECT)); - } }; private final HandlerCaller.Callback mHandlerCallback = (msg) -> { switch (msg.what) { case MSG_CONNECT: { + mConnection = (IAutoFillServiceConnection) msg.obj; onConnected(); break; } case MSG_ON_FILL_REQUEST: { @@ -136,6 +139,7 @@ public abstract class AutoFillService extends Service { break; } case MSG_DISCONNECT: { onDisconnected(); + mConnection = null; break; } default: { Log.w(TAG, "MyCallbacks received invalid message type: " + msg); @@ -145,6 +149,8 @@ public abstract class AutoFillService extends Service { private HandlerCaller mHandlerCaller; + private IAutoFillServiceConnection mConnection; + /** * {@inheritDoc} * @@ -223,4 +229,22 @@ public abstract class AutoFillService extends Service { public void onDisconnected() { //TODO(b/33197203): is not called anymore, fix it! } + + /** + * Disables the service. After calling this method, the service will + * be disabled and settings will show that it is turned off. + * + * <p>You should call this method only after a call to {@link #onConnected()} + * and before the corresponding call to {@link #onDisconnected()}. In other words + * you can disable your service only while the system is connected to it.</p> + */ + public final void disableSelf() { + if (mConnection != null) { + try { + mConnection.disableSelf(); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + } } diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java index ba75c8bee039..ef551ad29623 100644 --- a/core/java/android/service/autofill/FillResponse.java +++ b/core/java/android/service/autofill/FillResponse.java @@ -171,7 +171,7 @@ public final class FillResponse implements Parcelable { if (false) { // TODO(b/33197203, 35727295): this is how mSaveInfo will be set once we don't support - // FillResponse.setSavableIds() + // FillResponse.addSavableIds() mSaveInfo = builder.mSaveInfo; if (mSaveInfo != null) { mSaveInfo.addSavableIds(mDatasets); @@ -181,11 +181,11 @@ public final class FillResponse implements Parcelable { } } } else { - // Temporary workaround to support FillResponse.setSavableIds() + // Temporary workaround to support FillResponse.addSavableIds() SaveInfo saveInfo = builder.mSaveInfoBuilder != null ? builder.mSaveInfoBuilder.build() : builder.mSaveInfo; - // Handle the the case where service didn't call setSavableIds() because it would + // Handle the the case where service didn't call addSavableIds() because it would // contain just the ids from the datasets. if (saveInfo == null && mDatasets != null) { saveInfo = new SaveInfo.Builder(SaveInfo.SAVE_DATA_TYPE_GENERIC).build(); diff --git a/core/java/android/service/autofill/IAutoFillService.aidl b/core/java/android/service/autofill/IAutoFillService.aidl index fa1ea65e30b0..80685d87a788 100644 --- a/core/java/android/service/autofill/IAutoFillService.aidl +++ b/core/java/android/service/autofill/IAutoFillService.aidl @@ -18,6 +18,7 @@ package android.service.autofill; import android.app.assist.AssistStructure; import android.os.Bundle; +import android.service.autofill.IAutoFillServiceConnection; import android.service.autofill.IFillCallback; import android.service.autofill.ISaveCallback; import com.android.internal.os.IResultReceiver; @@ -28,10 +29,9 @@ import com.android.internal.os.IResultReceiver; * @hide */ oneway interface IAutoFillService { + void onInit(in IAutoFillServiceConnection connection); void onFillRequest(in AssistStructure structure, in Bundle extras, in IFillCallback callback); void onSaveRequest(in AssistStructure structure, in Bundle extras, in ISaveCallback callback); - void onConnected(); - void onDisconnected(); } diff --git a/core/java/android/service/autofill/IAutoFillServiceConnection.aidl b/core/java/android/service/autofill/IAutoFillServiceConnection.aidl new file mode 100644 index 000000000000..cf73a10ca58c --- /dev/null +++ b/core/java/android/service/autofill/IAutoFillServiceConnection.aidl @@ -0,0 +1,26 @@ +/* + * 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 android.service.autofill; + +/** + * Interface from an auto fill service to the system. + * + * @hide + */ +interface IAutoFillServiceConnection { + void disableSelf(); +} diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java index 096f28b60687..a8f9aeedb6b9 100644 --- a/core/java/android/service/autofill/SaveInfo.java +++ b/core/java/android/service/autofill/SaveInfo.java @@ -21,6 +21,7 @@ import static android.view.autofill.Helper.DEBUG; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.content.IntentSender; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; @@ -72,6 +73,8 @@ public final class SaveInfo implements Parcelable { public static final int SAVE_DATA_TYPE_CREDIT_CARD = 3; private final @SaveDataType int mType; + private CharSequence mNegativeActionTitle; + private IntentSender mNegativeActionListener; private ArraySet<AutoFillId> mSavableIds; private final CharSequence mDescription; @@ -88,11 +91,23 @@ public final class SaveInfo implements Parcelable { private SaveInfo(Builder builder) { mType = builder.mType; + mNegativeActionTitle = builder.mNegativeActionTitle; + mNegativeActionListener = builder.mNegativeActionListener; mSavableIds = builder.mSavableIds; mDescription = builder.mDescription; } /** @hide */ + public @Nullable CharSequence getNegativeActionTitle() { + return mNegativeActionTitle; + } + + /** @hide */ + public @Nullable IntentSender getNegativeActionListener() { + return mNegativeActionListener; + } + + /** @hide */ public @Nullable ArraySet<AutoFillId> getSavableIds() { return mSavableIds; } @@ -132,6 +147,8 @@ public final class SaveInfo implements Parcelable { public static final class Builder { private final @SaveDataType int mType; + private CharSequence mNegativeActionTitle; + private IntentSender mNegativeActionListener; private ArraySet<AutoFillId> mSavableIds; private CharSequence mDescription; private boolean mDestroyed; @@ -195,6 +212,42 @@ public final class SaveInfo implements Parcelable { } /** + * Sets the title and listener for the negative save action. + * + * <p>This allows a fill-provider to customize the text and be + * notified when the user selects the negative action in the save + * UI. Note that selecting the negative action regardless of its text + * and listener being customized would dismiss the save UI and if a + * custom listener intent is provided then this intent will be + * started.</p> + * + * <p>This customization could be useful for providing additional + * semantics to the negative action. For example, a fill-provider + * can use this mechanism to add a "Disable" function or a "More info" + * function, etc. Note that the save action is exclusively controlled + * by the platform to ensure user consent is collected to release + * data from the filled app to the fill-provider.</p> + * + * @param title The action title. + * @param listener The action listener. + * @return This builder. + * + * @throws IllegalArgumentException If the title and the listener + * are not both either null or non-null. + */ + public @NonNull Builder setNegativeAction(@Nullable CharSequence title, + @Nullable IntentSender listener) { + throwIfDestroyed(); + if (title == null ^ listener == null) { + throw new IllegalArgumentException("title and listener" + + " must be both non-null or null"); + } + mNegativeActionTitle = title; + mNegativeActionListener = listener; + return this; + } + + /** * Builds a new {@link SaveInfo} instance. */ public SaveInfo build() { @@ -235,6 +288,8 @@ public final class SaveInfo implements Parcelable { @Override public void writeToParcel(Parcel parcel, int flags) { parcel.writeInt(mType); + parcel.writeCharSequence(mNegativeActionTitle); + parcel.writeParcelable(mNegativeActionListener, flags); parcel.writeTypedArraySet(mSavableIds, flags); parcel.writeCharSequence(mDescription); } @@ -246,6 +301,7 @@ public final class SaveInfo implements Parcelable { // the system obeys the contract of the builder to avoid attacks // using specially crafted parcels. final Builder builder = new Builder(parcel.readInt()); + builder.setNegativeAction(parcel.readCharSequence(), parcel.readParcelable(null)); final ArraySet<AutoFillId> savableIds = parcel.readTypedArraySet(null); final int savableIdsCount = (savableIds != null) ? savableIds.size() : 0; for (int i = 0; i < savableIdsCount; i++) { diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index 0ac16c1fa023..b718696b2202 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -95,11 +95,6 @@ public class SurfaceControl { IBinder displayToken, int mode); private static native void nativeDeferTransactionUntil(long nativeObject, IBinder handle, long frame); - private static native void nativeDeferTransactionUntilSurface(long nativeObject, - long surfaceObject, long frame); - private static native void nativeReparentChildren(long nativeObject, - IBinder handle); - private static native void nativeSeverChildren(long nativeObject); private static native void nativeSetOverrideScalingMode(long nativeObject, int scalingMode); private static native IBinder nativeGetHandle(long nativeObject); @@ -426,18 +421,6 @@ public class SurfaceControl { nativeDeferTransactionUntil(mNativeObject, handle, frame); } - public void deferTransactionUntil(Surface barrier, long frame) { - nativeDeferTransactionUntilSurface(mNativeObject, barrier.mNativeObject, frame); - } - - public void reparentChildren(IBinder newParentHandle) { - nativeReparentChildren(mNativeObject, newParentHandle); - } - - public void detachChildren() { - nativeSeverChildren(mNativeObject); - } - public void setOverrideScalingMode(int scalingMode) { checkNotReleased(); nativeSetOverrideScalingMode(mNativeObject, scalingMode); diff --git a/core/java/android/view/SurfaceSession.java b/core/java/android/view/SurfaceSession.java index b5912bc1e1c8..3cf5af484625 100644 --- a/core/java/android/view/SurfaceSession.java +++ b/core/java/android/view/SurfaceSession.java @@ -27,7 +27,6 @@ public final class SurfaceSession { private long mNativeClient; // SurfaceComposerClient* private static native long nativeCreate(); - private static native long nativeCreateScoped(long surfacePtr); private static native void nativeDestroy(long ptr); private static native void nativeKill(long ptr); @@ -36,10 +35,6 @@ public final class SurfaceSession { mNativeClient = nativeCreate(); } - public SurfaceSession(Surface root) { - mNativeClient = nativeCreateScoped(root.mNativeObject); - } - /* no user serviceable parts here ... */ @Override protected void finalize() throws Throwable { diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 61b12475d542..d2577d48c3d1 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -16,10 +16,6 @@ package android.view; -import static android.view.WindowManagerPolicy.APPLICATION_MEDIA_SUBLAYER; -import static android.view.WindowManagerPolicy.APPLICATION_MEDIA_OVERLAY_SUBLAYER; -import static android.view.WindowManagerPolicy.APPLICATION_PANEL_SUBLAYER; - import android.content.Context; import android.content.res.CompatibilityInfo.Translator; import android.content.res.Configuration; @@ -30,12 +26,16 @@ import android.graphics.Rect; import android.graphics.Region; import android.os.Handler; import android.os.Message; +import android.os.ParcelFileDescriptor; +import android.os.RemoteException; import android.os.SystemClock; import android.util.AttributeSet; import android.util.Log; +import com.android.internal.view.BaseIWindow; import com.android.internal.view.SurfaceCallbackHelper; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.concurrent.locks.ReentrantLock; @@ -92,8 +92,8 @@ import java.util.concurrent.locks.ReentrantLock; * positioned asynchronously.</p> */ public class SurfaceView extends View { - private static final String TAG = "SurfaceView"; - private static final boolean DEBUG = false; + static private final String TAG = "SurfaceView"; + static private final boolean DEBUG = false; final ArrayList<SurfaceHolder.Callback> mCallbacks = new ArrayList<SurfaceHolder.Callback>(); @@ -102,23 +102,28 @@ public class SurfaceView extends View { final ReentrantLock mSurfaceLock = new ReentrantLock(); final Surface mSurface = new Surface(); // Current surface in use + final Surface mNewSurface = new Surface(); // New surface we are switching to boolean mDrawingStopped = true; - // We use this to track if the application has produced a frame - // in to the Surface. Up until that point, we should be careful not to punch - // holes. - boolean mDrawFinished = false; - - final Rect mScreenRect = new Rect(); - SurfaceSession mSurfaceSession; - SurfaceControl mSurfaceControl; + final WindowManager.LayoutParams mLayout + = new WindowManager.LayoutParams(); + IWindowSession mSession; + MyWindow mWindow; + final Rect mVisibleInsets = new Rect(); + final Rect mWinFrame = new Rect(); + final Rect mOverscanInsets = new Rect(); + final Rect mContentInsets = new Rect(); + final Rect mStableInsets = new Rect(); + final Rect mOutsets = new Rect(); + final Rect mBackdropFrame = new Rect(); final Rect mTmpRect = new Rect(); final Configuration mConfiguration = new Configuration(); static final int KEEP_SCREEN_ON_MSG = 1; - static final int DRAW_FINISHED_MSG = 2; + static final int GET_NEW_SURFACE_MSG = 2; + static final int UPDATE_WINDOW_MSG = 3; - int mSubLayer = APPLICATION_MEDIA_SUBLAYER; + int mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA; boolean mIsCreating = false; private volatile boolean mRtHandlingPositionUpdates = false; @@ -130,9 +135,11 @@ public class SurfaceView extends View { case KEEP_SCREEN_ON_MSG: { setKeepScreenOn(msg.arg1 != 0); } break; - case DRAW_FINISHED_MSG: { - mDrawFinished = true; - invalidate(); + case GET_NEW_SURFACE_MSG: { + handleGetNewSurface(); + } break; + case UPDATE_WINDOW_MSG: { + updateWindow(); } break; } } @@ -142,7 +149,7 @@ public class SurfaceView extends View { = new ViewTreeObserver.OnScrollChangedListener() { @Override public void onScrollChanged() { - updateSurface(); + updateWindow(); } }; @@ -152,14 +159,13 @@ public class SurfaceView extends View { public boolean onPreDraw() { // reposition ourselves where the surface is mHaveFrame = getWidth() > 0 && getHeight() > 0; - updateSurface(); + updateWindow(); return true; } }; boolean mRequestedVisible = false; boolean mWindowVisibility = false; - boolean mLastWindowVisibility = false; boolean mViewVisibility = false; int mRequestedWidth = -1; int mRequestedHeight = -1; @@ -175,17 +181,19 @@ public class SurfaceView extends View { boolean mVisible = false; int mWindowSpaceLeft = -1; int mWindowSpaceTop = -1; - int mSurfaceWidth = -1; - int mSurfaceHeight = -1; + int mWindowSpaceWidth = -1; + int mWindowSpaceHeight = -1; int mFormat = -1; final Rect mSurfaceFrame = new Rect(); int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1; + boolean mUpdateWindowNeeded; + boolean mReportDrawNeeded; private Translator mTranslator; + private int mWindowInsetLeft; + private int mWindowInsetTop; private boolean mGlobalListenersAdded; - private int mSurfaceFlags = SurfaceControl.HIDDEN; - public SurfaceView(Context context) { this(context, null); } @@ -219,8 +227,11 @@ public class SurfaceView extends View { protected void onAttachedToWindow() { super.onAttachedToWindow(); mParent.requestTransparentRegion(this); + mSession = getWindowSession(); + mLayout.token = getWindowToken(); + mLayout.setTitle("SurfaceView - " + getViewRootImpl().getTitle()); + mLayout.packageName = mContext.getOpPackageName(); mViewVisibility = getVisibility() == VISIBLE; - mRequestedVisible = mViewVisibility && mWindowVisibility; if (!mGlobalListenersAdded) { ViewTreeObserver observer = getViewTreeObserver(); @@ -235,7 +246,7 @@ public class SurfaceView extends View { super.onWindowVisibilityChanged(visibility); mWindowVisibility = visibility == VISIBLE; mRequestedVisible = mWindowVisibility && mViewVisibility; - updateSurface(); + updateWindow(); } @Override @@ -253,7 +264,7 @@ public class SurfaceView extends View { requestLayout(); } mRequestedVisible = newRequestedVisible; - updateSurface(); + updateWindow(); } @Override @@ -266,14 +277,19 @@ public class SurfaceView extends View { } mRequestedVisible = false; - - updateSurface(); - if (mSurfaceControl != null) { - mSurfaceControl.destroy(); + updateWindow(); + mHaveFrame = false; + if (mWindow != null) { + try { + mSession.remove(mWindow); + } catch (RemoteException ex) { + // Not much we can do here... + } + mWindow = null; } - mSurfaceControl = null; + mSession = null; + mLayout.token = null; - mHaveFrame = false; super.onDetachedFromWindow(); } @@ -292,13 +308,13 @@ public class SurfaceView extends View { @Override protected boolean setFrame(int left, int top, int right, int bottom) { boolean result = super.setFrame(left, top, right, bottom); - updateSurface(); + updateWindow(); return result; } @Override public boolean gatherTransparentRegion(Region region) { - if (isAboveParent()) { + if (mWindowType == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) { return super.gatherTransparentRegion(region); } @@ -325,7 +341,7 @@ public class SurfaceView extends View { @Override public void draw(Canvas canvas) { - if (mDrawFinished && !isAboveParent()) { + if (mWindowType != WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) { // draw() is not called when SKIP_DRAW is set if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) { // punch a whole in the view-hierarchy below us @@ -337,8 +353,8 @@ public class SurfaceView extends View { @Override protected void dispatchDraw(Canvas canvas) { - if (mDrawFinished && !isAboveParent()) { - // draw() is not called when SKIP_DRAW is set + if (mWindowType != WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) { + // if SKIP_DRAW is cleared, draw() has already punched a hole if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { // punch a whole in the view-hierarchy below us canvas.drawColor(0, PorterDuff.Mode.CLEAR); @@ -359,8 +375,9 @@ public class SurfaceView extends View { * <p>Calling this overrides any previous call to {@link #setZOrderOnTop}. */ public void setZOrderMediaOverlay(boolean isMediaOverlay) { - mSubLayer = isMediaOverlay - ? APPLICATION_MEDIA_OVERLAY_SUBLAYER : APPLICATION_MEDIA_SUBLAYER; + mWindowType = isMediaOverlay + ? WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY + : WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA; } /** @@ -378,9 +395,12 @@ public class SurfaceView extends View { */ public void setZOrderOnTop(boolean onTop) { if (onTop) { - mSubLayer = APPLICATION_PANEL_SUBLAYER; + mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL; + // ensures the surface is placed below the IME + mLayout.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; } else { - mSubLayer = APPLICATION_MEDIA_SUBLAYER; + mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA; + mLayout.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; } } @@ -398,32 +418,31 @@ public class SurfaceView extends View { */ public void setSecure(boolean isSecure) { if (isSecure) { - mSurfaceFlags |= SurfaceControl.SECURE; + mLayout.flags |= WindowManager.LayoutParams.FLAG_SECURE; } else { - mSurfaceFlags &= ~SurfaceControl.SECURE; + mLayout.flags &= ~WindowManager.LayoutParams.FLAG_SECURE; } } - private Rect getParentSurfaceInsets() { - final ViewRootImpl root = getViewRootImpl(); - if (root == null) { - return null; - } else { - return root.mWindowAttributes.surfaceInsets; - } + /** + * Hack to allow special layering of windows. The type is one of the + * types in WindowManager.LayoutParams. This is a hack so: + * @hide + */ + public void setWindowType(int type) { + mWindowType = type; } /** @hide */ - protected void updateSurface() { + protected void updateWindow() { if (!mHaveFrame) { return; } ViewRootImpl viewRoot = getViewRootImpl(); - if (viewRoot == null || viewRoot.mSurface == null || !viewRoot.mSurface.isValid()) { - return; + if (viewRoot != null) { + mTranslator = viewRoot.mTranslator; } - mTranslator = viewRoot.mTranslator; if (mTranslator != null) { mSurface.setCompatibilityTranslator(mTranslator); } @@ -433,15 +452,17 @@ public class SurfaceView extends View { int myHeight = mRequestedHeight; if (myHeight <= 0) myHeight = getHeight(); + final boolean creating = mWindow == null; final boolean formatChanged = mFormat != mRequestedFormat; - final boolean creating = (mSurfaceControl == null || formatChanged) - && mRequestedVisible; - final boolean sizeChanged = mSurfaceWidth != myWidth || mSurfaceHeight != myHeight; + final boolean sizeChanged = mWindowSpaceWidth != myWidth || mWindowSpaceHeight != myHeight; final boolean visibleChanged = mVisible != mRequestedVisible; - final boolean windowVisibleChanged = mWindowVisibility != mLastWindowVisibility; + final boolean layoutSizeChanged = getWidth() != mLayout.width + || getHeight() != mLayout.height; + boolean redrawNeeded = false; - if (creating || formatChanged || sizeChanged || visibleChanged || windowVisibleChanged) { + if (creating || formatChanged || sizeChanged || visibleChanged + || mUpdateWindowNeeded || mReportDrawNeeded) { getLocationInWindow(mLocation); if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " @@ -455,77 +476,93 @@ public class SurfaceView extends View { final boolean visible = mVisible = mRequestedVisible; mWindowSpaceLeft = mLocation[0]; mWindowSpaceTop = mLocation[1]; - mSurfaceWidth = myWidth; - mSurfaceHeight = myHeight; + mWindowSpaceWidth = myWidth; + mWindowSpaceHeight = myHeight; mFormat = mRequestedFormat; - mLastWindowVisibility = mWindowVisibility; - mScreenRect.left = mWindowSpaceLeft; - mScreenRect.top = mWindowSpaceTop; - mScreenRect.right = mWindowSpaceLeft + getWidth(); - mScreenRect.bottom = mWindowSpaceTop + getHeight(); + // Scaling/Translate window's layout here because mLayout is not used elsewhere. + + // Places the window relative + mLayout.x = mWindowSpaceLeft; + mLayout.y = mWindowSpaceTop; + mLayout.width = getWidth(); + mLayout.height = getHeight(); if (mTranslator != null) { - mTranslator.translateRectInAppWindowToScreen(mScreenRect); + mTranslator.translateLayoutParamsInAppWindowToScreen(mLayout); } - final Rect surfaceInsets = getParentSurfaceInsets(); - mScreenRect.offset(surfaceInsets.left, surfaceInsets.top); + mLayout.format = mRequestedFormat; + mLayout.flags |=WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE + | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS + | WindowManager.LayoutParams.FLAG_SCALED + | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE + ; + if (!creating && !sizeChanged) { + mLayout.privateFlags |= + WindowManager.LayoutParams.PRIVATE_FLAG_PRESERVE_GEOMETRY; + } else { + mLayout.privateFlags &= + ~WindowManager.LayoutParams.PRIVATE_FLAG_PRESERVE_GEOMETRY; + } - if (creating) { - mSurfaceSession = new SurfaceSession(viewRoot.mSurface); - mSurfaceControl = new SurfaceControl(mSurfaceSession, - "SurfaceView - " + viewRoot.getTitle().toString(), - mSurfaceWidth, mSurfaceHeight, mFormat, - mSurfaceFlags); + if (!getContext().getResources().getCompatibilityInfo().supportsScreen()) { + mLayout.privateFlags |= + WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW; + } + mLayout.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION + | WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME; + + if (mWindow == null) { + Display display = getDisplay(); + mWindow = new MyWindow(this); + mLayout.type = mWindowType; + mLayout.gravity = Gravity.START|Gravity.TOP; + mSession.addToDisplayWithoutInputChannel(mWindow, mWindow.mSeq, mLayout, + mVisible ? VISIBLE : GONE, display.getDisplayId(), mContentInsets, + mStableInsets); } - boolean realSizeChanged = false; + boolean realSizeChanged; + boolean reportDrawNeeded; + + int relayoutResult; mSurfaceLock.lock(); try { + mUpdateWindowNeeded = false; + reportDrawNeeded = mReportDrawNeeded; + mReportDrawNeeded = false; mDrawingStopped = !visible; if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Cur surface: " + mSurface); - SurfaceControl.openTransaction(); - try { - mSurfaceControl.setLayer(mSubLayer); - if (mViewVisibility) { - mSurfaceControl.show(); - } else { - mSurfaceControl.hide(); - } - - // While creating the surface, we will set it's initial - // geometry. Outside of that though, we should generally - // leave it to the RenderThread. - if (creating || !mRtHandlingPositionUpdates) { - mSurfaceControl.setPosition(mScreenRect.left, mScreenRect.top); - mSurfaceControl.setMatrix(mScreenRect.width() / (float) mSurfaceWidth, - 0.0f, 0.0f, - mScreenRect.height() / (float) mSurfaceHeight); - } - if (sizeChanged) { - mSurfaceControl.setSize(mSurfaceWidth, mSurfaceHeight); - } - } finally { - SurfaceControl.closeTransaction(); + relayoutResult = mSession.relayout( + mWindow, mWindow.mSeq, mLayout, mWindowSpaceWidth, mWindowSpaceHeight, + visible ? VISIBLE : GONE, + WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY, + mWinFrame, mOverscanInsets, mContentInsets, + mVisibleInsets, mStableInsets, mOutsets, mBackdropFrame, + mConfiguration, mNewSurface); + if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) { + reportDrawNeeded = true; } - if (sizeChanged || creating) { - redrawNeeded = true; - } + if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + + "New surface: " + mNewSurface + + ", vis=" + visible + ", frame=" + mWinFrame); mSurfaceFrame.left = 0; mSurfaceFrame.top = 0; if (mTranslator == null) { - mSurfaceFrame.right = mSurfaceWidth; - mSurfaceFrame.bottom = mSurfaceHeight; + mSurfaceFrame.right = mWinFrame.width(); + mSurfaceFrame.bottom = mWinFrame.height(); } else { float appInvertedScale = mTranslator.applicationInvertedScale; - mSurfaceFrame.right = (int) (mSurfaceWidth * appInvertedScale + 0.5f); - mSurfaceFrame.bottom = (int) (mSurfaceHeight * appInvertedScale + 0.5f); + mSurfaceFrame.right = (int) (mWinFrame.width() * appInvertedScale + 0.5f); + mSurfaceFrame.bottom = (int) (mWinFrame.height() * appInvertedScale + 0.5f); } final int surfaceWidth = mSurfaceFrame.right; @@ -539,11 +576,12 @@ public class SurfaceView extends View { } try { - redrawNeeded |= visible && !mDrawFinished; + redrawNeeded |= creating | reportDrawNeeded; SurfaceHolder.Callback callbacks[] = null; - final boolean surfaceChanged = creating; + final boolean surfaceChanged = (relayoutResult + & WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED) != 0; if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) { mSurfaceCreated = false; if (mSurface.isValid()) { @@ -570,10 +608,7 @@ public class SurfaceView extends View { } } - if (creating) { - mSurface.copyFrom(mSurfaceControl); - } - + mSurface.transferFrom(mNewSurface); if (visible && mSurface.isValid()) { if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) { mSurfaceCreated = true; @@ -606,55 +641,53 @@ public class SurfaceView extends View { callbacks = getSurfaceCallbacks(); } SurfaceCallbackHelper sch = - new SurfaceCallbackHelper(this::onDrawFinished); + new SurfaceCallbackHelper(mSession, mWindow); sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks); } } } finally { mIsCreating = false; - if (mSurfaceControl != null && !mSurfaceCreated) { - mSurfaceControl.destroy(); - mSurfaceControl = null; - } + mSession.performDeferredDestroy(mWindow); } - } catch (Exception ex) { + } catch (RemoteException ex) { Log.e(TAG, "Exception from relayout", ex); } if (DEBUG) Log.v( - TAG, "Layout: x=" + mScreenRect.left + " y=" + mScreenRect.top - + " w=" + mScreenRect.width() + " h=" + mScreenRect.height() - + ", frame=" + mSurfaceFrame); + TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y + + " w=" + mLayout.width + " h=" + mLayout.height + + ", frame=" + mSurfaceFrame); } else { // Calculate the window position in case RT loses the window // and we need to fallback to a UI-thread driven position update - getLocationInSurface(mLocation); + getLocationInWindow(mLocation); final boolean positionChanged = mWindowSpaceLeft != mLocation[0] || mWindowSpaceTop != mLocation[1]; - final boolean layoutSizeChanged = getWidth() != mScreenRect.width() - || getHeight() != mScreenRect.height(); if (positionChanged || layoutSizeChanged) { // Only the position has changed mWindowSpaceLeft = mLocation[0]; mWindowSpaceTop = mLocation[1]; - // For our size changed check, we keep mScreenRect.width() and mScreenRect.height() + // For our size changed check, we keep mLayout.width and mLayout.height // in view local space. - mLocation[0] = getWidth(); - mLocation[1] = getHeight(); + mLocation[0] = mLayout.width = getWidth(); + mLocation[1] = mLayout.height = getHeight(); + + transformFromViewToWindowSpace(mLocation); - mScreenRect.set(mWindowSpaceLeft, mWindowSpaceTop, + mTmpRect.set(mWindowSpaceLeft, mWindowSpaceTop, mLocation[0], mLocation[1]); if (mTranslator != null) { - mTranslator.translateRectInAppWindowToScreen(mScreenRect); + mTranslator.translateRectInAppWindowToScreen(mTmpRect); } if (!isHardwareAccelerated() || !mRtHandlingPositionUpdates) { try { - if (DEBUG) Log.d(TAG, String.format("%d updateSurfacePosition UI, " + + if (DEBUG) Log.d(TAG, String.format("%d updateWindowPosition UI, " + "postion = [%d, %d, %d, %d]", System.identityHashCode(this), - mScreenRect.left, mScreenRect.top, - mScreenRect.right, mScreenRect.bottom)); - setParentSpaceRectangle(mScreenRect, -1); - } catch (Exception ex) { + mTmpRect.left, mTmpRect.top, + mTmpRect.right, mTmpRect.bottom)); + mSession.repositionChild(mWindow, mTmpRect.left, mTmpRect.top, + mTmpRect.right, mTmpRect.bottom, -1, mTmpRect); + } catch (RemoteException ex) { Log.e(TAG, "Exception from relayout", ex); } } @@ -662,43 +695,20 @@ public class SurfaceView extends View { } } - private void onDrawFinished() { - if (DEBUG) { - Log.i(TAG, System.identityHashCode(this) + " " - + "finishedDrawing"); - } - mHandler.sendEmptyMessage(DRAW_FINISHED_MSG); - } - - private void setParentSpaceRectangle(Rect position, long frameNumber) { - ViewRootImpl viewRoot = getViewRootImpl(); - - SurfaceControl.openTransaction(); - try { - if (frameNumber > 0) { - mSurfaceControl.deferTransactionUntil(viewRoot.mSurface, frameNumber); - } - mSurfaceControl.setPosition(position.left, position.top); - mSurfaceControl.setMatrix(position.width() / (float) mSurfaceWidth, - 0.0f, 0.0f, - position.height() / (float) mSurfaceHeight); - } finally { - SurfaceControl.closeTransaction(); - } - } - private Rect mRTLastReportedPosition = new Rect(); /** * Called by native by a Rendering Worker thread to update the window position * @hide */ - public final void updateSurfacePosition_renderWorker(long frameNumber, + public final void updateWindowPosition_renderWorker(long frameNumber, int left, int top, int right, int bottom) { - if (mSurfaceControl == null) { + IWindowSession session = mSession; + MyWindow window = mWindow; + if (session == null || window == null) { + // Guess we got detached, that sucks return; } - // TODO: This is teensy bit racey in that a brand new SurfaceView moving on // its 2nd frame if RenderThread is running slowly could potentially see // this as false, enter the branch, get pre-empted, then this comes along @@ -716,29 +726,35 @@ public class SurfaceView extends View { } try { if (DEBUG) { - Log.d(TAG, String.format("%d updateSurfacePosition RenderWorker, frameNr = %d, " + + Log.d(TAG, String.format("%d updateWindowPosition RenderWorker, frameNr = %d, " + "postion = [%d, %d, %d, %d]", System.identityHashCode(this), frameNumber, left, top, right, bottom)); } - mRTLastReportedPosition.set(left, top, right, bottom); - setParentSpaceRectangle(mRTLastReportedPosition, frameNumber); + // Just using mRTLastReportedPosition as a dummy rect here + session.repositionChild(window, left, top, right, bottom, + frameNumber, + mRTLastReportedPosition); // Now overwrite mRTLastReportedPosition with our values - } catch (Exception ex) { + mRTLastReportedPosition.set(left, top, right, bottom); + } catch (RemoteException ex) { Log.e(TAG, "Exception from repositionChild", ex); } } /** - * Called by native on RenderThread to notify that the view is no longer in the + * Called by native on RenderThread to notify that the window is no longer in the * draw tree. UI thread is blocked at this point. * @hide */ - public final void surfacePositionLost_uiRtSync(long frameNumber) { + public final void windowPositionLost_uiRtSync(long frameNumber) { if (DEBUG) { Log.d(TAG, String.format("%d windowPositionLost, frameNr = %d", System.identityHashCode(this), frameNumber)); } - if (mSurfaceControl == null) { + IWindowSession session = mSession; + MyWindow window = mWindow; + if (session == null || window == null) { + // We got detached prior to receiving this, abort return; } if (mRtHandlingPositionUpdates) { @@ -747,14 +763,19 @@ public class SurfaceView extends View { // safely access other member variables at this time. // So do what the UI thread would have done if RT wasn't handling position // updates. - if (!mScreenRect.isEmpty() && !mScreenRect.equals(mRTLastReportedPosition)) { + mTmpRect.set(mLayout.x, mLayout.y, + mLayout.x + mLayout.width, + mLayout.y + mLayout.height); + + if (!mTmpRect.isEmpty() && !mTmpRect.equals(mRTLastReportedPosition)) { try { - if (DEBUG) Log.d(TAG, String.format("%d updateSurfacePosition, " + + if (DEBUG) Log.d(TAG, String.format("%d updateWindowPosition, " + "postion = [%d, %d, %d, %d]", System.identityHashCode(this), - mScreenRect.left, mScreenRect.top, - mScreenRect.right, mScreenRect.bottom)); - setParentSpaceRectangle(mScreenRect, frameNumber); - } catch (Exception ex) { + mTmpRect.left, mTmpRect.top, + mTmpRect.right, mTmpRect.bottom)); + session.repositionChild(window, mTmpRect.left, mTmpRect.top, + mTmpRect.right, mTmpRect.bottom, frameNumber, mWinFrame); + } catch (RemoteException ex) { Log.e(TAG, "Exception from relayout", ex); } } @@ -771,6 +792,10 @@ public class SurfaceView extends View { return callbacks; } + void handleGetNewSurface() { + updateWindow(); + } + /** * Check to see if the surface has fixed size dimensions or if the surface's * dimensions are dimensions are dependent on its current layout. @@ -782,8 +807,65 @@ public class SurfaceView extends View { return (mRequestedWidth != -1 || mRequestedHeight != -1); } - private boolean isAboveParent() { - return mSubLayer >= 0; + private static class MyWindow extends BaseIWindow { + private final WeakReference<SurfaceView> mSurfaceView; + + public MyWindow(SurfaceView surfaceView) { + mSurfaceView = new WeakReference<SurfaceView>(surfaceView); + } + + @Override + public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, + Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw, + Configuration newConfig, Rect backDropRect, boolean forceLayout, + boolean alwaysConsumeNavBar, int displayId) { + SurfaceView surfaceView = mSurfaceView.get(); + if (surfaceView != null) { + if (DEBUG) Log.v(TAG, surfaceView + " got resized: w=" + frame.width() + + " h=" + frame.height() + ", cur w=" + mCurWidth + " h=" + mCurHeight); + surfaceView.mSurfaceLock.lock(); + try { + if (reportDraw) { + surfaceView.mUpdateWindowNeeded = true; + surfaceView.mReportDrawNeeded = true; + surfaceView.mHandler.sendEmptyMessage(UPDATE_WINDOW_MSG); + } else if (surfaceView.mWinFrame.width() != frame.width() + || surfaceView.mWinFrame.height() != frame.height() + || forceLayout) { + surfaceView.mUpdateWindowNeeded = true; + surfaceView.mHandler.sendEmptyMessage(UPDATE_WINDOW_MSG); + } + } finally { + surfaceView.mSurfaceLock.unlock(); + } + } + } + + @Override + public void dispatchAppVisibility(boolean visible) { + // The point of SurfaceView is to let the app control the surface. + } + + @Override + public void dispatchGetNewSurface() { + SurfaceView surfaceView = mSurfaceView.get(); + if (surfaceView != null) { + Message msg = surfaceView.mHandler.obtainMessage(GET_NEW_SURFACE_MSG); + surfaceView.mHandler.sendMessage(msg); + } + } + + @Override + public void windowFocusChanged(boolean hasFocus, boolean touchEnabled) { + Log.w("SurfaceView", "Unexpected focus in surface: focus=" + hasFocus + ", touchEnabled=" + touchEnabled); + } + + @Override + public void executeCommand(String command, String parameters, ParcelFileDescriptor out) { + } + + int mCurWidth = -1; + int mCurHeight = -1; } private final SurfaceHolder mSurfaceHolder = new SurfaceHolder() { @@ -831,14 +913,15 @@ public class SurfaceView extends View { @Override public void setFormat(int format) { + // for backward compatibility reason, OPAQUE always // means 565 for SurfaceView if (format == PixelFormat.OPAQUE) format = PixelFormat.RGB_565; mRequestedFormat = format; - if (mSurfaceControl != null) { - updateSurface(); + if (mWindow != null) { + updateWindow(); } } @@ -899,10 +982,10 @@ public class SurfaceView extends View { mSurfaceLock.lock(); if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Locking canvas... stopped=" - + mDrawingStopped + ", surfaceControl=" + mSurfaceControl); + + mDrawingStopped + ", win=" + mWindow); Canvas c = null; - if (!mDrawingStopped && mSurfaceControl != null) { + if (!mDrawingStopped && mWindow != null) { try { if (hardware) { c = mSurface.lockHardwareCanvas(); diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index f9863b0a6761..20d960fff661 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -2632,14 +2632,6 @@ public final class ViewRootImpl implements ViewParent, } } - private void onDrawFinished() { - try { - mWindowSession.finishDrawing(mWindow); - } catch (RemoteException e) { - // Have fun! - } - } - private void performDraw() { if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) { return; @@ -2690,7 +2682,7 @@ public final class ViewRootImpl implements ViewParent, } if (mSurfaceHolder != null && mSurface.isValid()) { - SurfaceCallbackHelper sch = new SurfaceCallbackHelper(this::onDrawFinished); + SurfaceCallbackHelper sch = new SurfaceCallbackHelper(mWindowSession, mWindow); SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks(); sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks); diff --git a/core/java/com/android/internal/view/SurfaceCallbackHelper.java b/core/java/com/android/internal/view/SurfaceCallbackHelper.java index 507b673ec279..5b6a82cf1c43 100644 --- a/core/java/com/android/internal/view/SurfaceCallbackHelper.java +++ b/core/java/com/android/internal/view/SurfaceCallbackHelper.java @@ -17,11 +17,14 @@ package com.android.internal.view; import android.os.RemoteException; +import android.view.IWindow; +import android.view.IWindowSession; import android.view.Surface; import android.view.SurfaceHolder; public class SurfaceCallbackHelper { - Runnable mRunnable; + IWindowSession mSession; + IWindow.Stub mWindow; int mFinishDrawingCollected = 0; int mFinishDrawingExpected = 0; @@ -34,18 +37,26 @@ public class SurfaceCallbackHelper { if (mFinishDrawingCollected < mFinishDrawingExpected) { return; } - mRunnable.run(); + try { + mSession.finishDrawing(mWindow); + } catch (RemoteException e) { + } } } }; - public SurfaceCallbackHelper(Runnable callbacksCollected) { - mRunnable = callbacksCollected; + public SurfaceCallbackHelper(IWindowSession session, + IWindow.Stub window) { + mSession = session; + mWindow = window; } public void dispatchSurfaceRedrawNeededAsync(SurfaceHolder holder, SurfaceHolder.Callback callbacks[]) { if (callbacks == null || callbacks.length == 0) { - mRunnable.run(); + try { + mSession.finishDrawing(mWindow); + } catch (RemoteException e) { + } return; } diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp index 6e8c93132562..f221392f16bd 100644 --- a/core/jni/android_view_RenderNode.cpp +++ b/core/jni/android_view_RenderNode.cpp @@ -452,6 +452,10 @@ static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject, const RenderProperties& props = node.properties(); uirenderer::Rect bounds(props.getWidth(), props.getHeight()); transform.mapRect(bounds); + bounds.left -= info.windowInsetLeft; + bounds.right -= info.windowInsetLeft; + bounds.top -= info.windowInsetTop; + bounds.bottom -= info.windowInsetTop; if (CC_LIKELY(transform.isPureTranslate())) { // snap/round the computed bounds, so they match the rounding behavior @@ -623,9 +627,9 @@ static const JNINativeMethod gMethods[] = { int register_android_view_RenderNode(JNIEnv* env) { jclass clazz = FindClassOrDie(env, "android/view/SurfaceView"); gSurfaceViewPositionUpdateMethod = GetMethodIDOrDie(env, clazz, - "updateSurfacePosition_renderWorker", "(JIIII)V"); + "updateWindowPosition_renderWorker", "(JIIII)V"); gSurfaceViewPositionLostMethod = GetMethodIDOrDie(env, clazz, - "surfacePositionLost_uiRtSync", "(J)V"); + "windowPositionLost_uiRtSync", "(J)V"); return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods)); } diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index be86f5c6b8ab..a81901df9a1b 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -693,6 +693,7 @@ static jboolean nativeGetAnimationFrameStats(JNIEnv* env, jclass clazz, jobject return JNI_TRUE; } + static void nativeDeferTransactionUntil(JNIEnv* env, jclass clazz, jlong nativeObject, jobject handleObject, jlong frameNumber) { auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject); @@ -701,27 +702,6 @@ static void nativeDeferTransactionUntil(JNIEnv* env, jclass clazz, jlong nativeO ctrl->deferTransactionUntil(handle, frameNumber); } -static void nativeDeferTransactionUntilSurface(JNIEnv* env, jclass clazz, jlong nativeObject, - jobject surfaceObject, jlong frameNumber) { - auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject); - sp<Surface> barrier = reinterpret_cast<Surface *>(surfaceObject); - - ctrl->deferTransactionUntil(barrier, frameNumber); -} - -static void nativeReparentChildren(JNIEnv* env, jclass clazz, jlong nativeObject, - jobject newParentObject) { - auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject); - sp<IBinder> handle = ibinderForJavaObject(env, newParentObject); - - ctrl->reparentChildren(handle); -} - -static void nativeSeverChildren(JNIEnv* env, jclass clazz, jlong nativeObject) { - auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject); - ctrl->detachChildren(); -} - static void nativeSetOverrideScalingMode(JNIEnv* env, jclass clazz, jlong nativeObject, jint scalingMode) { auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject); @@ -844,12 +824,6 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeSetDisplayPowerMode }, {"nativeDeferTransactionUntil", "(JLandroid/os/IBinder;J)V", (void*)nativeDeferTransactionUntil }, - {"nativeDeferTransactionUntilSurface", "(JJJ)V", - (void*)nativeDeferTransactionUntilSurface }, - {"nativeReparentChildren", "(JLandroid/os/IBinder;)V", - (void*)nativeReparentChildren } , - {"nativeSeverChildren", "(J)V", - (void*)nativeSeverChildren } , {"nativeSetOverrideScalingMode", "(JI)V", (void*)nativeSetOverrideScalingMode }, {"nativeGetHandle", "(J)Landroid/os/IBinder;", diff --git a/core/jni/android_view_SurfaceSession.cpp b/core/jni/android_view_SurfaceSession.cpp index 508d89795569..dad6958560c0 100644 --- a/core/jni/android_view_SurfaceSession.cpp +++ b/core/jni/android_view_SurfaceSession.cpp @@ -24,7 +24,6 @@ #include <utils/RefBase.h> #include <gui/SurfaceComposerClient.h> -#include <gui/Surface.h> namespace android { @@ -46,13 +45,6 @@ static jlong nativeCreate(JNIEnv* env, jclass clazz) { return reinterpret_cast<jlong>(client); } -static jlong nativeCreateScoped(JNIEnv* env, jclass clazz, jlong surfaceObject) { - Surface *parent = reinterpret_cast<Surface*>(surfaceObject); - SurfaceComposerClient* client = new SurfaceComposerClient(parent->getIGraphicBufferProducer()); - client->incStrong((void*)nativeCreate); - return reinterpret_cast<jlong>(client); -} - static void nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) { SurfaceComposerClient* client = reinterpret_cast<SurfaceComposerClient*>(ptr); client->decStrong((void*)nativeCreate); @@ -63,12 +55,11 @@ static void nativeKill(JNIEnv* env, jclass clazz, jlong ptr) { client->dispose(); } + static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ { "nativeCreate", "()J", (void*)nativeCreate }, - { "nativeCreateScoped", "(J)J", - (void*)nativeCreateScoped }, { "nativeDestroy", "(J)V", (void*)nativeDestroy }, { "nativeKill", "(J)V", diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp index 99edf6ef944e..37eae48a7a11 100644 --- a/core/jni/android_view_ThreadedRenderer.cpp +++ b/core/jni/android_view_ThreadedRenderer.cpp @@ -178,9 +178,13 @@ public: } } // TODO: This is hacky + info.windowInsetLeft = -stagingProperties().getLeft(); + info.windowInsetTop = -stagingProperties().getTop(); info.updateWindowPositions = true; RenderNode::prepareTree(info); info.updateWindowPositions = false; + info.windowInsetLeft = 0; + info.windowInsetTop = 0; info.errorHandler = nullptr; } diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp index 59a536b1b001..9660de4dbba4 100644 --- a/core/jni/fd_utils.cpp +++ b/core/jni/fd_utils.cpp @@ -26,8 +26,8 @@ #include <sys/un.h> #include <unistd.h> +#include <android-base/logging.h> #include <android-base/strings.h> -#include <cutils/log.h> // Static whitelist of open paths that the zygote is allowed to keep open. static const char* kPathWhitelist[] = { @@ -137,7 +137,7 @@ FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd) { // This should never happen; the zygote should always have the right set // of permissions required to stat all its open files. if (TEMP_FAILURE_RETRY(fstat(fd, &f_stat)) == -1) { - ALOGE("Unable to stat fd %d : %s", fd, strerror(errno)); + PLOG(ERROR) << "Unable to stat fd " << fd; return NULL; } @@ -150,7 +150,8 @@ FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd) { } if (!whitelist->IsAllowed(socket_name)) { - ALOGE("Socket name not whitelisted : %s (fd=%d)", socket_name.c_str(), fd); + LOG(ERROR) << "Socket name not whitelisted : " << socket_name + << " (fd=" << fd << ")"; return NULL; } @@ -168,7 +169,7 @@ FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd) { // with the child process across forks but those should have been closed // before we got to this point. if (!S_ISCHR(f_stat.st_mode) && !S_ISREG(f_stat.st_mode)) { - ALOGE("Unsupported st_mode %d", f_stat.st_mode); + LOG(ERROR) << "Unsupported st_mode " << f_stat.st_mode; return NULL; } @@ -178,7 +179,7 @@ FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd) { } if (!whitelist->IsAllowed(file_path)) { - ALOGE("Not whitelisted : %s", file_path.c_str()); + LOG(ERROR) << "Not whitelisted : " << file_path; return NULL; } @@ -187,7 +188,7 @@ FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd) { // there won't be any races. const int fd_flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD)); if (fd_flags == -1) { - ALOGE("Failed fcntl(%d, F_GETFD) : %s", fd, strerror(errno)); + PLOG(ERROR) << "Failed fcntl(" << fd << ", F_GETFD)"; return NULL; } @@ -205,7 +206,7 @@ FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd) { // their presence and pass them in to open(). int fs_flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL)); if (fs_flags == -1) { - ALOGE("Failed fcntl(%d, F_GETFL) : %s", fd, strerror(errno)); + PLOG(ERROR) << "Failed fcntl(" << fd << ", F_GETFL)"; return NULL; } @@ -224,6 +225,7 @@ FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd) { bool FileDescriptorInfo::Restat() const { struct stat f_stat; if (TEMP_FAILURE_RETRY(fstat(fd, &f_stat)) == -1) { + PLOG(ERROR) << "Unable to restat fd " << fd; return false; } @@ -241,31 +243,31 @@ bool FileDescriptorInfo::ReopenOrDetach() const { const int new_fd = TEMP_FAILURE_RETRY(open(file_path.c_str(), open_flags)); if (new_fd == -1) { - ALOGE("Failed open(%s, %d) : %s", file_path.c_str(), open_flags, strerror(errno)); + PLOG(ERROR) << "Failed open(" << file_path << ", " << open_flags << ")"; return false; } if (TEMP_FAILURE_RETRY(fcntl(new_fd, F_SETFD, fd_flags)) == -1) { close(new_fd); - ALOGE("Failed fcntl(%d, F_SETFD, %x) : %s", new_fd, fd_flags, strerror(errno)); + PLOG(ERROR) << "Failed fcntl(" << new_fd << ", F_SETFD, " << fd_flags << ")"; return false; } if (TEMP_FAILURE_RETRY(fcntl(new_fd, F_SETFL, fs_flags)) == -1) { close(new_fd); - ALOGE("Failed fcntl(%d, F_SETFL, %x) : %s", new_fd, fs_flags, strerror(errno)); + PLOG(ERROR) << "Failed fcntl(" << new_fd << ", F_SETFL, " << fs_flags << ")"; return false; } if (offset != -1 && TEMP_FAILURE_RETRY(lseek64(new_fd, offset, SEEK_SET)) == -1) { close(new_fd); - ALOGE("Failed lseek64(%d, SEEK_SET) : %s", new_fd, strerror(errno)); + PLOG(ERROR) << "Failed lseek64(" << new_fd << ", SEEK_SET)"; return false; } if (TEMP_FAILURE_RETRY(dup2(new_fd, fd)) == -1) { close(new_fd); - ALOGE("Failed dup2(%d, %d) : %s", fd, new_fd, strerror(errno)); + PLOG(ERROR) << "Failed dup2(" << fd << ", " << new_fd << ")"; return false; } @@ -312,7 +314,10 @@ bool FileDescriptorInfo::Readlink(const int fd, std::string* result) { // ext2 and ext4 both have PAGE_SIZE limitations, so we assume that here. char buf[4096]; ssize_t len = readlink(path, buf, sizeof(buf)); - if (len == -1) return false; + if (len == -1) { + PLOG(ERROR) << "Readlink on " << fd << " failed."; + return false; + } result->assign(buf, len); return true; @@ -325,12 +330,12 @@ bool FileDescriptorInfo::GetSocketName(const int fd, std::string* result) { socklen_t addr_len = sizeof(ss); if (TEMP_FAILURE_RETRY(getsockname(fd, addr, &addr_len)) == -1) { - ALOGE("Failed getsockname(%d) : %s", fd, strerror(errno)); + PLOG(ERROR) << "Failed getsockname(" << fd << ")"; return false; } if (addr->sa_family != AF_UNIX) { - ALOGE("Unsupported socket (fd=%d) with family %d", fd, addr->sa_family); + LOG(ERROR) << "Unsupported socket (fd=" << fd << ") with family " << addr->sa_family; return false; } @@ -339,13 +344,13 @@ bool FileDescriptorInfo::GetSocketName(const int fd, std::string* result) { size_t path_len = addr_len - offsetof(struct sockaddr_un, sun_path); // This is an unnamed local socket, we do not accept it. if (path_len == 0) { - ALOGE("Unsupported AF_UNIX socket (fd=%d) with empty path.", fd); + LOG(ERROR) << "Unsupported AF_UNIX socket (fd=" << fd << ") with empty path."; return false; } // This is a local socket with an abstract address, we do not accept it. if (unix_addr->sun_path[0] == '\0') { - ALOGE("Unsupported AF_UNIX socket (fd=%d) with abstract address.", fd); + LOG(ERROR) << "Unsupported AF_UNIX socket (fd=" << fd << ") with abstract address."; return false; } @@ -363,17 +368,17 @@ bool FileDescriptorInfo::GetSocketName(const int fd, std::string* result) { bool FileDescriptorInfo::DetachSocket() const { const int dev_null_fd = open("/dev/null", O_RDWR); if (dev_null_fd < 0) { - ALOGE("Failed to open /dev/null : %s", strerror(errno)); + PLOG(ERROR) << "Failed to open /dev/null"; return false; } if (dup2(dev_null_fd, fd) == -1) { - ALOGE("Failed dup2 on socket descriptor %d : %s", fd, strerror(errno)); + PLOG(ERROR) << "Failed dup2 on socket descriptor " << fd; return false; } if (close(dev_null_fd) == -1) { - ALOGE("Failed close(%d) : %s", dev_null_fd, strerror(errno)); + PLOG(ERROR) << "Failed close(" << dev_null_fd << ")"; return false; } @@ -384,7 +389,7 @@ bool FileDescriptorInfo::DetachSocket() const { FileDescriptorTable* FileDescriptorTable::Create(const std::vector<int>& fds_to_ignore) { DIR* d = opendir(kFdPath); if (d == NULL) { - ALOGE("Unable to open directory %s: %s", kFdPath, strerror(errno)); + PLOG(ERROR) << "Unable to open directory " << std::string(kFdPath); return NULL; } int dir_fd = dirfd(d); @@ -397,14 +402,14 @@ FileDescriptorTable* FileDescriptorTable::Create(const std::vector<int>& fds_to_ continue; } if (std::find(fds_to_ignore.begin(), fds_to_ignore.end(), fd) != fds_to_ignore.end()) { - ALOGI("Ignoring open file descriptor %d", fd); + LOG(INFO) << "Ignoring open file descriptor " << fd; continue; } FileDescriptorInfo* info = FileDescriptorInfo::CreateFromFd(fd); if (info == NULL) { if (closedir(d) == -1) { - ALOGE("Unable to close directory : %s", strerror(errno)); + PLOG(ERROR) << "Unable to close directory"; } return NULL; } @@ -412,7 +417,7 @@ FileDescriptorTable* FileDescriptorTable::Create(const std::vector<int>& fds_to_ } if (closedir(d) == -1) { - ALOGE("Unable to close directory : %s", strerror(errno)); + PLOG(ERROR) << "Unable to close directory"; return NULL; } return new FileDescriptorTable(open_fd_map); @@ -424,7 +429,7 @@ bool FileDescriptorTable::Restat(const std::vector<int>& fds_to_ignore) { // First get the list of open descriptors. DIR* d = opendir(kFdPath); if (d == NULL) { - ALOGE("Unable to open directory %s: %s", kFdPath, strerror(errno)); + PLOG(ERROR) << "Unable to open directory " << std::string(kFdPath); return false; } @@ -436,7 +441,7 @@ bool FileDescriptorTable::Restat(const std::vector<int>& fds_to_ignore) { continue; } if (std::find(fds_to_ignore.begin(), fds_to_ignore.end(), fd) != fds_to_ignore.end()) { - ALOGI("Ignoring open file descriptor %d", fd); + LOG(INFO) << "Ignoring open file descriptor " << fd; continue; } @@ -444,7 +449,7 @@ bool FileDescriptorTable::Restat(const std::vector<int>& fds_to_ignore) { } if (closedir(d) == -1) { - ALOGE("Unable to close directory : %s", strerror(errno)); + PLOG(ERROR) << "Unable to close directory"; return false; } diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp index 35ff635930ab..1b57e290c198 100644 --- a/libs/hwui/FrameBuilder.cpp +++ b/libs/hwui/FrameBuilder.cpp @@ -78,7 +78,7 @@ void FrameBuilder::deferLayers(const LayerUpdateQueue& layers) { // Render all layers to be updated, in order. Defer in reverse order, so that they'll be // updated in the order they're passed in (mLayerBuilders are issued to Renderer in reverse) for (int i = layers.entries().size() - 1; i >= 0; i--) { - RenderNode* layerNode = layers.entries()[i].renderNode; + RenderNode* layerNode = layers.entries()[i].renderNode.get(); // only schedule repaint if node still on layer - possible it may have been // removed during a dropped frame, but layers may still remain scheduled so // as not to lose info on what portion is damaged diff --git a/libs/hwui/LayerUpdateQueue.h b/libs/hwui/LayerUpdateQueue.h index 5b1a8543dd0d..38f3596d70df 100644 --- a/libs/hwui/LayerUpdateQueue.h +++ b/libs/hwui/LayerUpdateQueue.h @@ -19,6 +19,7 @@ #include "Rect.h" #include "utils/Macros.h" +#include <utils/StrongPointer.h> #include <vector> #include <unordered_map> @@ -35,7 +36,7 @@ public: Entry(RenderNode* renderNode, const Rect& damage) : renderNode(renderNode) , damage(damage) {} - RenderNode* renderNode; + sp<RenderNode> renderNode; Rect damage; }; diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h index e39614b6a5ea..c6fbe2bd55de 100644 --- a/libs/hwui/TreeInfo.h +++ b/libs/hwui/TreeInfo.h @@ -91,6 +91,8 @@ public: LayerUpdateQueue* layerUpdateQueue = nullptr; ErrorHandler* errorHandler = nullptr; + int32_t windowInsetLeft = 0; + int32_t windowInsetTop = 0; bool updateWindowPositions = false; struct Out { diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp index 117395bfc75c..39f11b8e6bfe 100644 --- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp +++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp @@ -197,12 +197,12 @@ void RenderNodeDrawable::drawContent(SkCanvas* canvas) const { if (needsLayer) { canvas->saveLayer(bounds, &paint); } - canvas->drawDrawable(displayList->mDrawable.get()); + displayList->draw(canvas); if (needsLayer) { canvas->restore(); } } else { - canvas->drawDrawable(displayList->mDrawable.get()); + displayList->draw(canvas); } } } diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp index b4babcb9564e..496f7babd3cc 100644 --- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp +++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp @@ -27,10 +27,6 @@ namespace android { namespace uirenderer { namespace skiapipeline { -SkiaDisplayList::SkiaDisplayList(SkRect bounds) : mDrawable(SkLiteDL::New(bounds)) { - SkASSERT(projectionReceiveIndex == -1); -} - void SkiaDisplayList::syncContents() { for (auto& functor : mChildFunctors) { functor.syncFunctor(); @@ -41,7 +37,7 @@ void SkiaDisplayList::syncContents() { } bool SkiaDisplayList::reuseDisplayList(RenderNode* node, renderthread::CanvasContext* context) { - reset(SkRect::MakeEmpty()); + reset(); node->attachAvailableList(this); return true; } @@ -102,10 +98,10 @@ bool SkiaDisplayList::prepareListAndChildren(TreeObserver& observer, TreeInfo& i return isDirty; } -void SkiaDisplayList::reset(SkRect bounds) { +void SkiaDisplayList::reset() { mProjectionReceiver = nullptr; - mDrawable->reset(bounds); + mDisplayList.reset(); mMutableImages.clear(); mVectorDrawables.clear(); @@ -119,7 +115,7 @@ void SkiaDisplayList::reset(SkRect bounds) { void SkiaDisplayList::output(std::ostream& output, uint32_t level) { DumpOpsCanvas canvas(output, level, *this); - mDrawable->draw(&canvas, nullptr); + mDisplayList.draw(&canvas); } }; // namespace skiapipeline diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.h b/libs/hwui/pipeline/skia/SkiaDisplayList.h index 439b999380ac..6ee5922f9cd6 100644 --- a/libs/hwui/pipeline/skia/SkiaDisplayList.h +++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h @@ -22,7 +22,7 @@ #include <deque> #include <SkLiteDL.h> -#include <SkPictureRecorder.h> +#include <SkLiteRecorder.h> namespace android { namespace uirenderer { @@ -39,22 +39,22 @@ namespace skiapipeline { */ class SkiaDisplayList : public DisplayList { public: - SkiaDisplayList(SkRect bounds); + SkiaDisplayList() { SkASSERT(projectionReceiveIndex == -1); } virtual ~SkiaDisplayList() { /* Given that we are using a LinearStdAllocator to store some of the * SkDrawable contents we must ensure that any other object that is * holding a reference to those drawables is destroyed prior to their * deletion. */ - mDrawable.reset(); + mDisplayList.reset(); } /** * This resets the DisplayList so that it behaves as if the object were newly - * constructed with the provided bounds. The reuse avoids any overhead - * associated with destroying the SkLiteDL as well as the deques and vectors. + * constructed. The reuse avoids any overhead associated with destroying + * the SkLiteDL as well as the deques and vectors. */ - void reset(SkRect bounds); + void reset(); /** * Use the linear allocator to create any SkDrawables needed by the display @@ -72,7 +72,7 @@ public: /** * Returns true if the DisplayList does not have any recorded content */ - bool isEmpty() const override { return mDrawable->empty(); } + bool isEmpty() const override { return mDisplayList.empty(); } /** * Returns true if this list directly contains a GLFunctor drawing command. @@ -126,18 +126,24 @@ public: */ inline bool containsProjectionReceiver() const { return mProjectionReceiver; } + void attachRecorder(SkLiteRecorder* recorder, const SkIRect& bounds) { + recorder->reset(&mDisplayList, bounds); + } + + void draw(SkCanvas* canvas) { mDisplayList.draw(canvas); } + void output(std::ostream& output, uint32_t level) override; /** * We use std::deque here because (1) we need to iterate through these - * elements and (2) mDrawable holds pointers to the elements, so they cannot - * relocate. + * elements and (2) mDisplayList holds pointers to the elements, so they + * cannot relocate. */ std::deque<RenderNodeDrawable> mChildNodes; std::deque<GLFunctorDrawable> mChildFunctors; std::vector<SkImage*> mMutableImages; std::vector<VectorDrawableRoot*> mVectorDrawables; - sk_sp<SkLiteDL> mDrawable; + SkLiteDL mDisplayList; //mProjectionReceiver points to a child node (stored in mChildNodes) that is as a projection //receiver. It is set at record time and used at both prepare and draw tree traversals to diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp index 430d6bea70c1..11dc1f4c2161 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp @@ -80,7 +80,7 @@ void SkiaPipeline::renderLayers(const FrameBuilder::LightGeometry& lightGeometry void SkiaPipeline::renderLayersImpl(const LayerUpdateQueue& layers, bool opaque) { // Render all layers that need to be updated, in order. for (size_t i = 0; i < layers.entries().size(); i++) { - RenderNode* layerNode = layers.entries()[i].renderNode; + RenderNode* layerNode = layers.entries()[i].renderNode.get(); // only schedule repaint if node still on layer - possible it may have been // removed during a dropped frame, but layers may still remain scheduled so // as not to lose info on what portion is damaged diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp index dbe0296eae24..559d268b71f7 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp @@ -39,14 +39,11 @@ void SkiaRecordingCanvas::initDisplayList(uirenderer::RenderNode* renderNode, in if (renderNode) { mDisplayList = renderNode->detachAvailableList(); } - SkRect bounds = SkRect::MakeWH(width, height); - if (mDisplayList) { - mDisplayList->reset(bounds); - } else { - mDisplayList.reset(new SkiaDisplayList(bounds)); + if (!mDisplayList) { + mDisplayList.reset(new SkiaDisplayList()); } - mRecorder.reset(mDisplayList->mDrawable.get()); + mDisplayList->attachRecorder(&mRecorder, SkIRect::MakeWH(width, height)); SkiaCanvas::reset(&mRecorder); } diff --git a/libs/hwui/tests/unit/LayerUpdateQueueTests.cpp b/libs/hwui/tests/unit/LayerUpdateQueueTests.cpp index 4db1cb935902..91c7514e271e 100644 --- a/libs/hwui/tests/unit/LayerUpdateQueueTests.cpp +++ b/libs/hwui/tests/unit/LayerUpdateQueueTests.cpp @@ -48,11 +48,11 @@ TEST(LayerUpdateQueue, enqueueSimple) { EXPECT_EQ(3u, queue.entries().size()); - EXPECT_EQ(a.get(), queue.entries()[0].renderNode); + EXPECT_EQ(a.get(), queue.entries()[0].renderNode.get()); EXPECT_EQ(Rect(25, 25, 75, 75), queue.entries()[0].damage); - EXPECT_EQ(b.get(), queue.entries()[1].renderNode); + EXPECT_EQ(b.get(), queue.entries()[1].renderNode.get()); EXPECT_EQ(Rect(100, 100, 200, 200), queue.entries()[1].damage); // clipped to bounds - EXPECT_EQ(c.get(), queue.entries()[2].renderNode); + EXPECT_EQ(c.get(), queue.entries()[2].renderNode.get()); EXPECT_EQ(Rect(0, 0, 1, 1), queue.entries()[2].damage); // rounded out } @@ -65,7 +65,7 @@ TEST(LayerUpdateQueue, enqueueUnion) { EXPECT_EQ(1u, queue.entries().size()); - EXPECT_EQ(a.get(), queue.entries()[0].renderNode); + EXPECT_EQ(a.get(), queue.entries()[0].renderNode.get()); EXPECT_EQ(Rect(10, 10, 40, 40), queue.entries()[0].damage); } diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp index f21b3f7ec334..cbea501e3df3 100644 --- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp +++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp @@ -44,9 +44,9 @@ TEST(RenderNodeDrawable, create) { canvas.drawColor(Color::Red_500, SkBlendMode::kSrcOver); }); - auto skLiteDL = SkLiteDL::New(SkRect::MakeWH(1, 1)); + SkLiteDL skLiteDL; SkLiteRecorder canvas; - canvas.reset(skLiteDL.get()); + canvas.reset(&skLiteDL, SkIRect::MakeWH(1, 1)); canvas.translate(100, 100); RenderNodeDrawable drawable(rootNode.get(), &canvas); diff --git a/libs/hwui/tests/unit/RenderNodeTests.cpp b/libs/hwui/tests/unit/RenderNodeTests.cpp index 2925243d9f1c..eda4a9de49ae 100644 --- a/libs/hwui/tests/unit/RenderNodeTests.cpp +++ b/libs/hwui/tests/unit/RenderNodeTests.cpp @@ -331,7 +331,7 @@ RENDERTHREAD_TEST(RenderNode, prepareTree_HwLayer_AVD_enqueueDamage) { // damage rect. EXPECT_TRUE(rootNode->getDisplayList()->hasVectorDrawables()); EXPECT_FALSE(info.layerUpdateQueue->entries().empty()); - EXPECT_EQ(rootNode.get(), info.layerUpdateQueue->entries().at(0).renderNode); + EXPECT_EQ(rootNode.get(), info.layerUpdateQueue->entries().at(0).renderNode.get()); EXPECT_EQ(uirenderer::Rect(0, 0, 200, 400), info.layerUpdateQueue->entries().at(0).damage); canvasContext->destroy(); } diff --git a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp index be460bf6bdfe..dd8f4b4ec8cc 100644 --- a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp +++ b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp @@ -30,16 +30,13 @@ using namespace android::uirenderer::renderthread; using namespace android::uirenderer::skiapipeline; TEST(SkiaDisplayList, create) { - SkRect bounds = SkRect::MakeWH(200, 200); - SkiaDisplayList skiaDL(bounds); + SkiaDisplayList skiaDL; ASSERT_TRUE(skiaDL.isEmpty()); ASSERT_FALSE(skiaDL.mProjectionReceiver); - ASSERT_EQ(skiaDL.mDrawable->getBounds(), bounds); } TEST(SkiaDisplayList, reset) { - SkRect bounds = SkRect::MakeWH(200, 200); - SkiaDisplayList skiaDL(bounds); + SkiaDisplayList skiaDL; SkCanvas dummyCanvas; RenderNodeDrawable drawable(nullptr, &dummyCanvas); @@ -47,10 +44,9 @@ TEST(SkiaDisplayList, reset) { skiaDL.mChildFunctors.emplace_back(nullptr, nullptr, &dummyCanvas); skiaDL.mMutableImages.push_back(nullptr); skiaDL.mVectorDrawables.push_back(nullptr); - skiaDL.mDrawable->drawAnnotation(bounds, "testAnnotation", nullptr); + skiaDL.mDisplayList.drawAnnotation(SkRect::MakeWH(200, 200), "testAnnotation", nullptr); skiaDL.mProjectionReceiver = &drawable; - ASSERT_EQ(skiaDL.mDrawable->getBounds(), bounds); ASSERT_FALSE(skiaDL.mChildNodes.empty()); ASSERT_FALSE(skiaDL.mChildFunctors.empty()); ASSERT_FALSE(skiaDL.mMutableImages.empty()); @@ -58,10 +54,8 @@ TEST(SkiaDisplayList, reset) { ASSERT_FALSE(skiaDL.isEmpty()); ASSERT_TRUE(skiaDL.mProjectionReceiver); - bounds = SkRect::MakeWH(100, 100); - skiaDL.reset(bounds); + skiaDL.reset(); - ASSERT_EQ(skiaDL.mDrawable->getBounds(), bounds); ASSERT_TRUE(skiaDL.mChildNodes.empty()); ASSERT_TRUE(skiaDL.mChildFunctors.empty()); ASSERT_TRUE(skiaDL.mMutableImages.empty()); @@ -79,7 +73,7 @@ TEST(SkiaDisplayList, reuseDisplayList) { ASSERT_EQ(availableList.get(), nullptr); // attach a displayList for reuse - SkiaDisplayList skiaDL(SkRect::MakeWH(200, 200)); + SkiaDisplayList skiaDL; ASSERT_TRUE(skiaDL.reuseDisplayList(renderNode.get(), nullptr)); // detach the list that you just attempted to reuse @@ -93,13 +87,13 @@ TEST(SkiaDisplayList, reuseDisplayList) { } TEST(SkiaDisplayList, syncContexts) { - SkRect bounds = SkRect::MakeWH(200, 200); - SkiaDisplayList skiaDL(bounds); + SkiaDisplayList skiaDL; SkCanvas dummyCanvas; TestUtils::MockFunctor functor; skiaDL.mChildFunctors.emplace_back(&functor, nullptr, &dummyCanvas); + SkRect bounds = SkRect::MakeWH(200, 200); VectorDrawableRoot vectorDrawable(new VectorDrawable::Group()); vectorDrawable.mutateStagingProperties()->setBounds(bounds); skiaDL.mVectorDrawables.push_back(&vectorDrawable); @@ -127,7 +121,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaDisplayList, prepareListAndChildren) { DamageAccumulator damageAccumulator; info.damageAccumulator = &damageAccumulator; - SkiaDisplayList skiaDL(SkRect::MakeWH(200, 200)); + SkiaDisplayList skiaDL; // prepare with a clean VD VectorDrawableRoot cleanVD(new VectorDrawable::Group()); @@ -170,8 +164,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaDisplayList, prepareListAndChildren) { } TEST(SkiaDisplayList, updateChildren) { - SkRect bounds = SkRect::MakeWH(200, 200); - SkiaDisplayList skiaDL(bounds); + SkiaDisplayList skiaDL; sp<RenderNode> renderNode = new RenderNode(); SkCanvas dummyCanvas; diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java index 1ca96583112e..d26412789f39 100644 --- a/media/java/android/media/MediaCodec.java +++ b/media/java/android/media/MediaCodec.java @@ -3188,9 +3188,55 @@ final public class MediaCodec { /** * Returns Analytics/Metrics data about the current content being * - * @return a Bundle containint the set of attributes and values available + * @return a Bundle containing the set of attributes and values available * for the media being handled by this instance of MediaCodec * + * <table style="width: 0%"> + * <thead> + * <tr> + * <th>Key</th> + * <th>Type</th> + * <th>Description</th> + * </tr> + * </thead> + * <tbody> + * <tr> + * <td>{@code "codec"}</td> + * <td>String</td> + * <td>Identifies the particular codec in use</td> + * </tr><tr> + * <td>{@code "mime"}</td> + * <td>String</td> + * <td>Mime type of the media being encoded/decoded</td> + * </tr><tr> + * <td>{@code "mode"}</td> + * <td>String</td> + * <td>"Audio" or "Video"</td> + * </tr><tr> + * <td>{@code "secure"}</td> + * <td>Integer</td> + * <td>Indicates whether the code is operating on secure content and + * may also use capabilities in android.media.MediaCrypto</td> + * </tr><tr> + * <td>{@code "height"}</td> + * <td>Integer</td> + * <td>Height (pixels); valid only when mode=video</td> + * </tr><tr> + * <td>{@code "width"}</td> + * <td>Integer</td> + * <td>Width (pixels); valid only when mode=video</td> + * </tr><tr> + * <td>{@code "rotation"}</td> + * <td>Integer</td> + * <td>rotation (degrees) to orient the video onto the target surface; + * valid only when mode=video. Note there may be additional + * rotations applied when the surface is mapped to the screen.</td> + * </tr> + * </tbody> + * </table> + * + * Additional fields specific to individual codecs will also appear in + * the return value. */ public native Bundle getMetrics(); diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java index 01ae36ffccfe..b9e409d17748 100644 --- a/media/java/android/media/MediaExtractor.java +++ b/media/java/android/media/MediaExtractor.java @@ -656,6 +656,33 @@ final public class MediaExtractor { * @return the set of keys and values available for the media being * handled by this instance of MediaExtractor * + * <table style="width: 0%"> + * <thead> + * <tr> + * <th>Key</th> + * <th>Type</th> + * <th>Description</th> + * </tr> + * </thead> + * <tbody> + * <tr> + * <td>{@code "fmt"}</td> + * <td>String</td> + * <td>The container format (which determines the handler)</td> + * </tr><tr> + * <td>{@code "mime"}</td> + * <td>String</td> + * <td>Mime type of the container.</td> + * </tr><tr> + * <td>{@code "ntrk"}</td> + * <td>Integer</td> + * <td>Number of tracks in the container</td> + * </tr> + * </tbody> + * </table> + * + * Additional fields specific to individual codecs will also appear in + * the return value. */ public native Bundle getMetrics(); diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index fb37f9f62d14..b85c91119384 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -1498,6 +1498,64 @@ public class MediaPlayer extends PlayerBase * * @return the a map of attributes and values available for this video * player or null if no metrics are available. + * + * <table style="width: 0%"> + * <thead> + * <tr> + * <th>Key</th> + * <th>Type</th> + * <th>Description</th> + * </tr> + * </thead> + * <tbody> + * <tr> + * <td>{@code "video/codec"}</td> + * <td>String</td> + * <td>Identifies the video codec in use</td> + * </tr><tr> + * <td>{@code "video/mime"}</td> + * <td>String</td> + * <td>Mime type of the video being encoded/decoded</td> + * </tr><tr> + * <td>{@code "audio/codec"}</td> + * <td>String</td> + * <td>Identifies the audio codec in use</td> + * </tr><tr> + * <td>{@code "audio/mime"}</td> + * <td>String</td> + * <td>Mime type of the audio being encoded/decoded</td> + * </tr><tr> + * <td>{@code "ht"}</td> + * <td>Integer</td> + * <td>Height (pixels); valid only when mode=video</td> + * </tr><tr> + * <td>{@code "wid"}</td> + * <td>Integer</td> + * <td>Width (pixels); valid only when mode=video</td> + * </tr><tr> + * <td>{@code "frame"}</td> + * <td>Integer</td> + * <td>Number of decoded video frames sent to the display</td> + * </tr><tr> + * <td>{@code "dropped"}</td> + * <td>Integer</td> + * <td>Number of decoded video frames that were not sent to display. + * These frames were dropped by the player.</td> + * </tr><tr> + * <td>{@code "durationMs"}</td> + * <td>Integer</td> + * <td>The length of the media being played (in ms), e.g. "This video lasts for 30000 milliseconds". </td> + * </tr><tr> + * <td>{@code "playingMs"}</td> + * <td>Integer</td> + * <td>The time the media has been played (in ms). If you watch a + * 30 second twice through, this will report 60000 ms.</td> + * </tr> + * </tbody> + * </table> + * + * Additional fields specific to individual codecs will also appear in + * the return value. */ public native Bundle getMetrics(); diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java index e5af35711311..aee9d38e0a27 100644 --- a/media/java/android/media/tv/TvView.java +++ b/media/java/android/media/tv/TvView.java @@ -776,8 +776,8 @@ public class TvView extends ViewGroup { mSurface = null; mSurfaceView = new SurfaceView(getContext(), mAttrs, mDefStyleAttr) { @Override - protected void updateSurface() { - super.updateSurface(); + protected void updateWindow() { + super.updateWindow(); relayoutSessionOverlayView(); }}; // The surface view's content should be treated as secure all the time. diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java index 56ae618883b9..de79d3f98c32 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java @@ -143,6 +143,8 @@ final class SettingsState { @GuardedBy("sLock") private static Signature sSystemSignature; + private final Object mWriteLock = new Object(); + private final Object mLock; private final Handler mHandler; @@ -551,62 +553,66 @@ final class SettingsState { } private void doWriteState() { - if (DEBUG_PERSISTENCE) { - Slog.i(LOG_TAG, "[PERSIST START]"); - } - - AtomicFile destination = new AtomicFile(mStatePersistFile); + synchronized (mWriteLock) { + if (DEBUG_PERSISTENCE) { + Slog.i(LOG_TAG, "[PERSIST START]"); + } - final int version; - final ArrayMap<String, Setting> settings; + AtomicFile destination = new AtomicFile(mStatePersistFile); - synchronized (mLock) { - version = mVersion; - settings = new ArrayMap<>(mSettings); - mDirty = false; - mWriteScheduled = false; - } + final int version; + final ArrayMap<String, Setting> settings; - FileOutputStream out = null; - try { - out = destination.startWrite(); + synchronized (mLock) { + version = mVersion; + settings = new ArrayMap<>(mSettings); + mDirty = false; + mWriteScheduled = false; + } - XmlSerializer serializer = Xml.newSerializer(); - serializer.setOutput(out, StandardCharsets.UTF_8.name()); - serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); - serializer.startDocument(null, true); - serializer.startTag(null, TAG_SETTINGS); - serializer.attribute(null, ATTR_VERSION, String.valueOf(version)); + FileOutputStream out = null; + try { + out = destination.startWrite(); + + XmlSerializer serializer = Xml.newSerializer(); + serializer.setOutput(out, StandardCharsets.UTF_8.name()); + serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", + true); + serializer.startDocument(null, true); + serializer.startTag(null, TAG_SETTINGS); + serializer.attribute(null, ATTR_VERSION, String.valueOf(version)); + + final int settingCount = settings.size(); + for (int i = 0; i < settingCount; i++) { + Setting setting = settings.valueAt(i); + + writeSingleSetting(mVersion, serializer, setting.getId(), setting.getName(), + setting.getValue(), setting.getDefaultValue(), setting.getPackageName(), + setting.getTag(), setting.isDefaultFromSystem()); + + if (DEBUG_PERSISTENCE) { + Slog.i(LOG_TAG, "[PERSISTED]" + setting.getName() + "=" + + setting.getValue()); + } + } - final int settingCount = settings.size(); - for (int i = 0; i < settingCount; i++) { - Setting setting = settings.valueAt(i); + serializer.endTag(null, TAG_SETTINGS); + serializer.endDocument(); + destination.finishWrite(out); - writeSingleSetting(mVersion, serializer, setting.getId(), setting.getName(), - setting.getValue(), setting.getDefaultValue(), setting.getPackageName(), - setting.getTag(), setting.isDefaultFromSystem()); + synchronized (mLock) { + addHistoricalOperationLocked(HISTORICAL_OPERATION_PERSIST, null); + } if (DEBUG_PERSISTENCE) { - Slog.i(LOG_TAG, "[PERSISTED]" + setting.getName() + "=" + setting.getValue()); + Slog.i(LOG_TAG, "[PERSIST END]"); } + } catch (Throwable t) { + Slog.wtf(LOG_TAG, "Failed to write settings, restoring backup", t); + destination.failWrite(out); + } finally { + IoUtils.closeQuietly(out); } - - serializer.endTag(null, TAG_SETTINGS); - serializer.endDocument(); - destination.finishWrite(out); - - synchronized (mLock) { - addHistoricalOperationLocked(HISTORICAL_OPERATION_PERSIST, null); - } - - if (DEBUG_PERSISTENCE) { - Slog.i(LOG_TAG, "[PERSIST END]"); - } - } catch (Throwable t) { - Slog.wtf(LOG_TAG, "Failed to write settings, restoring backup", t); - destination.failWrite(out); - } finally { - IoUtils.closeQuietly(out); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java index f7bfc1e6d4fc..62aa4660bc56 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java @@ -23,16 +23,18 @@ import android.service.quicksettings.Tile; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.style.RelativeSizeSpan; +import android.util.Log; import android.util.TypedValue; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnAttachStateChangeListener; import android.view.View.OnClickListener; import android.view.ViewGroup; -import android.widget.Button; import android.widget.Checkable; import android.widget.ImageView; +import android.widget.Switch; import android.widget.TextView; + import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settingslib.BatteryInfo; import com.android.settingslib.graph.BatteryMeterDrawableBase; @@ -43,9 +45,8 @@ import com.android.systemui.plugins.qs.QS.DetailAdapter; import com.android.systemui.qs.QSTile; import com.android.systemui.statusbar.policy.BatteryController; -import java.text.NumberFormat; - -public class BatteryTile extends QSTile<QSTile.State> implements BatteryController.BatteryStateChangeCallback { +public class BatterySaverTile extends QSTile<QSTile.BooleanState> implements + BatteryController.BatteryStateChangeCallback { private final BatteryController mBatteryController; private final BatteryDetail mBatteryDetail = new BatteryDetail(); @@ -56,19 +57,14 @@ public class BatteryTile extends QSTile<QSTile.State> implements BatteryControll private boolean mDetailShown; private boolean mPluggedIn; - public BatteryTile(Host host) { + public BatterySaverTile(Host host) { super(host); mBatteryController = Dependency.get(BatteryController.class); } @Override - public State newTileState() { - return new QSTile.State(); - } - - @Override - public DetailAdapter getDetailAdapter() { - return mBatteryDetail; + public BooleanState newTileState() { + return new BooleanState(); } @Override @@ -109,22 +105,15 @@ public class BatteryTile extends QSTile<QSTile.State> implements BatteryControll } @Override - protected void handleUpdateState(State state, Object arg) { - int level = (arg != null) ? (Integer) arg : mLevel; - String percentage = NumberFormat.getPercentInstance().format((double) level / 100.0); - + protected void handleUpdateState(BooleanState state, Object arg) { state.state = mCharging ? Tile.STATE_UNAVAILABLE : mPowerSave ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE; state.icon = ResourceIcon.get(R.drawable.ic_qs_battery_saver); state.label = mContext.getString(R.string.battery_detail_switch_title); - state.contentDescription = mContext.getString(R.string.accessibility_quick_settings_battery, - percentage) + "," + - (mPowerSave ? mContext.getString(R.string.battery_saver_notification_title) - : mCharging ? mContext.getString(R.string.expanded_header_battery_charging) - : "") - + "," + mContext.getString(R.string.accessibility_battery_details); + state.contentDescription = state.label; + state.value = mPowerSave; state.minimalAccessibilityClassName = state.expandedAccessibilityClassName - = Button.class.getName(); + = Switch.class.getName(); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java index a1022c4757a5..de002372c442 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java @@ -37,7 +37,7 @@ import com.android.systemui.qs.external.CustomTile; import com.android.systemui.qs.external.TileLifecycleManager; import com.android.systemui.qs.external.TileServices; import com.android.systemui.qs.tiles.AirplaneModeTile; -import com.android.systemui.qs.tiles.BatteryTile; +import com.android.systemui.qs.tiles.BatterySaverTile; import com.android.systemui.qs.tiles.BluetoothTile; import com.android.systemui.qs.tiles.CastTile; import com.android.systemui.qs.tiles.CellularTile; @@ -273,7 +273,7 @@ public class QSTileHost implements QSTile.Host, Tunable { else if (tileSpec.equals("cast")) return new CastTile(this); else if (tileSpec.equals("hotspot")) return new HotspotTile(this); else if (tileSpec.equals("user")) return new UserTile(this); - else if (tileSpec.equals("battery")) return new BatteryTile(this); + else if (tileSpec.equals("battery")) return new BatterySaverTile(this); else if (tileSpec.equals("saver")) return new DataSaverTile(this); else if (tileSpec.equals("night")) return new NightDisplayTile(this); else if (tileSpec.equals("nfc")) return new NfcTile(this); diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java index 7a85d4e9b62e..8947b7d99eef 100644 --- a/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java +++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java @@ -186,6 +186,29 @@ public final class AutoFillManagerService extends SystemService { } // Called by Shell command. + void destroySessions(int userId, IResultReceiver receiver) { + Slog.i(TAG, "destroySessions() for userId " + userId); + mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); + + synchronized (mLock) { + if (userId != UserHandle.USER_ALL) { + mServicesCache.get(userId).destroySessionsLocked(); + } else { + final int size = mServicesCache.size(); + for (int i = 0; i < size; i++) { + mServicesCache.valueAt(i).destroySessionsLocked(); + } + } + } + + try { + receiver.send(0, new Bundle()); + } catch (RemoteException e) { + // Just ignore it... + } + } + + // Called by Shell command. void listSessions(int userId, IResultReceiver receiver) { Slog.i(TAG, "listSessions() for userId " + userId); mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java index bfc6e836c3b0..5e852f1738f1 100644 --- a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java @@ -59,7 +59,6 @@ import android.service.autofill.IAutoFillService; import android.service.autofill.SaveInfo; import android.text.TextUtils; import android.util.ArrayMap; -import android.util.ArraySet; import android.util.LocalLog; import android.util.PrintWriterPrinter; import android.util.Slog; @@ -405,6 +404,12 @@ final class AutoFillManagerServiceImpl { } } + void destroySessionsLocked() { + for (Session session : mSessions.values()) { + session.removeSelf(); + } + } + void listSessionsLocked(ArrayList<String> output) { for (IBinder activityToken : mSessions.keySet()) { output.add((mInfo != null ? mInfo.getServiceInfo().getComponentName() @@ -666,6 +671,28 @@ final class AutoFillManagerServiceImpl { // FillServiceCallbacks @Override + public void onDisableSelf() { + final long identity = Binder.clearCallingIdentity(); + try { + final String autoFillService = Settings.Secure.getStringForUser( + mContext.getContentResolver(), + Settings.Secure.AUTO_FILL_SERVICE, mUserId); + if (mInfo.getServiceInfo().getComponentName().equals( + ComponentName.unflattenFromString(autoFillService))) { + Settings.Secure.putStringForUser(mContext.getContentResolver(), + Settings.Secure.AUTO_FILL_SERVICE, null, mUserId); + } + } finally { + Binder.restoreCallingIdentity(identity); + } + synchronized (mLock) { + destroyLocked(); + mSessions.remove(this); + } + } + + // FillServiceCallbacks + @Override public void onServiceDied(RemoteFillService service) { // TODO(b/33197203): implement } diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java index cfa4a1d0a107..76eed2ac2639 100644 --- a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java +++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java @@ -20,7 +20,6 @@ import static com.android.server.autofill.AutoFillManagerService.RECEIVER_BUNDLE import android.app.ActivityManager; import android.os.Bundle; -import android.os.RemoteException; import android.os.ShellCommand; import android.os.UserHandle; @@ -50,6 +49,8 @@ public final class AutoFillManagerServiceShellCommand extends ShellCommand { return requestSave(); case "list": return requestList(pw); + case "destroy": + return requestDestroy(pw); case "reset": return requestReset(); default: @@ -67,6 +68,9 @@ public final class AutoFillManagerServiceShellCommand extends ShellCommand { pw.println(" list sessions [--user USER_ID]"); pw.println(" List all pending sessions."); pw.println(""); + pw.println(" destroy sessions [--user USER_ID]"); + pw.println(" Destroy all pending sessions."); + pw.println(""); pw.println(" save [--user USER_ID]"); pw.println(" Request provider to save contents of the top activity. "); pw.println(""); @@ -82,30 +86,55 @@ public final class AutoFillManagerServiceShellCommand extends ShellCommand { return 0; } - private int requestList(PrintWriter pw) { - final String type = getNextArgRequired(); - if (!type.equals("sessions")) { - pw.println("Error: invalid list type"); + private int requestDestroy(PrintWriter pw) { + if (!isNextArgSessions(pw)) { return -1; - } + final int userId = getUserIdFromArgsOrAllUsers(); final CountDownLatch latch = new CountDownLatch(1); final IResultReceiver receiver = new IResultReceiver.Stub() { + @Override + public void send(int resultCode, Bundle resultData) { + latch.countDown(); + } + }; + return requestSessionCommon(pw, latch, () -> mService.destroySessions(userId, receiver)); + } + private int requestList(PrintWriter pw) { + if (!isNextArgSessions(pw)) { + return -1; + } + + final int userId = getUserIdFromArgsOrAllUsers(); + final CountDownLatch latch = new CountDownLatch(1); + final IResultReceiver receiver = new IResultReceiver.Stub() { @Override - public void send(int resultCode, Bundle resultData) throws RemoteException { + public void send(int resultCode, Bundle resultData) { final ArrayList<String> sessions = resultData .getStringArrayList(RECEIVER_BUNDLE_EXTRA_SESSIONS); - for (String session : sessions) { pw.println(session); } latch.countDown(); } }; + return requestSessionCommon(pw, latch, () -> mService.listSessions(userId, receiver)); + } + + private boolean isNextArgSessions(PrintWriter pw) { + final String type = getNextArgRequired(); + if (!type.equals("sessions")) { + pw.println("Error: invalid list type"); + return false; + } + return true; + } - mService.listSessions(userId, receiver); + private int requestSessionCommon(PrintWriter pw, CountDownLatch latch, + Runnable command) { + command.run(); try { final boolean received = latch.await(5, TimeUnit.SECONDS); diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java index c469718780c0..04eeb324ddf6 100644 --- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java +++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java @@ -33,6 +33,7 @@ import android.os.UserHandle; import android.service.autofill.AutoFillService; import android.service.autofill.FillResponse; import android.service.autofill.IAutoFillService; +import android.service.autofill.IAutoFillServiceConnection; import android.service.autofill.IFillCallback; import android.service.autofill.ISaveCallback; import android.text.format.DateUtils; @@ -57,7 +58,7 @@ final class RemoteFillService implements DeathRecipient { private static final boolean DEBUG = Helper.DEBUG; // How long after the last interaction with the service we would unbind - private static final long TIMEOUT_IDLE_BIND_MILLIS = 5 * DateUtils.MINUTE_IN_MILLIS; + private static final long TIMEOUT_IDLE_BIND_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS; private final Context mContext; @@ -91,6 +92,7 @@ final class RemoteFillService implements DeathRecipient { void onSaveRequestSuccess(); void onSaveRequestFailure(CharSequence message); void onServiceDied(RemoteFillService service); + void onDisableSelf(); } public RemoteFillService(Context context, ComponentName componentName, @@ -197,6 +199,10 @@ final class RemoteFillService implements DeathRecipient { } } + private void handleDisableSelf() { + mCallbacks.onDisableSelf(); + } + private boolean isBound() { return mAutoFillService != null; } @@ -239,7 +245,7 @@ final class RemoteFillService implements DeathRecipient { // Need to double check if it's null, since it could be set on onServiceDisconnected() if (mAutoFillService != null) { try { - mAutoFillService.onDisconnected(); + mAutoFillService.onInit(null); } catch (Exception e) { Slog.w(LOG_TAG, "Exception calling onDisconnected(): " + e); } @@ -321,7 +327,12 @@ final class RemoteFillService implements DeathRecipient { // Need to double check if it's null, since it could be set on // onServiceDisconnected() if (mAutoFillService != null) { - mAutoFillService.onConnected(); + mAutoFillService.onInit(new IAutoFillServiceConnection.Stub() { + @Override + public void disableSelf() { + mHandler.obtainMessage(MyHandler.MSG_ON_DISABLE_SELF).sendToTarget(); + } + }); } } catch (RemoteException e) { Slog.w(LOG_TAG, "Exception calling onConnected(): " + e); @@ -347,6 +358,7 @@ final class RemoteFillService implements DeathRecipient { public static final int MSG_BINDER_DIED = 2; public static final int MSG_UNBIND = 3; public static final int MSG_ON_PENDING_REQUEST = 4; + public static final int MSG_ON_DISABLE_SELF = 5; public MyHandler(Context context) { // Cannot use lambda - doesn't compile @@ -374,6 +386,10 @@ final class RemoteFillService implements DeathRecipient { case MSG_ON_PENDING_REQUEST: { handlePendingRequest((PendingRequest) message.obj); } break; + + case MSG_ON_DISABLE_SELF: { + handleDisableSelf(); + } break; } } }, false); diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java index 949a80c7bfdc..0da36c8936c8 100644 --- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java +++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java @@ -26,6 +26,7 @@ import android.service.autofill.Dataset; import android.service.autofill.FillResponse; import android.service.autofill.SaveInfo; import android.text.TextUtils; +import android.util.Slog; import android.view.autofill.AutoFillId; import android.widget.Toast; @@ -41,6 +42,8 @@ import java.io.PrintWriter; * managing saving of user edits. */ public final class AutoFillUI { + private static final String TAG = "AutoFillUI"; + private final Handler mHandler = UiThread.getHandler(); private final @NonNull Context mContext; @@ -191,9 +194,17 @@ public final class AutoFillUI { } @Override - public void onCancel() { + public void onCancel(IntentSender listener) { // TODO(b/33197203): add MetricsLogger call hideSaveUiUiThread(); + if (listener != null) { + try { + listener.sendIntent(mContext, 0, null, null, null); + } catch (IntentSender.SendIntentException e) { + Slog.e(TAG, "Error starting negative action listener: " + + listener, e); + } + } } }); }); diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java index afe93c7d6e06..d443dc34f949 100644 --- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java +++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java @@ -19,6 +19,7 @@ package com.android.server.autofill.ui; import android.annotation.NonNull; import android.app.Dialog; import android.content.Context; +import android.content.IntentSender; import android.os.Handler; import android.service.autofill.SaveInfo; import android.text.format.DateUtils; @@ -38,7 +39,7 @@ import com.android.server.UiThread; final class SaveUi { public interface OnSaveListener { void onSave(); - void onCancel(); + void onCancel(IntentSender listener); } private static final long LIFETIME_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS; @@ -87,14 +88,20 @@ final class SaveUi { subTitleView.setVisibility(View.VISIBLE); } - final View noButton = view.findViewById(R.id.autofill_save_no); - noButton.setOnClickListener((v) -> mListener.onCancel()); + final TextView noButton = view.findViewById(R.id.autofill_save_no); + if (info.getNegativeActionTitle() != null) { + noButton.setText(info.getNegativeActionTitle()); + noButton.setOnClickListener((v) -> mListener.onCancel( + info.getNegativeActionListener())); + } else { + noButton.setOnClickListener((v) -> mListener.onCancel(null)); + } final View yesButton = view.findViewById(R.id.autofill_save_yes); yesButton.setOnClickListener((v) -> mListener.onSave()); final View closeButton = view.findViewById(R.id.autofill_save_close); - closeButton.setOnClickListener((v) -> mListener.onCancel()); + closeButton.setOnClickListener((v) -> mListener.onCancel(null)); mDialog = new Dialog(context, R.style.Theme_Material_Panel); mDialog.setContentView(view); @@ -112,7 +119,7 @@ final class SaveUi { mDialog.show(); - mHandler.postDelayed(() -> mListener.onCancel(), LIFETIME_MILLIS); + mHandler.postDelayed(() -> mListener.onCancel(null), LIFETIME_MILLIS); } void destroy() { diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index 4f8b8af49518..2d947a4dfca1 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -16,9 +16,23 @@ package com.android.server.backup; -import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_VERSION_OF_BACKUP_OLDER; -import static android.app.backup.BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY; +import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_NAME; +import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_VERSION; import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_OLD_VERSION; +import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_POLICY_ALLOW_APKS; +import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_MANIFEST_PACKAGE_NAME; +import static android.app.backup.BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT; +import static android.app.backup.BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY; +import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_VERSION_OF_BACKUP_OLDER; +import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_FULL_RESTORE_SIGNATURE_MISMATCH; +import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_SYSTEM_APP_NO_AGENT; +import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_FULL_RESTORE_ALLOW_BACKUP_FALSE; +import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_APK_NOT_INSTALLED; +import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_CANNOT_RESTORE_WITHOUT_APK; +import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_MISSING_SIGNATURE; +import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_EXPECTED_DIFFERENT_PACKAGE; +import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_RESTORE_ANY_VERSION; +import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_VERSIONS_MATCH; import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND; import android.app.ActivityManager; @@ -2374,6 +2388,8 @@ public class BackupManagerService { IBackupTransport transport = mTransportManager.getCurrentTransportBinder(); if (transport == null) { sendBackupFinished(observer, BackupManager.ERROR_TRANSPORT_ABORTED); + monitor = monitorEvent(monitor, BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_IS_NULL, + null, BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT, null); return BackupManager.ERROR_TRANSPORT_ABORTED; } @@ -3338,6 +3354,14 @@ public class BackupManagerService { addBackupTrace("illegal key " + key + " from " + pkgName); EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, pkgName, "bad key"); + mMonitor = monitorEvent(mMonitor, + BackupManagerMonitor.LOG_EVENT_ID_ILLEGAL_KEY, + mCurrentPackage, + BackupManagerMonitor + .LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, + putMonitoringExtra(null, + BackupManagerMonitor.EXTRA_LOG_ILLEGAL_KEY, + key)); mBackupHandler.removeMessages(MSG_BACKUP_OPERATION_TIMEOUT); sendBackupOnPackageResult(mObserver, pkgName, BackupManager.ERROR_AGENT_FAILURE); @@ -3407,6 +3431,11 @@ public class BackupManagerService { if (MORE_DEBUG) Slog.i(TAG, "no backup data written; not calling transport"); addBackupTrace("no data to send"); + mMonitor = monitorEvent(mMonitor, + BackupManagerMonitor.LOG_EVENT_ID_NO_DATA_TO_SEND, + mCurrentPackage, + BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, + null); } if (mStatus == BackupTransport.TRANSPORT_OK) { @@ -3502,8 +3531,10 @@ public class BackupManagerService { Slog.e(TAG, "Cancel backing up " + mCurrentPackage.packageName); EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, mCurrentPackage.packageName); mMonitor = monitorEvent(mMonitor, - BackupManagerMonitor.LOG_EVENT_ID_KEY_VALUE_BACKUP_TIMEOUT, - mCurrentPackage, BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT, null); + BackupManagerMonitor.LOG_EVENT_ID_KEY_VALUE_BACKUP_CANCEL, + mCurrentPackage, BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT, + putMonitoringExtra(null, BackupManagerMonitor.EXTRA_LOG_CANCEL_ALL, + mCancelAll)); addBackupTrace( "cancel of " + mCurrentPackage.packageName + ", cancelAll=" + cancelAll); errorCleanup(); @@ -4593,6 +4624,11 @@ public class BackupManagerService { if (MORE_DEBUG) { Slog.d(TAG, "Ignoring ineligible package " + pkg); } + mMonitor = monitorEvent(mMonitor, + BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_INELIGIBLE, + mCurrentPackage, + BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, + null); sendBackupOnPackageResult(mBackupObserver, pkg, BackupManager.ERROR_BACKUP_NOT_ALLOWED); continue; @@ -4603,6 +4639,11 @@ public class BackupManagerService { Slog.d(TAG, "Ignoring full-data backup of key/value participant " + pkg); } + mMonitor = monitorEvent(mMonitor, + BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_KEY_VALUE_PARTICIPANT, + mCurrentPackage, + BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, + null); sendBackupOnPackageResult(mBackupObserver, pkg, BackupManager.ERROR_BACKUP_NOT_ALLOWED); continue; @@ -4613,6 +4654,11 @@ public class BackupManagerService { if (MORE_DEBUG) { Slog.d(TAG, "Ignoring stopped package " + pkg); } + mMonitor = monitorEvent(mMonitor, + BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_STOPPED, + mCurrentPackage, + BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, + null); sendBackupOnPackageResult(mBackupObserver, pkg, BackupManager.ERROR_BACKUP_NOT_ALLOWED); continue; @@ -4620,7 +4666,7 @@ public class BackupManagerService { mPackages.add(info); } catch (NameNotFoundException e) { Slog.i(TAG, "Requested package " + pkg + " not found; ignoring"); - monitor = monitorEvent(monitor, + mMonitor = monitorEvent(mMonitor, BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_NOT_FOUND, mCurrentPackage, BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, @@ -4696,9 +4742,17 @@ public class BackupManagerService { if (!mEnabled || !mProvisioned) { // Backups are globally disabled, so don't proceed. if (DEBUG) { - Slog.i(TAG, "full backup requested but e=" + mEnabled - + " p=" + mProvisioned + "; ignoring"); + Slog.i(TAG, "full backup requested but enabled=" + mEnabled + + " provisioned=" + mProvisioned + "; ignoring"); + } + int monitoringEvent; + if (!mEnabled) { + monitoringEvent = BackupManagerMonitor.LOG_EVENT_ID_BACKUP_DISABLED; + } else { + monitoringEvent = BackupManagerMonitor.LOG_EVENT_ID_DEVICE_NOT_PROVISIONED; } + mMonitor = monitorEvent(mMonitor, monitoringEvent, null, + BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, null); mUpdateSchedule = false; backupRunStatus = BackupManager.ERROR_BACKUP_NOT_ALLOWED; return; @@ -4722,7 +4776,8 @@ public class BackupManagerService { PackageInfo currentPackage = mPackages.get(i); String packageName = currentPackage.packageName; if (DEBUG) { - Slog.i(TAG, "Initiating full-data transport backup of " + packageName); + Slog.i(TAG, "Initiating full-data transport backup of " + packageName + + " token: " + mCurrentOpToken); } EventLog.writeEvent(EventLogTags.FULL_BACKUP_PACKAGE, packageName); @@ -4781,6 +4836,13 @@ public class BackupManagerService { + packageName + ": " + preflightResult + ", not running backup."); } + mMonitor = monitorEvent(mMonitor, + BackupManagerMonitor.LOG_EVENT_ID_ERROR_PREFLIGHT, + mCurrentPackage, + BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, + putMonitoringExtra(null, + BackupManagerMonitor.EXTRA_LOG_PREFLIGHT_ERROR, + preflightResult)); backupPackageStatus = (int) preflightResult; } else { int nRead = 0; @@ -4808,6 +4870,11 @@ public class BackupManagerService { if (backupPackageStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) { Slog.w(TAG, "Package hit quota limit in-flight " + packageName + ": " + totalRead + " of " + quota); + mMonitor = monitorEvent(mMonitor, + BackupManagerMonitor.LOG_EVENT_ID_QUOTA_HIT_PREFLIGHT, + mCurrentPackage, + BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT, + null); mBackupRunner.sendQuotaExceeded(totalRead, quota); } } @@ -4942,6 +5009,14 @@ public class BackupManagerService { } catch (Exception e) { backupRunStatus = BackupManager.ERROR_TRANSPORT_ABORTED; Slog.w(TAG, "Exception trying full transport backup", e); + mMonitor = monitorEvent(mMonitor, + BackupManagerMonitor.LOG_EVENT_ID_EXCEPTION_FULL_BACKUP, + mCurrentPackage, + BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, + putMonitoringExtra(null, + BackupManagerMonitor.EXTRA_LOG_EXCEPTION_FULL_BACKUP, + Log.getStackTraceString(e))); + } finally { if (mCancelAll) { @@ -5221,7 +5296,7 @@ public class BackupManagerService { } mMonitor = monitorEvent(mMonitor, - BackupManagerMonitor.LOG_EVENT_ID_FULL_BACKUP_TIMEOUT, + BackupManagerMonitor.LOG_EVENT_ID_FULL_BACKUP_CANCEL, mCurrentPackage, BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT, null); mIsCancelled = true; // Cancel tasks spun off by this task. @@ -6309,9 +6384,29 @@ public class BackupManagerService { } else { Slog.w(TAG, "Metadata mismatch: package " + info.packageName + " but widget data for " + pkg); + + Bundle monitoringExtras = putMonitoringExtra(null, + EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName); + monitoringExtras = putMonitoringExtra(monitoringExtras, + BackupManagerMonitor.EXTRA_LOG_WIDGET_PACKAGE_NAME, pkg); + mMonitor = monitorEvent(mMonitor, + BackupManagerMonitor.LOG_EVENT_ID_WIDGET_METADATA_MISMATCH, + null, + LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, + monitoringExtras); } } else { Slog.w(TAG, "Unsupported metadata version " + version); + + Bundle monitoringExtras = putMonitoringExtra(null, EXTRA_LOG_EVENT_PACKAGE_NAME, + info.packageName); + monitoringExtras = putMonitoringExtra(monitoringExtras, + EXTRA_LOG_EVENT_PACKAGE_VERSION, version); + mMonitor = monitorEvent(mMonitor, + BackupManagerMonitor.LOG_EVENT_ID_WIDGET_UNKNOWN_VERSION, + null, + LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, + monitoringExtras); } } @@ -6386,10 +6481,20 @@ public class BackupManagerService { if ((pkgInfo.applicationInfo.flags & ApplicationInfo.FLAG_RESTORE_ANY_VERSION) != 0) { Slog.i(TAG, "Package has restoreAnyVersion; taking data"); + mMonitor = monitorEvent(mMonitor, + LOG_EVENT_ID_RESTORE_ANY_VERSION, + pkgInfo, + LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, + null); policy = RestorePolicy.ACCEPT; } else if (pkgInfo.versionCode >= version) { Slog.i(TAG, "Sig + version match; taking data"); policy = RestorePolicy.ACCEPT; + mMonitor = monitorEvent(mMonitor, + LOG_EVENT_ID_VERSIONS_MATCH, + pkgInfo, + LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, + null); } else { // The data is from a newer version of the app than // is presently installed. That means we can only @@ -6403,30 +6508,43 @@ public class BackupManagerService { } else { Slog.i(TAG, "Data requires newer version " + version + "; ignoring"); - ArrayList<Pair<String, String>> list = - new ArrayList<>(); - list.add(new Pair<String, String>( - EXTRA_LOG_OLD_VERSION, - Integer.toString(version))); mMonitor = monitorEvent(mMonitor, LOG_EVENT_ID_VERSION_OF_BACKUP_OLDER, pkgInfo, LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, - list); + putMonitoringExtra(null, + EXTRA_LOG_OLD_VERSION, + version)); + policy = RestorePolicy.IGNORE; } } } else { Slog.w(TAG, "Restore manifest signatures do not match " + "installed application for " + info.packageName); + mMonitor = monitorEvent(mMonitor, + LOG_EVENT_ID_FULL_RESTORE_SIGNATURE_MISMATCH, + pkgInfo, + LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, + null); } } else { Slog.w(TAG, "Package " + info.packageName + " is system level with no agent"); + mMonitor = monitorEvent(mMonitor, + LOG_EVENT_ID_SYSTEM_APP_NO_AGENT, + pkgInfo, + LOG_EVENT_CATEGORY_AGENT, + null); } } else { if (DEBUG) Slog.i(TAG, "Restore manifest from " + info.packageName + " but allowBackup=false"); + mMonitor = monitorEvent(mMonitor, + LOG_EVENT_ID_FULL_RESTORE_ALLOW_BACKUP_FALSE, + pkgInfo, + LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, + null); } } catch (NameNotFoundException e) { // Okay, the target app isn't installed. We can process @@ -6439,26 +6557,71 @@ public class BackupManagerService { } else { policy = RestorePolicy.IGNORE; } + Bundle monitoringExtras = putMonitoringExtra(null, + EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName); + monitoringExtras = putMonitoringExtra(monitoringExtras, + EXTRA_LOG_POLICY_ALLOW_APKS, mAllowApks); + mMonitor = monitorEvent(mMonitor, + LOG_EVENT_ID_APK_NOT_INSTALLED, + null, + LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, + monitoringExtras); } if (policy == RestorePolicy.ACCEPT_IF_APK && !hasApk) { Slog.i(TAG, "Cannot restore package " + info.packageName + " without the matching .apk"); + mMonitor = monitorEvent(mMonitor, + LOG_EVENT_ID_CANNOT_RESTORE_WITHOUT_APK, + null, + LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, + putMonitoringExtra(null, + EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName)); } } else { Slog.i(TAG, "Missing signature on backed-up package " + info.packageName); + mMonitor = monitorEvent(mMonitor, + LOG_EVENT_ID_MISSING_SIGNATURE, + null, + LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, + putMonitoringExtra(null, + EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName)); } } else { Slog.i(TAG, "Expected package " + info.packageName + " but restore manifest claims " + manifestPackage); + Bundle monitoringExtras = putMonitoringExtra(null, + EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName); + monitoringExtras = putMonitoringExtra(monitoringExtras, + EXTRA_LOG_MANIFEST_PACKAGE_NAME, manifestPackage); + mMonitor = monitorEvent(mMonitor, + LOG_EVENT_ID_EXPECTED_DIFFERENT_PACKAGE, + null, + LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, + monitoringExtras); } } else { Slog.i(TAG, "Unknown restore manifest version " + version + " for package " + info.packageName); + Bundle monitoringExtras = putMonitoringExtra(null, + EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName); + monitoringExtras = putMonitoringExtra(monitoringExtras, + EXTRA_LOG_EVENT_PACKAGE_VERSION, version); + mMonitor = monitorEvent(mMonitor, + BackupManagerMonitor.LOG_EVENT_ID_UNKNOWN_VERSION, + null, + LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, + monitoringExtras); + } } catch (NumberFormatException e) { Slog.w(TAG, "Corrupt restore manifest for package " + info.packageName); + mMonitor = monitorEvent(mMonitor, + BackupManagerMonitor.LOG_EVENT_ID_CORRUPT_MANIFEST, + null, + LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, + putMonitoringExtra(null, EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName)); } catch (IllegalArgumentException e) { Slog.w(TAG, e.getMessage()); } @@ -8557,7 +8720,12 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF return; } if (!PACKAGE_MANAGER_SENTINEL.equals(desc.getPackageName())) { - Slog.e(TAG, "Required metadata but got " + desc.getPackageName()); + Slog.e(TAG, "Required package metadata but got " + + desc.getPackageName()); + mMonitor = monitorEvent(mMonitor, + BackupManagerMonitor.LOG_EVENT_ID_NO_PM_METADATA_RECEIVED, + mCurrentPackage, + BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, null); mStatus = BackupTransport.TRANSPORT_ERROR; executeNextState(UnifiedRestoreState.FINAL); return; @@ -8585,7 +8753,11 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF // signature/version verification etc, so we simply do not proceed with // the restore operation. if (!mPmAgent.hasMetadata()) { - Slog.e(TAG, "No restore metadata available, so not restoring"); + Slog.e(TAG, "PM agent has no metadata, so not restoring"); + mMonitor = monitorEvent(mMonitor, + BackupManagerMonitor.LOG_EVENT_ID_PM_AGENT_HAS_NO_METADATA, + mCurrentPackage, + BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, null); EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, PACKAGE_MANAGER_SENTINEL, "Package manager restore metadata missing"); @@ -8601,6 +8773,10 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF } catch (Exception e) { // If we lost the transport at any time, halt Slog.e(TAG, "Unable to contact transport for restore: " + e.getMessage()); + mMonitor = monitorEvent(mMonitor, + BackupManagerMonitor.LOG_EVENT_ID_LOST_TRANSPORT, + null, + BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT, null); mStatus = BackupTransport.TRANSPORT_ERROR; mBackupHandler.removeMessages(MSG_BACKUP_RESTORE_STEP, this); executeNextState(UnifiedRestoreState.FINAL); @@ -8670,17 +8846,37 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF // handle this case, we do not attempt the restore. if ((mCurrentPackage.applicationInfo.flags & ApplicationInfo.FLAG_RESTORE_ANY_VERSION) == 0) { - String message = "Version " + metaInfo.versionCode + String message = "Source version " + metaInfo.versionCode + " > installed version " + mCurrentPackage.versionCode; Slog.w(TAG, "Package " + pkgName + ": " + message); + Bundle monitoringExtras = putMonitoringExtra(null, + BackupManagerMonitor.EXTRA_LOG_RESTORE_VERSION, + metaInfo.versionCode); + monitoringExtras = putMonitoringExtra(monitoringExtras, + BackupManagerMonitor.EXTRA_LOG_RESTORE_ANYWAY, false); + mMonitor = monitorEvent(mMonitor, + BackupManagerMonitor.LOG_EVENT_ID_RESTORE_VERSION_HIGHER, + mCurrentPackage, + BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, + monitoringExtras); EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, pkgName, message); nextState = UnifiedRestoreState.RUNNING_QUEUE; return; } else { - if (DEBUG) Slog.v(TAG, "Version " + metaInfo.versionCode - + " > installed " + mCurrentPackage.versionCode + if (DEBUG) Slog.v(TAG, "Source version " + metaInfo.versionCode + + " > installed version " + mCurrentPackage.versionCode + " but restoreAnyVersion"); + Bundle monitoringExtras = putMonitoringExtra(null, + BackupManagerMonitor.EXTRA_LOG_RESTORE_VERSION, + metaInfo.versionCode); + monitoringExtras = putMonitoringExtra(monitoringExtras, + BackupManagerMonitor.EXTRA_LOG_RESTORE_ANYWAY, true); + mMonitor = monitorEvent(mMonitor, + BackupManagerMonitor.LOG_EVENT_ID_RESTORE_VERSION_HIGHER, + mCurrentPackage, + BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, + monitoringExtras); } } @@ -8739,6 +8935,9 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF Metadata metaInfo = mPmAgent.getRestoredMetadata(packageName); if (!BackupUtils.signaturesMatch(metaInfo.sigHashes, mCurrentPackage)) { Slog.w(TAG, "Signature mismatch restoring " + packageName); + mMonitor = monitorEvent(mMonitor, + BackupManagerMonitor.LOG_EVENT_ID_SIGNATURE_MISMATCH, mCurrentPackage, + BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, null); EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName, "Signature mismatch"); executeNextState(UnifiedRestoreState.RUNNING_QUEUE); @@ -11035,23 +11234,54 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF } } + private Bundle putMonitoringExtra(Bundle extras, String key, String value) { + if (extras == null) { + extras = new Bundle(); + } + extras.putString(key, value); + return extras; + } + + private Bundle putMonitoringExtra(Bundle extras, String key, int value) { + if (extras == null) { + extras = new Bundle(); + } + extras.putInt(key, value); + return extras; + } + + private Bundle putMonitoringExtra(Bundle extras, String key, long value) { + if (extras == null) { + extras = new Bundle(); + } + extras.putLong(key, value); + return extras; + } + + + private Bundle putMonitoringExtra(Bundle extras, String key, boolean value) { + if (extras == null) { + extras = new Bundle(); + } + extras.putBoolean(key, value); + return extras; + } + private static IBackupManagerMonitor monitorEvent(IBackupManagerMonitor monitor, int id, - PackageInfo pkg, int category, ArrayList<Pair<String, String>> extras) { + PackageInfo pkg, int category, Bundle extras) { if (monitor != null) { try { Bundle bundle = new Bundle(); bundle.putInt(BackupManagerMonitor.EXTRA_LOG_EVENT_ID, id); bundle.putInt(BackupManagerMonitor.EXTRA_LOG_EVENT_CATEGORY, category); if (pkg != null) { - bundle.putString(BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_NAME, + bundle.putString(EXTRA_LOG_EVENT_PACKAGE_NAME, pkg.packageName); bundle.putInt(BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_VERSION, pkg.versionCode); } if (extras != null) { - for (Pair<String,String> pair : extras) { - bundle.putString(pair.first, pair.second); - } + bundle.putAll(extras); } monitor.onEvent(bundle); return monitor; diff --git a/services/backup/java/com/android/server/backup/TransportManager.java b/services/backup/java/com/android/server/backup/TransportManager.java index b9dbe13af7c8..619ddb16ee9b 100644 --- a/services/backup/java/com/android/server/backup/TransportManager.java +++ b/services/backup/java/com/android/server/backup/TransportManager.java @@ -41,6 +41,7 @@ import com.android.internal.backup.IBackupTransport; import com.android.server.EventLogTags; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -103,13 +104,18 @@ class TransportManager { // been removed from mBoundTransports because onServiceDisconnected would already been // called on TransportConnection objects. synchronized (mTransportLock) { - for (ComponentName transport : mValidTransports.keySet()) { - if (transport.getPackageName().equals(packageName)) { - TransportConnection removed = mValidTransports.remove(transport); - if (removed != null) { - mContext.unbindService(removed); - log_verbose("Package removed, Removing transport: " + - transport.flattenToShortString()); + Iterator<Map.Entry<ComponentName, TransportConnection>> iter = + mValidTransports.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry<ComponentName, TransportConnection> validTransport = iter.next(); + ComponentName componentName = validTransport.getKey(); + if (componentName.getPackageName().equals(packageName)) { + TransportConnection transportConnection = validTransport.getValue(); + iter.remove(); + if (transportConnection != null) { + mContext.unbindService(transportConnection); + log_verbose("Package removed, removing transport: " + + componentName.flattenToShortString()); } } } @@ -278,15 +284,16 @@ class TransportManager { } private void tryBindTransport(ServiceInfo transport) { - Slog.d(TAG, "Binding to transport: " + transport.getComponentName().flattenToShortString()); + final ComponentName transportComponentName = transport.getComponentName(); + Slog.d(TAG, "Binding to transport: " + transportComponentName.flattenToShortString()); // TODO: b/22388012 (Multi user backup and restore) - TransportConnection connection = new TransportConnection(transport.getComponentName()); - if (bindToTransport(transport.getComponentName(), connection)) { + TransportConnection connection = new TransportConnection(transportComponentName); + if (bindToTransport(transportComponentName, connection)) { synchronized (mTransportLock) { - mValidTransports.put(transport.getComponentName(), connection); + mValidTransports.put(transportComponentName, connection); } } else { - Slog.w(TAG, "Couldn't bind to transport " + transport.getComponentName()); + Slog.w(TAG, "Couldn't bind to transport " + transportComponentName); } } diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index 5ffb7385fcc3..0d438cb0f87a 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -99,6 +99,7 @@ class AlarmManagerService extends SystemService { static final boolean DEBUG_VALIDATE = localLOGV || false; static final boolean DEBUG_ALARM_CLOCK = localLOGV || false; static final boolean DEBUG_LISTENER_CALLBACK = localLOGV || false; + static final boolean DEBUG_WAKELOCK = localLOGV || false; static final boolean RECORD_ALARMS_IN_HISTORY = true; static final boolean RECORD_DEVICE_IDLE_ALARMS = false; static final int ALARM_EVENT = 1; @@ -2934,6 +2935,9 @@ class AlarmManagerService extends SystemService { updateStatsLocked(inflight); } mBroadcastRefCount--; + if (DEBUG_WAKELOCK) { + Slog.d(TAG, "mBroadcastRefCount -> " + mBroadcastRefCount); + } if (mBroadcastRefCount == 0) { mHandler.obtainMessage(AlarmHandler.REPORT_ALARMS_ACTIVE, 0).sendToTarget(); mWakeLock.release(); @@ -3074,6 +3078,9 @@ class AlarmManagerService extends SystemService { } // The alarm is now in flight; now arrange wakelock and stats tracking + if (DEBUG_WAKELOCK) { + Slog.d(TAG, "mBroadcastRefCount -> " + (mBroadcastRefCount + 1)); + } if (mBroadcastRefCount == 0) { setWakelockWorkSource(alarm.operation, alarm.workSource, alarm.type, alarm.statsTag, (alarm.operation == null) ? alarm.uid : -1, diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 88ceb6fa4109..e9e73cc20510 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -135,6 +135,8 @@ 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.LOCK_TASK_AUTH_LAUNCHABLE_PRIV; import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE; +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.wm.AppTransition.TRANSIT_ACTIVITY_OPEN; import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_RELAUNCH; import static com.android.server.wm.AppTransition.TRANSIT_NONE; @@ -144,6 +146,8 @@ import static com.android.server.wm.AppTransition.TRANSIT_TASK_TO_FRONT; import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; import static org.xmlpull.v1.XmlPullParser.START_TAG; +import static java.lang.Integer.MAX_VALUE; + import android.Manifest; import android.Manifest.permission; import android.annotation.NonNull; @@ -4157,13 +4161,9 @@ public class ActivityManagerService extends IActivityManager.Stub synchronized (this) { for (int i=mLruProcesses.size()-1; i>=0; i--) { final ProcessRecord proc = mLruProcesses.get(i); - if (procState == ActivityManager.PROCESS_STATE_NONEXISTENT - || procState > proc.setProcState) { - if (proc.pkgList.containsKey(packageName)) { - procState = proc.setProcState; - break; - } - if (proc.pkgDeps != null && proc.pkgDeps.contains(packageName)) { + if (procState > proc.setProcState) { + if (proc.pkgList.containsKey(packageName) || + (proc.pkgDeps != null && proc.pkgDeps.contains(packageName))) { procState = proc.setProcState; } } @@ -9812,14 +9812,19 @@ public class ActivityManagerService extends IActivityManager.Stub } else if (bounds != null && stackId != FREEFORM_WORKSPACE_STACK_ID ) { stackId = FREEFORM_WORKSPACE_STACK_ID; } + + // Reparent the task to the right stack if necessary boolean preserveWindow = (resizeMode & RESIZE_MODE_PRESERVE_WINDOW) != 0; if (stackId != task.getStackId()) { - mStackSupervisor.moveTaskToStackUncheckedLocked(task, stackId, ON_TOP, - !FORCE_FOCUS, "resizeTask"); + // Defer resume until the task is resized below + task.reparent(stackId, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, + DEFER_RESUME, "resizeTask"); preserveWindow = false; } - task.resize(bounds, resizeMode, preserveWindow, false /* deferResume */); + // After reparenting (which only resizes the task to the stack bounds), resize the + // task to the actual bounds provided + task.resize(bounds, resizeMode, preserveWindow, !DEFER_RESUME); } } finally { Binder.restoreCallingIdentity(ident); @@ -10198,14 +10203,16 @@ public class ActivityManagerService extends IActivityManager.Stub throw new IllegalArgumentException( "exitFreeformMode: No activity record matching token=" + token); } - final ActivityStack stack = r.getStackLocked(token); + + final ActivityStack stack = r.getStack(); if (stack == null || stack.mStackId != FREEFORM_WORKSPACE_STACK_ID) { throw new IllegalStateException( "exitFreeformMode: You can only go fullscreen from freeform."); } + if (DEBUG_STACK) Slog.d(TAG_STACK, "exitFreeformMode: " + r); - mStackSupervisor.moveTaskToStackLocked(r.task.taskId, FULLSCREEN_WORKSPACE_STACK_ID, - ON_TOP, !FORCE_FOCUS, "exitFreeformMode", ANIMATE); + r.task.reparent(FULLSCREEN_WORKSPACE_STACK_ID, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, + ANIMATE, !DEFER_RESUME, "exitFreeformMode"); } finally { Binder.restoreCallingIdentity(ident); } @@ -10222,15 +10229,22 @@ public class ActivityManagerService extends IActivityManager.Stub synchronized (this) { long ident = Binder.clearCallingIdentity(); try { + final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId); + if (task == null) { + Slog.w(TAG, "moveTaskToStack: No task for id=" + taskId); + return; + } + 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 */); } - boolean result = mStackSupervisor.moveTaskToStackLocked(taskId, stackId, toTop, - !FORCE_FOCUS, "moveTaskToStack", ANIMATE); - if (result && stackId == DOCKED_STACK_ID) { + + final boolean successful = task.reparent(stackId, toTop, + REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, !DEFER_RESUME, "moveTaskToStack"); + if (successful && stackId == DOCKED_STACK_ID) { // If task moved to docked stack - show recents if needed. mWindowManager.showRecentApps(false /* fromHome */); } @@ -10262,22 +10276,23 @@ public class ActivityManagerService extends IActivityManager.Stub // TODO: App transition mWindowManager.prepareAppTransition(TRANSIT_ACTIVITY_RELAUNCH, false); - // Defer the resume so resume/pausing while moving stacks is dangerous. - mStackSupervisor.moveTaskToStackLocked(topTask.taskId, DOCKED_STACK_ID, - false /* toTop */, !FORCE_FOCUS, "swapDockedAndFullscreenStack", - ANIMATE, true /* deferResume */); + // Defer the resume until we move all the docked tasks to the fullscreen stack below + topTask.reparent(DOCKED_STACK_ID, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, + DEFER_RESUME, "swapDockedAndFullscreenStack - DOCKED_STACK"); final int size = tasks.size(); for (int i = 0; i < size; i++) { final int id = tasks.get(i).taskId; if (id == topTask.taskId) { continue; } - mStackSupervisor.moveTaskToStackLocked(id, - FULLSCREEN_WORKSPACE_STACK_ID, true /* toTop */, !FORCE_FOCUS, - "swapDockedAndFullscreenStack", ANIMATE, true /* deferResume */); + + // Defer the resume until after all the tasks have been moved + tasks.get(i).reparent(FULLSCREEN_WORKSPACE_STACK_ID, ON_TOP, + REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, DEFER_RESUME, + "swapDockedAndFullscreenStack - FULLSCREEN_STACK"); } - // Because we deferred the resume, to avoid conflicts with stack switches while + // Because we deferred the resume to avoid conflicts with stack switches while // resuming, we need to do it after all the tasks are moved. mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); mStackSupervisor.resumeFocusedStackTopActivityLocked(); @@ -10310,12 +10325,20 @@ public class ActivityManagerService extends IActivityManager.Stub synchronized (this) { long ident = Binder.clearCallingIdentity(); try { + final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId); + if (task == null) { + Slog.w(TAG, "moveTaskToDockedStack: No task for id=" + taskId); + return false; + } + if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToDockedStack: moving task=" + taskId + " to createMode=" + createMode + " toTop=" + toTop); mWindowManager.setDockedStackCreateState(createMode, initialBounds); - final boolean moved = mStackSupervisor.moveTaskToStackLocked( - taskId, DOCKED_STACK_ID, toTop, !FORCE_FOCUS, "moveTaskToDockedStack", - animate, DEFER_RESUME); + + // Defer resuming until we move the home stack to the front below + final boolean moved = task.reparent(DOCKED_STACK_ID, toTop, + REPARENT_KEEP_STACK_AT_FRONT, animate, DEFER_RESUME, + "moveTaskToDockedStack"); if (moved) { if (moveHomeStackFront) { mStackSupervisor.moveHomeStackToFront("moveTaskToDockedStack"); @@ -10449,7 +10472,8 @@ public class ActivityManagerService extends IActivityManager.Stub stack.positionChildAt(task, position); } else { // Reparent to new stack. - task.reparent(stackId, position, "positionTaskInStack"); + task.reparent(stackId, position, REPARENT_LEAVE_STACK_IN_PLACE, + !ANIMATE, !DEFER_RESUME, "positionTaskInStack"); } } finally { Binder.restoreCallingIdentity(ident); @@ -18853,7 +18877,9 @@ public class ActivityManagerService extends IActivityManager.Stub appOp, brOptions, registeredReceivers, resultTo, resultCode, resultData, resultExtras, ordered, sticky, false, userId); if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r); - final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r); + final boolean replaced = replacePending + && (queue.replaceParallelBroadcastLocked(r) != null); + // Note: We assume resultTo is null for non-ordered broadcasts. if (!replaced) { queue.enqueueParallelBroadcastLocked(r); queue.scheduleBroadcastsLocked(); @@ -18952,8 +18978,25 @@ public class ActivityManagerService extends IActivityManager.Stub if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST, "Enqueueing broadcast " + r.intent.getAction()); - boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r); - if (!replaced) { + final BroadcastRecord oldRecord = + replacePending ? queue.replaceOrderedBroadcastLocked(r) : null; + if (oldRecord != null) { + // Replaced, fire the result-to receiver. + if (oldRecord.resultTo != null) { + final BroadcastQueue oldQueue = broadcastQueueForIntent(oldRecord.intent); + try { + oldQueue.performReceiveLocked(oldRecord.callerApp, oldRecord.resultTo, + oldRecord.intent, + Activity.RESULT_CANCELED, null, null, + false, false, oldRecord.userId); + } catch (RemoteException e) { + Slog.w(TAG, "Failure [" + + queue.mQueueName + "] sending broadcast result of " + + intent, e); + + } + } + } else { queue.enqueueOrderedBroadcastLocked(r); queue.scheduleBroadcastsLocked(); } diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index fa7dd28eb856..c79ed2af29aa 100644 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -797,6 +797,15 @@ final class ActivityRecord implements AppWindowContainerListener { + " is already the parent of r=" + this); } + // TODO: Ensure that we do not directly reparent activities across stacks, as that may leave + // the stacks in strange states. For now, we should use Task.reparent() to ensure that + // the stack is left in an OK state. + if (prevTask != null && newTask != null && prevTask.getStack() != newTask.getStack()) { + throw new IllegalArgumentException(reason + ": task=" + newTask + + " is in a different stack (" + newTask.getStackId() + ") than the parent of" + + " r=" + this + " (" + prevTask.getStackId() + ")"); + } + // Must reparent first in window manager mWindowContainerController.reparent(newTask.getWindowContainerController(), position); @@ -2019,12 +2028,6 @@ final class ActivityRecord implements AppWindowContainerListener { // Okay we now are going to make this activity have the new config. // But then we need to figure out how it needs to deal with that. - - // Find changes between last reported merged configuration and the current one. This is used - // to decide whether to relaunch an activity or just report a configuration change. - final int changes = getTaskConfigurationChanges(mTmpConfig1); - - // Update last reported values. final Configuration newGlobalConfig = service.getGlobalConfiguration(); final Configuration newTaskMergedOverrideConfig = task.getMergedOverrideConfiguration(); mTmpConfig1.setTo(mLastReportedConfiguration); @@ -2032,6 +2035,9 @@ final class ActivityRecord implements AppWindowContainerListener { mLastReportedConfiguration.setTo(newGlobalConfig); mLastReportedOverrideConfiguration.setTo(newTaskMergedOverrideConfig); + int taskChanges = getTaskConfigurationChanges(this, newTaskMergedOverrideConfig, + mTmpConfig2); + final int changes = mTmpConfig1.diff(newGlobalConfig) | taskChanges; if (changes == 0 && !forceNewConfig) { if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Configuration no differences in " + this); @@ -2046,7 +2052,8 @@ final class ActivityRecord implements AppWindowContainerListener { } if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, - "Configuration changes for " + this + ", allChanges=" + "Configuration changes for " + this + " ; taskChanges=" + + Configuration.configurationDiffToString(taskChanges) + ", allChanges=" + Configuration.configurationDiffToString(changes)); // If the activity isn't currently running, just leave the new configuration and it will @@ -2144,27 +2151,40 @@ final class ActivityRecord implements AppWindowContainerListener { return (changes&(~configChanged)) != 0; } - private int getTaskConfigurationChanges(Configuration newTaskConfig) { + private static int getTaskConfigurationChanges(ActivityRecord record, Configuration taskConfig, + Configuration oldTaskOverride) { + // If we went from full-screen to non-full-screen, make sure to use the correct + // configuration task diff, so the diff stays as small as possible. + if (Configuration.EMPTY.equals(oldTaskOverride) + && !Configuration.EMPTY.equals(taskConfig)) { + oldTaskOverride = record.task.extractOverrideConfig(record.mLastReportedConfiguration); + } + + // Conversely, do the same when going the other direction. + if (Configuration.EMPTY.equals(taskConfig) + && !Configuration.EMPTY.equals(oldTaskOverride)) { + taskConfig = record.task.extractOverrideConfig(record.mLastReportedConfiguration); + } + // Determine what has changed. May be nothing, if this is a config that has come back from // the app after going idle. In that case we just want to leave the official config object // now in the activity and do nothing else. - final Configuration oldTaskConfig = task.getConfiguration(); - int taskChanges = oldTaskConfig.diff(newTaskConfig, true /* skipUndefined */); + int taskChanges = oldTaskOverride.diff(taskConfig, true /* skipUndefined */); // We don't want to use size changes if they don't cross boundaries that are important to // the app. if ((taskChanges & CONFIG_SCREEN_SIZE) != 0) { - final boolean crosses = crossesHorizontalSizeThreshold(oldTaskConfig.screenWidthDp, - newTaskConfig.screenWidthDp) - || crossesVerticalSizeThreshold(oldTaskConfig.screenHeightDp, - newTaskConfig.screenHeightDp); + final boolean crosses = record.crossesHorizontalSizeThreshold( + oldTaskOverride.screenWidthDp, taskConfig.screenWidthDp) + || record.crossesVerticalSizeThreshold( + oldTaskOverride.screenHeightDp, taskConfig.screenHeightDp); if (!crosses) { taskChanges &= ~CONFIG_SCREEN_SIZE; } } if ((taskChanges & CONFIG_SMALLEST_SCREEN_SIZE) != 0) { - final int oldSmallest = oldTaskConfig.smallestScreenWidthDp; - final int newSmallest = newTaskConfig.smallestScreenWidthDp; - if (!crossesSmallestSizeThreshold(oldSmallest, newSmallest)) { + final int oldSmallest = oldTaskOverride.smallestScreenWidthDp; + final int newSmallest = taskConfig.smallestScreenWidthDp; + if (!record.crossesSmallestSizeThreshold(oldSmallest, newSmallest)) { taskChanges &= ~CONFIG_SMALLEST_SCREEN_SIZE; } } diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 827a41e776d8..5d4bff97b1b1 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -5077,45 +5077,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai moveToFront(reason); } - /** - * Moves the input activity from its current stack to this one. - * NOTE: The current task of the activity isn't moved to this stack. Instead a new task is - * created on this stack which the activity is added to. - * */ - void moveActivityToStack(ActivityRecord r) { - final ActivityStack prevStack = r.getStack(); - if (prevStack.mStackId == mStackId) { - // You are already in the right stack silly... - return; - } - - final boolean wasFocused = mStackSupervisor.isFocusedStack(prevStack) - && (mStackSupervisor.topRunningActivityLocked() == r); - final boolean wasResumed = wasFocused && (prevStack.mResumedActivity == r); - final boolean wasPaused = prevStack.mPausingActivity == r; - - // Create a new task for the activity to be parented in - final TaskRecord task = createTaskRecord( - mStackSupervisor.getNextTaskIdForUserLocked(r.userId), - r.info, r.intent, null, null, true, r.mActivityType); - // This is a new task, so reparenting it to position 0 will move it to the top - r.reparent(task, 0 /* position */, "moveActivityToStack"); - - // Notify the task actiivties if it was moved to/from a pinned stack - mStackSupervisor.scheduleReportPictureInPictureModeChangedIfNeeded(task, prevStack); - - // Resume the activity if necessary after it has moved - moveToFrontAndResumeStateIfNeeded(r, wasFocused, wasResumed, wasPaused, - "moveActivityToStack"); - if (wasResumed) { - prevStack.mResumedActivity = null; - } - if (wasPaused) { - prevStack.mPausingActivity = null; - prevStack.removeTimeoutsForActivityLocked(r); - } - } - public int getStackId() { return mStackId; } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index d3ad0572d556..6e138a161e1c 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -89,6 +89,9 @@ import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE; import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV; import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE; import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_WHITELISTED; +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.wm.AppTransition.TRANSIT_DOCK_TASK_FROM_RECENTS; import static java.lang.Integer.MAX_VALUE; @@ -1992,8 +1995,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D stackId = task.getLaunchStackId(); } if (stackId != currentStack.mStackId) { - currentStack = moveTaskToStackUncheckedLocked(task, stackId, ON_TOP, - !FORCE_FOCUS, reason); + task.reparent(stackId, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, !ANIMATE, + DEFER_RESUME, "findTaskToMoveToFrontLocked"); stackId = currentStack.mStackId; // moveTaskToStackUncheckedLocked() should already placed the task on top, // still need moveTaskToFrontLocked() below for any transition settings. @@ -2278,6 +2281,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D if (onTop) { for (int i = 0; i < size; i++) { final TaskRecord task = tasks.get(i); + final boolean isTopTask = i == (size - 1); if (fromStackId == PINNED_STACK_ID) { // Update the return-to to reflect where the pinned stack task was moved // from so that we retain the stack that was previously visible if the @@ -2287,22 +2291,25 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D MetricsLogger.action(mService.mContext, MetricsEvent.ACTION_PICTURE_IN_PICTURE_EXPANDED_TO_FULLSCREEN); } - moveTaskToStackLocked(tasks.get(i).taskId, - FULLSCREEN_WORKSPACE_STACK_ID, onTop, onTop /*forceFocus*/, - "moveTasksToFullscreenStack - onTop", ANIMATE, DEFER_RESUME); + // Defer resume until all the tasks have been moved to the fullscreen stack + task.reparent(FULLSCREEN_WORKSPACE_STACK_ID, ON_TOP, + REPARENT_MOVE_STACK_TO_FRONT, isTopTask /* animate */, DEFER_RESUME, + "moveTasksToFullscreenStack - onTop"); } - - ensureActivitiesVisibleLocked(null, 0, PRESERVE_WINDOWS); - resumeFocusedStackTopActivityLocked(); } else { for (int i = 0; i < size; i++) { final TaskRecord task = tasks.get(i); - final int position = fullscreenStack != null ? - Math.max(fullscreenStack.getAllTasks().size() - 1, 0) : 0; + final int position = fullscreenStack != null + ? Math.max(fullscreenStack.getAllTasks().size() - 1, 0) : 0; + // Defer resume until all the tasks have been moved to the fullscreen stack task.reparent(FULLSCREEN_WORKSPACE_STACK_ID, position, - "moveTasksToFullscreenStack - NOT_onTop"); + REPARENT_LEAVE_STACK_IN_PLACE, !ANIMATE, + DEFER_RESUME, "moveTasksToFullscreenStack - NOT_onTop"); } } + + ensureActivitiesVisibleLocked(null, 0, PRESERVE_WINDOWS); + resumeFocusedStackTopActivityLocked(); } finally { mAllowDockedStackResize = true; mWindowManager.continueSurfaceLayout(); @@ -2445,14 +2452,16 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D ? Math.max(0, fullscreenStack.getChildCount() - 1) : fullscreenStack.getChildCount(); final TaskRecord task = tasks.get(i); - task.reparent(FULLSCREEN_WORKSPACE_STACK_ID, insertPosition, "removeStack"); + // Defer resume until we remove all the tasks + task.reparent(FULLSCREEN_WORKSPACE_STACK_ID, insertPosition, + REPARENT_LEAVE_STACK_IN_PLACE, !ANIMATE, DEFER_RESUME, "removeStack"); } ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); resumeFocusedStackTopActivityLocked(); } else { // If there is no fullscreen stack, then create the stack and move all the tasks // onto the stack - moveTasksToFullscreenStackLocked(PINNED_STACK_ID, false /* onTop */); + moveTasksToFullscreenStackLocked(PINNED_STACK_ID, !ON_TOP); } } else { for (int i = tasks.size() - 1; i >= 0; i--) { @@ -2657,168 +2666,52 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } /** - * Moves the specified task record to the input stack id. - * WARNING: This method performs an unchecked/raw move of the task and - * can leave the system in an unstable state if used incorrectly. - * Use {@link #moveTaskToStackLocked} to perform safe task movement to a stack. - * @param task Task to move. - * @param stackId Id of stack to move task to. - * @param toTop True if the task should be placed at the top of the stack. - * @param forceFocus if focus should be moved to the new stack - * @param reason Reason the task is been moved. - * @return The stack the task was moved to. + * Returns the reparent target stack, creating the stack if necessary. This call also enforces + * the various checks on tasks that are going to be reparented from one stack to another. */ - ActivityStack moveTaskToStackUncheckedLocked(TaskRecord task, int stackId, boolean toTop, - boolean forceFocus, String reason) { - - if (StackId.isMultiWindowStack(stackId) && !mService.mSupportsMultiWindow) { - throw new IllegalStateException("moveTaskToStackUncheckedLocked: Device doesn't " - + "support multi-window task=" + task + " to stackId=" + stackId); - } - - final ActivityRecord r = task.topRunningActivityLocked(); + ActivityStack getReparentTargetStack(TaskRecord task, int stackId, boolean toTop) { final ActivityStack prevStack = task.getStack(); - final boolean wasFocused = isFocusedStack(prevStack) && (topRunningActivityLocked() == r); - final boolean wasResumed = prevStack.mResumedActivity == r; - final boolean wasPaused = prevStack.mPausingActivity == r; - // 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 = isFrontStackOnDisplay(prevStack) - && (prevStack.topRunningActivityLocked() == r); - - if (stackId == DOCKED_STACK_ID && !task.isResizeable()) { - // We don't allow moving a unresizeable task to the docked stack since the docked - // stack is used for split-screen mode and will cause things like the docked divider to - // show up. We instead leave the task in its current stack or move it to the fullscreen - // stack if it isn't currently in a stack. - stackId = (prevStack != null) ? prevStack.mStackId : FULLSCREEN_WORKSPACE_STACK_ID; - Slog.w(TAG, "Can not move unresizeable task=" + task - + " to docked stack. Moving to stackId=" + stackId + " instead."); - } - // Temporarily disable resizeablility of task we are moving. We don't want it to be resized - // if a docked stack is created below which will lead to the stack we are moving from and - // its resizeable tasks being resized. - task.mTemporarilyUnresizable = true; - final ActivityStack stack = getStack(stackId, CREATE_IF_NEEDED, toTop); - task.mTemporarilyUnresizable = false; - task.reparent(stack.mStackId, toTop ? MAX_VALUE : 0, reason); - - // Reset the resumed activity on the previous stack - if (wasResumed) { - prevStack.mResumedActivity = null; - } - // Reset the paused activity on the previous stack - if (wasPaused) { - prevStack.mPausingActivity = null; - prevStack.removeTimeoutsForActivityLocked(r); - } - - // If the task had focus before (or we're requested to move focus), - // move focus to the new stack by moving the stack to the front. - stack.moveToFrontAndResumeStateIfNeeded(r, forceFocus || wasFocused || wasFront, wasResumed, - wasPaused, reason); - - return stack; - } - - boolean moveTaskToStackLocked(int taskId, int stackId, boolean toTop, boolean forceFocus, - String reason, boolean animate) { - return moveTaskToStackLocked(taskId, stackId, toTop, forceFocus, reason, animate, - false /* deferResume */); - } - - boolean moveTaskToStackLocked(int taskId, int stackId, boolean toTop, boolean forceFocus, - String reason, boolean animate, boolean deferResume) { - final TaskRecord task = anyTaskForIdLocked(taskId); - if (task == null) { - Slog.w(TAG, "moveTaskToStack: no task for id=" + taskId); - return false; + // Check that we aren't reparenting to the same stack that the task is already in + if (prevStack != null && prevStack.mStackId == stackId) { + Slog.w(TAG, "Can not reparent to same stack, task=" + task + + " already in stackId=" + stackId); + return prevStack; } - final ActivityStack currentStack = task.getStack(); - if (currentStack != null && currentStack.mStackId == stackId) { - // You are already in the right stack silly... - Slog.i(TAG, "moveTaskToStack: taskId=" + taskId + " already in stackId=" + stackId); - return true; + // Ensure that we aren't trying to move into a multi-window stack without multi-window + // support + if (StackId.isMultiWindowStack(stackId) && !mService.mSupportsMultiWindow) { + throw new IllegalArgumentException("Device doesn't support multi-window, can not" + + " reparent task=" + task + " to stackId=" + stackId); } + // Ensure that we aren't trying to move into a freeform stack without freeform + // support if (stackId == FREEFORM_WORKSPACE_STACK_ID && !mService.mSupportsFreeformWindowManagement) { - throw new IllegalArgumentException("moveTaskToStack:" - + "Attempt to move task " + taskId + " to unsupported freeform stack"); + throw new IllegalArgumentException("Device doesn't support freeform, can not reparent" + + " task=" + task); } - final ActivityRecord topActivity = task.getTopActivity(); - final int sourceStackId = task.getStackId(); - 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 - // and then add a new one. This call will tell window manager about this, so it can - // preserve the old window until the new one is drawn. This prevents having a gap - // between the removal and addition, in which no window is visible. We also want the - // entrance of the new window to be properly animated. - // Note here we always set the replacing window first, as the flags might be needed - // during the relaunch. If we end up not doing any relaunch, we clear the flags later. - mWindowManager.setWillReplaceWindow(topActivity.appToken, animate); + // We don't allow moving a unresizeable task to the docked stack since the docked stack is + // used for split-screen mode and will cause things like the docked divider to show up. We + // instead leave the task in its current stack or move it to the fullscreen stack if it + // isn't currently in a stack. + if (stackId == DOCKED_STACK_ID && !task.isResizeable()) { + stackId = (prevStack != null) ? prevStack.mStackId : FULLSCREEN_WORKSPACE_STACK_ID; + Slog.w(TAG, "Can not move unresizeable task=" + task + " to docked stack." + + " Moving to stackId=" + stackId + " instead."); } - mWindowManager.deferSurfaceLayout(); - final int preferredLaunchStackId = stackId; - boolean kept = true; + // Temporarily disable resizeablility of the task as we don't want it to be resized if, for + // example, a docked stack is created which will lead to the stack we are moving from being + // resized and and its resizeable tasks being resized. try { - final ActivityStack stack = moveTaskToStackUncheckedLocked( - task, stackId, toTop, forceFocus, reason + " moveTaskToStack"); - stackId = stack.mStackId; - - if (!animate) { - stack.mNoAnimActivities.add(topActivity); - } - - // We might trigger a configuration change. Save the current task bounds for freezing. - // TODO: Should this call be moved inside the resize method in WM? - stack.prepareFreezingTaskBounds(); - - // Make sure the task has the appropriate bounds/size for the stack it is in. - if (stackId == FULLSCREEN_WORKSPACE_STACK_ID - && !Objects.equals(task.mBounds, stack.mBounds)) { - kept = task.resize(stack.mBounds, RESIZE_MODE_SYSTEM, !mightReplaceWindow, - deferResume); - } else if (stackId == FREEFORM_WORKSPACE_STACK_ID) { - Rect bounds = task.getLaunchBounds(); - if (bounds == null) { - stack.layoutTaskInStack(task, null); - bounds = task.mBounds; - } - kept = task.resize(bounds, RESIZE_MODE_FORCED, !mightReplaceWindow, deferResume); - } else if (stackId == DOCKED_STACK_ID || stackId == PINNED_STACK_ID) { - kept = task.resize(stack.mBounds, RESIZE_MODE_SYSTEM, !mightReplaceWindow, - deferResume); - } + task.mTemporarilyUnresizable = true; + return getStack(stackId, CREATE_IF_NEEDED, toTop); } finally { - mWindowManager.continueSurfaceLayout(); + task.mTemporarilyUnresizable = false; } - - if (mightReplaceWindow) { - // If we didn't actual do a relaunch (indicated by kept==true meaning we kept the old - // window), we need to clear the replace window settings. Otherwise, we schedule a - // timeout to remove the old window if the replacing window is not coming in time. - mWindowManager.scheduleClearWillReplaceWindows(topActivity.appToken, !kept); - } - - if (!deferResume) { - - // The task might have already been running and its visibility needs to be synchronized with - // the visibility of the stack / windows. - ensureActivitiesVisibleLocked(null, 0, !mightReplaceWindow); - resumeFocusedStackTopActivityLocked(); - } - - handleNonResizableTaskIfNeeded(task, preferredLaunchStackId, stackId); - - return (preferredLaunchStackId == stackId); } boolean moveTopStackActivityToPinnedStackLocked(int stackId, Rect bounds) { @@ -2849,8 +2742,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D void moveActivityToPinnedStackLocked(ActivityRecord r, String reason, Rect bounds, boolean moveHomeStackToFront) { - mWindowManager.deferSurfaceLayout(); + // Need to make sure the pinned stack exist so we can resize it below... final PinnedActivityStack stack = getStack(PINNED_STACK_ID, CREATE_IF_NEEDED, ON_TOP); @@ -2882,12 +2775,26 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // was launched from home so home should be visible behind it. moveHomeStackToFront(reason); } - moveTaskToStackLocked( - task.taskId, PINNED_STACK_ID, ON_TOP, FORCE_FOCUS, reason, !ANIMATE); + // Defer resume until below + task.reparent(PINNED_STACK_ID, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, !ANIMATE, + DEFER_RESUME, reason); } else { // There are multiple activities in the task and moving the top activity should - // reveal/leave the other activities in their original task - stack.moveActivityToStack(r); + // reveal/leave the other activities in their original task. + + // Currently, we don't support reparenting activities across tasks in two different + // stacks, so instead, just create a new task in the same stack, reparent the + // activity into that task, and then reparent the whole task to the new stack. This + // ensures that all the necessary work to migrate states in the old and new stacks + // is also done. + final TaskRecord newTask = task.getStack().createTaskRecord( + getNextTaskIdForUserLocked(r.userId), r.info, r.intent, null, null, true, + r.mActivityType); + r.reparent(newTask, MAX_VALUE, "moveActivityToStack"); + + // Defer resume until below + newTask.reparent(PINNED_STACK_ID, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, !ANIMATE, + DEFER_RESUME, reason); } // Reset the state that indicates it can enter PiP while pausing after we've moved it @@ -4880,9 +4787,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D if (launchStackId != INVALID_STACK_ID) { if (task.getStackId() != launchStackId) { - moveTaskToStackLocked( - taskId, launchStackId, ON_TOP, FORCE_FOCUS, "startActivityFromRecents", - ANIMATE); + task.reparent(launchStackId, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, + DEFER_RESUME, "startActivityFromRecents"); } } diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index 94656c4eb2e3..b9ae4fd4f7b3 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -77,11 +77,16 @@ import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE; import static com.android.server.am.ActivityStack.ActivityState.RESUMED; import static com.android.server.am.ActivityStack.STACK_INVISIBLE; import static com.android.server.am.ActivityStackSupervisor.CREATE_IF_NEEDED; +import static com.android.server.am.ActivityStackSupervisor.DEFER_RESUME; import static com.android.server.am.ActivityStackSupervisor.FORCE_FOCUS; import static com.android.server.am.ActivityStackSupervisor.ON_TOP; import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; import static com.android.server.am.ActivityStackSupervisor.TAG_TASKS; import static com.android.server.am.EventLogTags.AM_NEW_INTENT; +import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT; +import static com.android.server.am.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT; + +import static java.lang.Integer.MAX_VALUE; import android.annotation.NonNull; import android.app.ActivityManager; @@ -1489,9 +1494,9 @@ class ActivityStarter { if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) { // If we want to launch adjacent and mTargetStack is not the computed // launch stack - move task to top of computed stack. - mSupervisor.moveTaskToStackLocked(intentActivity.task.taskId, - launchStack.mStackId, ON_TOP, FORCE_FOCUS, "launchToSide", - ANIMATE); + intentActivity.task.reparent(launchStack.mStackId, ON_TOP, + REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, DEFER_RESUME, + "launchToSide"); } else { // TODO: This should be reevaluated in MW v2. // We choose to move task to front instead of launching it adjacent @@ -1710,8 +1715,8 @@ class ActivityStarter { if (mTargetStack == null) { mTargetStack = sourceStack; } else if (mTargetStack != sourceStack) { - mSupervisor.moveTaskToStackLocked(sourceTask.taskId, mTargetStack.mStackId, - ON_TOP, FORCE_FOCUS, "launchToSide", !ANIMATE); + sourceTask.reparent(mTargetStack.mStackId, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, + !ANIMATE, DEFER_RESUME, "launchToSide"); } final TaskRecord topTask = mTargetStack.topTask(); @@ -1777,9 +1782,9 @@ class ActivityStarter { mInTask.updateOverrideConfiguration(mLaunchBounds); int stackId = mInTask.getLaunchStackId(); if (stackId != mInTask.getStackId()) { - final ActivityStack stack = mSupervisor.moveTaskToStackUncheckedLocked(mInTask, - stackId, ON_TOP, !FORCE_FOCUS, "inTaskToFront"); - stackId = stack.mStackId; + mInTask.reparent(stackId, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, !ANIMATE, + DEFER_RESUME, "inTaskToFront"); + stackId = mInTask.getStackId(); } if (StackId.resizeStackWithLaunchBounds(stackId)) { mService.resizeStack(stackId, mLaunchBounds, true, !PRESERVE_WINDOWS, ANIMATE, -1); diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index 68253c78c78c..75b5929b0c65 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -239,33 +239,37 @@ public final class BroadcastQueue { } } - public final boolean replaceParallelBroadcastLocked(BroadcastRecord r) { - final Intent intent = r.intent; - for (int i = mParallelBroadcasts.size() - 1; i >= 0; i--) { - final Intent curIntent = mParallelBroadcasts.get(i).intent; - if (intent.filterEquals(curIntent)) { - if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, - "***** DROPPING PARALLEL [" - + mQueueName + "]: " + intent); - mParallelBroadcasts.set(i, r); - return true; - } - } - return false; + /** + * Find the same intent from queued parallel broadcast, replace with a new one and return + * the old one. + */ + public final BroadcastRecord replaceParallelBroadcastLocked(BroadcastRecord r) { + return replaceBroadcastLocked(mParallelBroadcasts, r, "PARALLEL"); } - public final boolean replaceOrderedBroadcastLocked(BroadcastRecord r) { + /** + * Find the same intent from queued ordered broadcast, replace with a new one and return + * the old one. + */ + public final BroadcastRecord replaceOrderedBroadcastLocked(BroadcastRecord r) { + return replaceBroadcastLocked(mOrderedBroadcasts, r, "ORDERED"); + } + + private BroadcastRecord replaceBroadcastLocked(ArrayList<BroadcastRecord> queue, + BroadcastRecord r, String typeForLogging) { final Intent intent = r.intent; - for (int i = mOrderedBroadcasts.size() - 1; i > 0; i--) { - if (intent.filterEquals(mOrderedBroadcasts.get(i).intent)) { - if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, - "***** DROPPING ORDERED [" - + mQueueName + "]: " + intent); - mOrderedBroadcasts.set(i, r); - return true; + for (int i = queue.size() - 1; i > 0; i--) { + final BroadcastRecord old = queue.get(i); + if (old.userId == r.userId && intent.filterEquals(old.intent)) { + if (DEBUG_BROADCAST) { + Slog.v(TAG_BROADCAST, "***** DROPPING " + + typeForLogging + " [" + mQueueName + "]: " + intent); + } + queue.set(i, r); + return old; } } - return false; + return null; } private final void processCurBroadcastLocked(BroadcastRecord r, diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index 241042452fb1..3f33f41e03f6 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -16,6 +16,7 @@ package com.android.server.am; +import android.annotation.IntDef; import android.annotation.Nullable; import android.app.Activity; import android.app.ActivityManager; @@ -54,6 +55,7 @@ import com.android.server.wm.AppWindowContainerController; import com.android.server.wm.StackWindowController; import com.android.server.wm.TaskWindowContainerController; import com.android.server.wm.TaskWindowContainerListener; +import com.android.server.wm.WindowManagerService; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -62,10 +64,13 @@ import org.xmlpull.v1.XmlSerializer; import java.io.File; import java.io.IOException; import java.io.PrintWriter; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Objects; import static android.app.ActivityManager.RESIZE_MODE_FORCED; +import static android.app.ActivityManager.RESIZE_MODE_SYSTEM; import static android.app.ActivityManager.StackId.ASSISTANT_STACK_ID; import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; @@ -107,9 +112,10 @@ import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE; import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE; import static com.android.server.am.ActivityRecord.STARTING_WINDOW_SHOWN; import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_MOVING; -import static com.android.server.am.ActivityStackSupervisor.CREATE_IF_NEEDED; import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; +import static java.lang.Integer.MAX_VALUE; + final class TaskRecord extends ConfigurationContainer implements TaskWindowContainerListener { private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_AM; private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE; @@ -160,6 +166,24 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta static final int INVALID_TASK_ID = -1; private static final int INVALID_MIN_SIZE = -1; + /** + * The modes to control how the stack is moved to the front when calling + * {@link TaskRecord#reparent}. + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + REPARENT_MOVE_STACK_TO_FRONT, + REPARENT_KEEP_STACK_AT_FRONT, + REPARENT_LEAVE_STACK_IN_PLACE + }) + public @interface ReparentMoveStackMode {} + // Moves the stack to the front if it was not at the front + public static final int REPARENT_MOVE_STACK_TO_FRONT = 0; + // Only moves the stack to the front if it was focused or front most already + public static final int REPARENT_KEEP_STACK_AT_FRONT = 1; + // Do not move the stack as a part of reparenting + public static final int REPARENT_LEAVE_STACK_IN_PLACE = 2; + final int taskId; // Unique identifier for this task. String affinity; // The affinity name for this task, or null; may change identity. String rootAffinity; // Initial base affinity, or null; does not change from initial root. @@ -537,36 +561,159 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta mWindowContainerController.getBounds(bounds); } - // TODO: Should we be doing all the stuff in ASS.moveTaskToStackLocked? - void reparent(int stackId, int position, String reason) { - mService.mWindowManager.deferSurfaceLayout(); + /** + * Convenience method to reparent a task to the top or bottom position of the stack. + */ + boolean reparent(int preferredStackId, boolean toTop, @ReparentMoveStackMode int moveStackMode, + boolean animate, boolean deferResume, String reason) { + return reparent(preferredStackId, toTop ? MAX_VALUE : 0, moveStackMode, animate, + deferResume, reason); + } + + /** + * Reparents the task into a preferred stack, creating it if necessary. + * + * @param preferredStackId the stack id of the target stack to move this task + * @param position the position to place this task in the new stack + * @param animate whether or not we should wait for the new window created as a part of the + * reparenting to be drawn and animated in + * @param moveStackMode whether or not to move the stack to the front always, only if it was + * previously focused & in front, or never + * @param deferResume whether or not to update the visibility of other tasks and stacks that may + * have changed as a result of this reparenting + * @param reason the caller of this reparenting + * @return + */ + boolean reparent(int preferredStackId, int position, @ReparentMoveStackMode int moveStackMode, + boolean animate, boolean deferResume, String reason) { + final ActivityStackSupervisor supervisor = mService.mStackSupervisor; + final WindowManagerService windowManager = mService.mWindowManager; + final ActivityStack sourceStack = getStack(); + final ActivityStack toStack = supervisor.getReparentTargetStack(this, preferredStackId, + position == MAX_VALUE); + if (toStack == sourceStack) { + return false; + } + + final int sourceStackId = getStackId(); + final int stackId = toStack.getStackId(); + final ActivityRecord topActivity = getTopActivity(); + 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 + // and then add a new one. This call will tell window manager about this, so it can + // preserve the old window until the new one is drawn. This prevents having a gap + // between the removal and addition, in which no window is visible. We also want the + // entrance of the new window to be properly animated. + // Note here we always set the replacing window first, as the flags might be needed + // during the relaunch. If we end up not doing any relaunch, we clear the flags later. + windowManager.setWillReplaceWindow(topActivity.appToken, animate); + } + + windowManager.deferSurfaceLayout(); + boolean kept = true; try { - final ActivityStackSupervisor supervisor = mService.mStackSupervisor; - final ActivityStack newStack = supervisor.getStack(stackId, - CREATE_IF_NEEDED, false /* toTop */); + final ActivityRecord r = topRunningActivityLocked(); + final boolean wasFocused = supervisor.isFocusedStack(sourceStack) + && (topRunningActivityLocked() == r); + final boolean wasResumed = sourceStack.mResumedActivity == r; + final boolean wasPaused = sourceStack.mPausingActivity == r; + + // 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 = supervisor.isFrontStackOnDisplay(sourceStack) + && (sourceStack.topRunningActivityLocked() == r); + // Adjust the position for the new parent stack as needed. - position = newStack.getAdjustedPositionForTask(this, position, null /* starting */); + position = toStack.getAdjustedPositionForTask(this, position, null /* starting */); // Must reparent first in window manager to avoid a situation where AM can delete the // we are coming from in WM before we reparent because it became empty. - mWindowContainerController.reparent(newStack.getWindowContainerController(), position); + mWindowContainerController.reparent(toStack.getWindowContainerController(), position); - final ActivityStack prevStack = mStack; - prevStack.removeTask(this, reason, REMOVE_TASK_MODE_MOVING); - newStack.addTask(this, position, reason); + // Reset the resumed activity on the previous stack + if (wasResumed) { + sourceStack.mResumedActivity = null; + } + + // Reset the paused activity on the previous stack + if (wasPaused) { + sourceStack.mPausingActivity = null; + sourceStack.removeTimeoutsForActivityLocked(r); + } - supervisor.scheduleReportPictureInPictureModeChangedIfNeeded(this, prevStack); + // Move the task + sourceStack.removeTask(this, reason, REMOVE_TASK_MODE_MOVING); + toStack.addTask(this, position, reason); + // TODO: Ensure that this is actually necessary here + // Notify of picture-in-picture mode changes + supervisor.scheduleReportPictureInPictureModeChangedIfNeeded(this, sourceStack); + + // TODO: Ensure that this is actually necessary here + // Notify the voice session if required if (voiceSession != null) { try { voiceSession.taskStarted(intent, taskId); } catch (RemoteException e) { } } + + // If the task had focus before (or we're requested to move focus), move focus to the + // new stack by moving the stack to the front. + final boolean moveStackToFront = moveStackMode == REPARENT_MOVE_STACK_TO_FRONT + || (moveStackMode == REPARENT_KEEP_STACK_AT_FRONT && (wasFocused || wasFront)); + toStack.moveToFrontAndResumeStateIfNeeded(r, moveStackToFront, wasResumed, wasPaused, + reason); + if (!animate) { + toStack.mNoAnimActivities.add(topActivity); + } + + // We might trigger a configuration change. Save the current task bounds for freezing. + // TODO: Should this call be moved inside the resize method in WM? + toStack.prepareFreezingTaskBounds(); + + // Make sure the task has the appropriate bounds/size for the stack it is in. + if (stackId == FULLSCREEN_WORKSPACE_STACK_ID + && !Objects.equals(mBounds, toStack.mBounds)) { + kept = resize(toStack.mBounds, RESIZE_MODE_SYSTEM, !mightReplaceWindow, + deferResume); + } else if (stackId == FREEFORM_WORKSPACE_STACK_ID) { + Rect bounds = getLaunchBounds(); + if (bounds == null) { + toStack.layoutTaskInStack(this, null); + bounds = mBounds; + } + kept = resize(bounds, RESIZE_MODE_FORCED, !mightReplaceWindow, deferResume); + } else if (stackId == DOCKED_STACK_ID || stackId == PINNED_STACK_ID) { + kept = resize(toStack.mBounds, RESIZE_MODE_SYSTEM, !mightReplaceWindow, + deferResume); + } } finally { - mService.mWindowManager.continueSurfaceLayout(); + windowManager.continueSurfaceLayout(); + } + + if (mightReplaceWindow) { + // If we didn't actual do a relaunch (indicated by kept==true meaning we kept the old + // window), we need to clear the replace window settings. Otherwise, we schedule a + // timeout to remove the old window if the replacing window is not coming in time. + windowManager.scheduleClearWillReplaceWindows(topActivity.appToken, !kept); } + + if (!deferResume) { + // The task might have already been running and its visibility needs to be synchronized + // with the visibility of the stack / windows. + supervisor.ensureActivitiesVisibleLocked(null, 0, !mightReplaceWindow); + supervisor.resumeFocusedStackTopActivityLocked(); + } + + supervisor.handleNonResizableTaskIfNeeded(this, preferredStackId, stackId); + + return (preferredStackId == stackId); } void cancelWindowTransition() { diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java index 9c9a6711c581..0634dac8de4e 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java @@ -80,9 +80,7 @@ public class PackageManagerServiceCompilerMapping { try { // Check that the system property name is legal. String sysPropName = getSystemPropertyName(reason); - if (sysPropName == null || - sysPropName.isEmpty() || - sysPropName.length() > SystemProperties.PROP_NAME_MAX) { + if (sysPropName == null || sysPropName.isEmpty()) { throw new IllegalStateException("Reason system property name \"" + sysPropName +"\" for reason " + REASON_STRINGS[reason]); } diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index 994f38d5a94a..647adbf960a5 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -84,8 +84,6 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree final boolean mVoiceInteraction; - // TODO: Use getParent instead? - private Task mTask; /** @see WindowContainer#fillsParent() */ private boolean mFillsParent; boolean layoutConfigChanges; @@ -411,7 +409,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree } boolean windowsAreFocusable() { - return StackId.canReceiveKeys(mTask.mStack.mStackId) || mAlwaysFocusable; + return StackId.canReceiveKeys(getTask().mStack.mStackId) || mAlwaysFocusable; } AppWindowContainerController getController() { @@ -467,7 +465,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree getController().removeStartingWindow(); } - final TaskStack stack = mTask.mStack; + final TaskStack stack = getTask().mStack; if (delayed && !isEmpty()) { // set the token aside because it has an active animation to be finished if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG_WM, @@ -667,20 +665,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree } Task getTask() { - return mTask; - } - - /** - * Sets the associated task, cleaning up dependencies when unset. - */ - void setTask(Task task) { - // Note: the following code assumes that the previous task's stack is the same as the - // new task's stack. - if (!mReparenting && mTask != null && mTask.mStack != null) { - mTask.mStack.mExitingAppTokens.remove(this); - } - - mTask = task; + return (Task) getParent(); } @Override @@ -690,10 +675,15 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree // When the associated task is {@code null}, the {@link AppWindowToken} can no longer // access visual elements like the {@link DisplayContent}. We must remove any associations // such as animations. - if (!mReparenting && mTask == null) { - // It is possible we have been marked as a closing app earlier. We must remove ourselves - // from this list so we do not participate in any future animations. - mService.mClosingApps.remove(this); + if (!mReparenting) { + final Task task = getTask(); + if (task == null) { + // It is possible we have been marked as a closing app earlier. We must remove ourselves + // from this list so we do not participate in any future animations. + mService.mClosingApps.remove(this); + } else if (task.mStack != null) { + task.mStack.mExitingAppTokens.remove(this); + } } } @@ -795,16 +785,6 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree if (canFreezeBounds()) { freezeBounds(); } - - // In the process of tearing down before relaunching, the app will - // try and clean up it's child surfaces. We need to prevent this from - // happening, so we sever the children, transfering their ownership - // from the client it-self to the parent surface (owned by us). - for (int i = mChildren.size() - 1; i >= 0; i--) { - final WindowState w = mChildren.get(i); - w.mWinAnimator.detachChildren(); - } - mPendingRelaunchCount++; } @@ -895,19 +875,20 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree } void reparent(Task task, int position) { - if (task == mTask) { + final Task currentTask = getTask(); + if (task == currentTask) { throw new IllegalArgumentException( - "window token=" + this + " already child of task=" + mTask); + "window token=" + this + " already child of task=" + currentTask); } - if (mTask.mStack != task.mStack) { + if (currentTask.mStack != task.mStack) { throw new IllegalArgumentException( - "window token=" + this + " current task=" + mTask + "window token=" + this + " current task=" + currentTask + " belongs to a different stack than " + task); } if (DEBUG_ADD_REMOVE) Slog.i(TAG, "reParentWindowToken: removing window token=" + this - + " from task=" + mTask); + + " from task=" + currentTask); final DisplayContent prevDisplayContent = getDisplayContent(); mReparenting = true; @@ -927,9 +908,11 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree } private boolean canFreezeBounds() { + final Task task = getTask(); + // For freeform windows, we can't freeze the bounds at the moment because this would make // the resizing unresponsive. - return mTask != null && !mTask.inFreeformWorkspace(); + return task != null && !task.inFreeformWorkspace(); } /** @@ -939,16 +922,17 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree * with a queue. */ private void freezeBounds() { - mFrozenBounds.offer(new Rect(mTask.mPreparedFrozenBounds)); + final Task task = getTask(); + mFrozenBounds.offer(new Rect(task.mPreparedFrozenBounds)); - if (mTask.mPreparedFrozenMergedConfig.equals(Configuration.EMPTY)) { + if (task.mPreparedFrozenMergedConfig.equals(Configuration.EMPTY)) { // We didn't call prepareFreezingBounds on the task, so use the current value. - mFrozenMergedConfig.offer(new Configuration(mTask.getConfiguration())); + mFrozenMergedConfig.offer(new Configuration(task.getConfiguration())); } else { - mFrozenMergedConfig.offer(new Configuration(mTask.mPreparedFrozenMergedConfig)); + mFrozenMergedConfig.offer(new Configuration(task.mPreparedFrozenMergedConfig)); } // Calling unset() to make it equal to Configuration.EMPTY. - mTask.mPreparedFrozenMergedConfig.unset(); + task.mPreparedFrozenMergedConfig.unset(); } /** @@ -1473,7 +1457,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree if (appToken != null) { pw.println(prefix + "app=true mVoiceInteraction=" + mVoiceInteraction); } - pw.print(prefix); pw.print("task="); pw.println(mTask); + pw.print(prefix); pw.print("task="); pw.println(getTask()); pw.print(prefix); pw.print(" mFillsParent="); pw.print(mFillsParent); pw.print(" mOrientation="); pw.println(mOrientation); pw.print(prefix); pw.print("hiddenRequested="); pw.print(hiddenRequested); diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 07eb88dc9ad7..99c085ffe19f 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -133,7 +133,6 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU void addChild(AppWindowToken wtoken, int position) { position = getAdjustedAddPosition(position); super.addChild(wtoken, position); - wtoken.setTask(this); mDeferRemoval = false; } @@ -244,8 +243,6 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU removeIfPossible(); } } - - token.setTask(null /*task*/); } void setSendingToBottom(boolean toBottom) { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index eb3a2d15a855..e339329b56d4 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2199,15 +2199,6 @@ public class WindowManagerService extends IWindowManager.Stub if (mAccessibilityController != null && win.getDisplayId() == DEFAULT_DISPLAY) { mAccessibilityController.onWindowTransitionLocked(win, transit); } - - // When we start the exit animation we take the Surface from the client - // so it will stop perturbing it. We need to likewise takeaway the SurfaceFlinger - // side child surfaces, so they will remain preserved in their current state - // (rather than be cleaned up immediately by the app code). - SurfaceControl.openTransaction(); - winAnimator.detachChildren(); - SurfaceControl.closeTransaction(); - return focusMayChange; } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 48060686a1de..6d572d78b9d7 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -1532,13 +1532,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return changed; } - // Next up we will notify the client that it's visibility has changed. - // We need to prevent it from destroying child surfaces until - // the animation has finished. - if (!visible && isVisibleNow()) { - mWinAnimator.detachChildren(); - } - if (visible != isVisibleNow()) { if (!runningAppAnimation) { final AccessibilityController accessibilityController = diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 4b7133836db8..98598e1654dc 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -566,20 +566,6 @@ class WindowStateAnimator { if (!mDestroyPreservedSurfaceUponRedraw) { return; } - if (mSurfaceController != null) { - if (mPendingDestroySurface != null) { - // If we are preserving a surface but we aren't relaunching that means - // we are just doing an in-place switch. In that case any SurfaceFlinger side - // child layers need to be reparented to the new surface to make this - // transparent to the app. - if (mWin.mAppToken == null || mWin.mAppToken.isRelaunching() == false) { - SurfaceControl.openTransaction(); - mPendingDestroySurface.reparentChildrenInTransaction(mSurfaceController); - SurfaceControl.closeTransaction(); - } - } - } - destroyDeferredSurfaceLocked(); mDestroyPreservedSurfaceUponRedraw = false; } @@ -1979,10 +1965,4 @@ class WindowStateAnimator { } return mForceScaleUntilResize; } - - void detachChildren() { - if (mSurfaceController != null) { - mSurfaceController.detachChildren(); - } - } } diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java index f7d3343831bf..f8e74284fafd 100644 --- a/services/core/java/com/android/server/wm/WindowSurfaceController.java +++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java @@ -135,20 +135,6 @@ class WindowSurfaceController { } } - void reparentChildrenInTransaction(WindowSurfaceController other) { - if (SHOW_TRANSACTIONS) Slog.i(TAG, "REPARENT from: " + this + " to: " + other); - if ((mSurfaceControl != null) && (other.mSurfaceControl != null)) { - mSurfaceControl.reparentChildren(other.getHandle()); - } - } - - void detachChildren() { - if (SHOW_TRANSACTIONS) Slog.i(TAG, "SEVER CHILDREN"); - if (mSurfaceControl != null) { - mSurfaceControl.detachChildren(); - } - } - void hideInTransaction(String reason) { if (SHOW_TRANSACTIONS) logSurface("HIDE ( " + reason + " )", null); mHiddenForOtherReasons = true; diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java index 440362d5c1b4..18c48b71270d 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java @@ -158,21 +158,6 @@ class WindowTestsBase { return win; } - /** - * Creates a window for a task on a the given {@param stackId}. - */ - private WindowState createStackWindow(int stackId, String name) { - final StackWindowController stackController = createStackControllerOnStackOnDisplay(stackId, - sDisplayContent); - final TestTaskWindowContainerController taskController = - new TestTaskWindowContainerController(stackController); - TestAppWindowToken appWinToken = new TestAppWindowToken(sDisplayContent); - appWinToken.setTask(taskController.mContainer); - final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, name); - win.mAppToken = appWinToken; - return win; - } - /** Asserts that the first entry is greater than the second entry. */ void assertGreaterThan(int first, int second) throws Exception { Assert.assertTrue("Excepted " + first + " to be greater than " + second, first > second); diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 6d465f713215..932c276de720 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -4041,9 +4041,8 @@ public class TelephonyManager { } } - if (property.length() > SystemProperties.PROP_NAME_MAX - || propVal.length() > SystemProperties.PROP_VALUE_MAX) { - Rlog.d(TAG, "setTelephonyProperty: property to long phoneId=" + phoneId + + if (propVal.length() > SystemProperties.PROP_VALUE_MAX) { + Rlog.d(TAG, "setTelephonyProperty: property too long phoneId=" + phoneId + " property=" + property + " value: " + value + " propVal=" + propVal); return; } diff --git a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java index 620759df8f1d..23888411c1b2 100644 --- a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java +++ b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java @@ -122,12 +122,22 @@ public final class Credential implements Parcelable { private static final int MAX_PASSWORD_BYTES = 255; /** + * Supported authentication methods. + * @hide + */ + public static final String AUTH_METHOD_PAP = "PAP"; + /** @hide */ + public static final String AUTH_METHOD_MSCHAP = "MS-CHAP"; + /** @hide */ + public static final String AUTH_METHOD_MSCHAPV2 = "MS-CHAP-V2"; + + /** * Supported Non-EAP inner methods. Refer to * Credential/UsernamePassword/EAPMethod/InnerEAPType in Hotspot 2.0 Release 2 Technical * Specification Section 9.1 for more info. */ - private static final Set<String> SUPPORTED_AUTH = - new HashSet<String>(Arrays.asList("PAP", "CHAP", "MS-CHAP", "MS-CHAP-V2")); + private static final Set<String> SUPPORTED_AUTH = new HashSet<String>( + Arrays.asList(AUTH_METHOD_PAP, AUTH_METHOD_MSCHAP, AUTH_METHOD_MSCHAPV2)); /** * Username of the credential. @@ -348,8 +358,9 @@ public final class Credential implements Parcelable { public static final class CertificateCredential implements Parcelable { /** * Supported certificate types. + * @hide */ - private static final String CERT_TYPE_X509V3 = "x509v3"; + public static final String CERT_TYPE_X509V3 = "x509v3"; /** * Certificate SHA-256 fingerprint length. |