diff options
64 files changed, 1293 insertions, 313 deletions
diff --git a/Ravenwood.bp b/Ravenwood.bp index 2f6709090093..b497871aee85 100644 --- a/Ravenwood.bp +++ b/Ravenwood.bp @@ -82,6 +82,7 @@ android_ravenwood_libgroup { "junit", "truth", "ravenwood-junit", + "android.test.mock", ], } diff --git a/core/api/current.txt b/core/api/current.txt index 4256d51b09e4..89ed896bc378 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -33179,6 +33179,7 @@ package android.os { method public int getCurrentThermalStatus(); method public int getLocationPowerSaveMode(); method public float getThermalHeadroom(@IntRange(from=0, to=60) int); + method @FlaggedApi("android.os.allow_thermal_headroom_thresholds") @NonNull public java.util.Map<java.lang.Integer,java.lang.Float> getThermalHeadroomThresholds(); method public boolean isAllowedInLowPowerStandby(int); method public boolean isAllowedInLowPowerStandby(@NonNull String); method public boolean isBatteryDischargePredictionPersonalized(); diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java index 0bc459a19e7d..67759f4aa76d 100644 --- a/core/java/android/content/ClipData.java +++ b/core/java/android/content/ClipData.java @@ -163,6 +163,7 @@ import java.util.List; * into an editor), then {@link Item#coerceToText(Context)} will ask the content * provider for the clip URI as text and successfully paste the entire note. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class ClipData implements Parcelable { static final String[] MIMETYPES_TEXT_PLAIN = new String[] { ClipDescription.MIMETYPE_TEXT_PLAIN }; @@ -387,6 +388,7 @@ public class ClipData implements Parcelable { * @return Returns the item's textual representation. */ //BEGIN_INCLUDE(coerceToText) + @android.ravenwood.annotation.RavenwoodThrow public CharSequence coerceToText(Context context) { // If this Item has an explicit textual value, simply return that. CharSequence text = getText(); @@ -470,6 +472,7 @@ public class ClipData implements Parcelable { * and other things can be retrieved. * @return Returns the item's textual representation. */ + @android.ravenwood.annotation.RavenwoodThrow public CharSequence coerceToStyledText(Context context) { CharSequence text = getText(); if (text instanceof Spanned) { @@ -520,6 +523,7 @@ public class ClipData implements Parcelable { * and other things can be retrieved. * @return Returns the item's representation as HTML text. */ + @android.ravenwood.annotation.RavenwoodThrow public String coerceToHtmlText(Context context) { // If the item has an explicit HTML value, simply return that. String htmlText = getHtmlText(); @@ -540,6 +544,7 @@ public class ClipData implements Parcelable { return text != null ? text.toString() : null; } + @android.ravenwood.annotation.RavenwoodThrow private CharSequence coerceToHtmlOrStyledText(Context context, boolean styled) { // If this Item has a URI value, try using that. if (mUri != null) { @@ -1030,6 +1035,7 @@ public class ClipData implements Parcelable { * * @hide */ + @android.ravenwood.annotation.RavenwoodThrow public void prepareToLeaveProcess(boolean leavingPackage) { // Assume that callers are going to be granting permissions prepareToLeaveProcess(leavingPackage, Intent.FLAG_GRANT_READ_URI_PERMISSION); @@ -1040,6 +1046,7 @@ public class ClipData implements Parcelable { * * @hide */ + @android.ravenwood.annotation.RavenwoodThrow public void prepareToLeaveProcess(boolean leavingPackage, int intentFlags) { final int size = mItems.size(); for (int i = 0; i < size; i++) { @@ -1060,6 +1067,7 @@ public class ClipData implements Parcelable { } /** {@hide} */ + @android.ravenwood.annotation.RavenwoodThrow public void prepareToEnterProcess(AttributionSource source) { final int size = mItems.size(); for (int i = 0; i < size; i++) { @@ -1073,6 +1081,7 @@ public class ClipData implements Parcelable { } /** @hide */ + @android.ravenwood.annotation.RavenwoodThrow public void fixUris(int contentUserHint) { final int size = mItems.size(); for (int i = 0; i < size; i++) { @@ -1090,6 +1099,7 @@ public class ClipData implements Parcelable { * Only fixing the data field of the intents * @hide */ + @android.ravenwood.annotation.RavenwoodThrow public void fixUrisLight(int contentUserHint) { final int size = mItems.size(); for (int i = 0; i < size; i++) { diff --git a/core/java/android/content/ClipDescription.java b/core/java/android/content/ClipDescription.java index de2ba44ca393..5953890ad85f 100644 --- a/core/java/android/content/ClipDescription.java +++ b/core/java/android/content/ClipDescription.java @@ -48,6 +48,7 @@ import java.util.Map; * developer guide.</p> * </div> */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class ClipDescription implements Parcelable { /** * The MIME type for a clip holding plain text. diff --git a/core/java/android/content/ComponentName.java b/core/java/android/content/ComponentName.java index f12e971afb1f..a6a6bccbb4b5 100644 --- a/core/java/android/content/ComponentName.java +++ b/core/java/android/content/ComponentName.java @@ -37,6 +37,7 @@ import java.io.PrintWriter; * name inside of that package. * */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class ComponentName implements Parcelable, Cloneable, Comparable<ComponentName> { private final String mPackage; private final String mClass; diff --git a/core/java/android/content/ContentUris.java b/core/java/android/content/ContentUris.java index 767d3f668313..093faff654ec 100644 --- a/core/java/android/content/ContentUris.java +++ b/core/java/android/content/ContentUris.java @@ -70,6 +70,7 @@ import java.util.List; *</dl> * */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class ContentUris { /** diff --git a/core/java/android/content/ContentValues.java b/core/java/android/content/ContentValues.java index 02a5ba13f2aa..bde2f3e9a707 100644 --- a/core/java/android/content/ContentValues.java +++ b/core/java/android/content/ContentValues.java @@ -35,6 +35,7 @@ import java.util.Set; * This class is used to store a set of values that the {@link ContentResolver} * can process. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class ContentValues implements Parcelable { public static final String TAG = "ContentValues"; diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 6b39f266a802..665ba1119550 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -660,6 +660,7 @@ import java.util.TimeZone; * {@link #setFlags} and {@link #addFlags}. See {@link #setFlags} for a list * of all possible flags. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class Intent implements Parcelable, Cloneable { private static final String TAG = "Intent"; @@ -12180,6 +12181,7 @@ public class Intent implements Parcelable, Cloneable { * * @hide */ + @android.ravenwood.annotation.RavenwoodThrow @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public void prepareToLeaveProcess(Context context) { final boolean leavingPackage; @@ -12201,6 +12203,7 @@ public class Intent implements Parcelable, Cloneable { * * @hide */ + @android.ravenwood.annotation.RavenwoodThrow public void prepareToLeaveProcess(boolean leavingPackage) { setAllowFds(false); @@ -12296,6 +12299,7 @@ public class Intent implements Parcelable, Cloneable { /** * @hide */ + @android.ravenwood.annotation.RavenwoodThrow public void prepareToEnterProcess(boolean fromProtectedComponent, AttributionSource source) { if (fromProtectedComponent) { prepareToEnterProcess(LOCAL_FLAG_FROM_PROTECTED_COMPONENT, source); @@ -12307,6 +12311,7 @@ public class Intent implements Parcelable, Cloneable { /** * @hide */ + @android.ravenwood.annotation.RavenwoodThrow public void prepareToEnterProcess(int localFlags, AttributionSource source) { // We just entered destination process, so we should be able to read all // parcelables inside. @@ -12378,6 +12383,7 @@ public class Intent implements Parcelable, Cloneable { /** * @hide */ + @android.ravenwood.annotation.RavenwoodThrow public void fixUris(int contentUserHint) { Uri data = getData(); if (data != null) { @@ -12417,6 +12423,7 @@ public class Intent implements Parcelable, Cloneable { * @return Whether any contents were migrated. * @hide */ + @android.ravenwood.annotation.RavenwoodThrow public boolean migrateExtraStreamToClipData() { return migrateExtraStreamToClipData(AppGlobals.getInitialApplication()); } @@ -12430,6 +12437,7 @@ public class Intent implements Parcelable, Cloneable { * @return Whether any contents were migrated. * @hide */ + @android.ravenwood.annotation.RavenwoodThrow public boolean migrateExtraStreamToClipData(Context context) { // Refuse to touch if extras already parcelled if (mExtras != null && mExtras.isParcelled()) return false; @@ -12545,6 +12553,7 @@ public class Intent implements Parcelable, Cloneable { return false; } + @android.ravenwood.annotation.RavenwoodThrow private Uri maybeConvertFileToContentUri(Context context, Uri uri) { if (ContentResolver.SCHEME_FILE.equals(uri.getScheme()) && context.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.R) { @@ -12598,6 +12607,7 @@ public class Intent implements Parcelable, Cloneable { // TODO(b/299109198): Refactor into the {@link SdkSandboxManagerLocal} /** @hide */ + @android.ravenwood.annotation.RavenwoodThrow public boolean isSandboxActivity(@NonNull Context context) { if (mAction != null && mAction.equals(ACTION_START_SANDBOXED_ACTIVITY)) { return true; diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java index f946754bd9a1..ad3acd713c6b 100644 --- a/core/java/android/content/IntentFilter.java +++ b/core/java/android/content/IntentFilter.java @@ -152,6 +152,7 @@ import java.util.function.Predicate; * that unlike the action, an IntentFilter with no categories * will only match an Intent that does not have any categories. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class IntentFilter implements Parcelable { private static final String TAG = "IntentFilter"; diff --git a/core/java/android/content/TEST_MAPPING b/core/java/android/content/TEST_MAPPING index addede4cc60c..a2cfbf5aa5bd 100644 --- a/core/java/android/content/TEST_MAPPING +++ b/core/java/android/content/TEST_MAPPING @@ -57,5 +57,11 @@ ], "file_patterns": ["(/|^)Context.java", "(/|^)ContextWrapper.java"] } + ], + "ravenwood-presubmit": [ + { + "name": "CtsContentTestCasesRavenwood", + "host": true + } ] -}
\ No newline at end of file +} diff --git a/core/java/android/content/UriMatcher.java b/core/java/android/content/UriMatcher.java index 7fa48f0e9a78..4422ade7ec0a 100644 --- a/core/java/android/content/UriMatcher.java +++ b/core/java/android/content/UriMatcher.java @@ -119,6 +119,7 @@ instead of: } </pre> */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class UriMatcher { public static final int NO_MATCH = -1; diff --git a/core/java/android/credentials/flags.aconfig b/core/java/android/credentials/flags.aconfig index ec96215525d3..bab84aadc73b 100644 --- a/core/java/android/credentials/flags.aconfig +++ b/core/java/android/credentials/flags.aconfig @@ -20,3 +20,10 @@ flag { description: "Enables clearing of Credential Manager sessions when client process dies" bug: "308470501" } + +flag { + namespace: "credential_manager" + name: "new_settings_intents" + description: "Enables settings intents to redirect to new settings page" + bug: "307587989" +}
\ No newline at end of file diff --git a/core/java/android/os/IThermalService.aidl b/core/java/android/os/IThermalService.aidl index c6c8adc4d8a9..bcffa45fbbd2 100644 --- a/core/java/android/os/IThermalService.aidl +++ b/core/java/android/os/IThermalService.aidl @@ -111,4 +111,9 @@ interface IThermalService { * occur; returns NaN if the headroom or forecast is unavailable */ float getThermalHeadroom(int forecastSeconds); + + /** + * @return thermal headroom for each thermal status + */ + float[] getThermalHeadroomThresholds(); } diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index d2c17556bb2f..11bddfb5b0f0 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -20,6 +20,7 @@ import android.annotation.FlaggedApi; import android.Manifest.permission; import android.annotation.CallbackExecutor; import android.annotation.CurrentTimeMillisLong; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; @@ -42,14 +43,17 @@ import android.view.Display; import com.android.internal.util.Preconditions; +import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; import java.net.InetAddress; import java.net.UnknownHostException; import java.time.Duration; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.concurrent.Executor; @@ -1180,6 +1184,8 @@ public final class PowerManager { private final ArrayMap<OnThermalStatusChangedListener, IThermalStatusListener> mListenerMap = new ArrayMap<>(); + private final Object mThermalHeadroomThresholdsLock = new Object(); + private float[] mThermalHeadroomThresholds = null; /** * {@hide} @@ -2636,6 +2642,7 @@ public final class PowerManager { public static final int THERMAL_STATUS_SHUTDOWN = Temperature.THROTTLING_SHUTDOWN; /** @hide */ + @Target(ElementType.TYPE_USE) @IntDef(prefix = { "THERMAL_STATUS_" }, value = { THERMAL_STATUS_NONE, THERMAL_STATUS_LIGHT, @@ -2800,6 +2807,63 @@ public final class PowerManager { } /** + * Gets the thermal headroom thresholds for all available thermal throttling status above + * {@link #THERMAL_STATUS_NONE}. + * <p> + * A thermal status key in the returned map is only set if the device manufacturer has the + * corresponding threshold defined for at least one of its sensors. If it's set, one should + * expect to see that from {@link #getCurrentThermalStatus()} or + * {@link OnThermalStatusChangedListener#onThermalStatusChanged(int)}. + * <p> + * The headroom threshold is used to interpret the possible thermal throttling status based on + * the headroom prediction. For example, if the headroom threshold for + * {@link #THERMAL_STATUS_LIGHT} is 0.7, and a headroom prediction in 10s returns 0.75 + * (or {@code getThermalHeadroom(10)=0.75}), one can expect that in 10 seconds the system could + * be in lightly throttled state if the workload remains the same. The app can consider + * taking actions according to the nearest throttling status the difference between the headroom + * and the threshold. + * <p> + * For new devices it's guaranteed to have a single sensor, but for older devices with multiple + * sensors reporting different threshold values, the minimum threshold is taken to be + * conservative on predictions. Thus, when reading real-time headroom, it's not guaranteed that + * a real-time value of 0.75 (or {@code getThermalHeadroom(0)}=0.75) exceeding the threshold of + * 0.7 above will always come with lightly throttled state + * (or {@code getCurrentThermalStatus()=THERMAL_STATUS_LIGHT}) but it can be lower + * (or {@code getCurrentThermalStatus()=THERMAL_STATUS_NONE}). While it's always guaranteed that + * the device won't be throttled heavier than the unmet threshold's state, so a real-time + * headroom of 0.75 will never come with {@link #THERMAL_STATUS_MODERATE} but lower, and 0.65 + * will never come with {@link #THERMAL_STATUS_LIGHT} but {@link #THERMAL_STATUS_NONE}. + * <p> + * The returned map of thresholds will not change between calls to this function, so it's + * best to call this once on initialization. Modifying the result will not change the thresholds + * cached by the system, and a new call to the API will get a new copy. + * + * @return map from each thermal status to its thermal headroom + * @throws IllegalStateException if the thermal service is not ready + * @throws UnsupportedOperationException if the feature is not enabled + */ + @FlaggedApi(Flags.FLAG_ALLOW_THERMAL_HEADROOM_THRESHOLDS) + public @NonNull Map<@ThermalStatus Integer, Float> getThermalHeadroomThresholds() { + try { + synchronized (mThermalHeadroomThresholdsLock) { + if (mThermalHeadroomThresholds == null) { + mThermalHeadroomThresholds = mThermalService.getThermalHeadroomThresholds(); + } + final ArrayMap<Integer, Float> ret = new ArrayMap<>(THERMAL_STATUS_SHUTDOWN); + for (int status = THERMAL_STATUS_LIGHT; status <= THERMAL_STATUS_SHUTDOWN; + status++) { + if (!Float.isNaN(mThermalHeadroomThresholds[status])) { + ret.put(status, mThermalHeadroomThresholds[status]); + } + } + return ret; + } + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * If true, the doze component is not started until after the screen has been * turned off and the screen off animation has been performed. * @hide diff --git a/core/java/android/os/TEST_MAPPING b/core/java/android/os/TEST_MAPPING index 2d6e09a1b268..b5029a6aaff3 100644 --- a/core/java/android/os/TEST_MAPPING +++ b/core/java/android/os/TEST_MAPPING @@ -153,5 +153,11 @@ "file_patterns": ["Bugreport[^/]*\\.java"], "name": "ShellTests" } + ], + "ravenwood-presubmit": [ + { + "name": "CtsOsTestCasesRavenwood", + "host": true + } ] } diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig index 0809b3bada20..d405d1d0cec6 100644 --- a/core/java/android/os/flags.aconfig +++ b/core/java/android/os/flags.aconfig @@ -29,6 +29,13 @@ flag { } flag { + name: "allow_thermal_headroom_thresholds" + namespace: "game" + description: "Enable thermal headroom thresholds API" + bug: "288119641" +} + +flag { name: "allow_private_profile" namespace: "profile_experiences" description: "Guards a new Private Profile type in UserManager - everything from its setup to config to deletion." diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig index fb2ac7112b0a..dc86e3f57c40 100644 --- a/core/java/android/permission/flags.aconfig +++ b/core/java/android/permission/flags.aconfig @@ -17,6 +17,7 @@ flag { flag { name: "role_controller_in_system_server" + is_fixed_read_only: true namespace: "permissions" description: "enable role controller in system server" bug: "302562590" diff --git a/core/java/android/util/TEST_MAPPING b/core/java/android/util/TEST_MAPPING index 0ae1c1593366..c681f86ce439 100644 --- a/core/java/android/util/TEST_MAPPING +++ b/core/java/android/util/TEST_MAPPING @@ -24,5 +24,11 @@ ], "file_patterns": ["Xml"] } + ], + "ravenwood-presubmit": [ + { + "name": "CtsUtilTestCasesRavenwood", + "host": true + } ] } diff --git a/core/java/android/util/proto/TEST_MAPPING b/core/java/android/util/proto/TEST_MAPPING index 5b9874153de3..126174374896 100644 --- a/core/java/android/util/proto/TEST_MAPPING +++ b/core/java/android/util/proto/TEST_MAPPING @@ -6,5 +6,11 @@ { "name": "CtsProtoTestCases" } + ], + "ravenwood-presubmit": [ + { + "name": "CtsProtoTestCasesRavenwood", + "host": true + } ] } diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java index ec961674db60..fb2b8b9c280c 100644 --- a/core/java/android/view/ViewConfiguration.java +++ b/core/java/android/view/ViewConfiguration.java @@ -88,6 +88,13 @@ public class ViewConfiguration { private static final int DEFAULT_MULTI_PRESS_TIMEOUT = 300; /** + * Defines the default duration in milliseconds between a key being pressed and its first key + * repeat event being generated. Historically, Android used the long press timeout as the + * key repeat timeout, so its default value is set to long press timeout's default. + */ + private static final int DEFAULT_KEY_REPEAT_TIMEOUT_MS = DEFAULT_LONG_PRESS_TIMEOUT; + + /** * Defines the default duration between successive key repeats in milliseconds. */ private static final int DEFAULT_KEY_REPEAT_DELAY_MS = 50; @@ -719,11 +726,8 @@ public class ViewConfiguration { * @return the time before the first key repeat in milliseconds. */ public static int getKeyRepeatTimeout() { - // Before the key repeat timeout was introduced, some users relied on changing - // LONG_PRESS_TIMEOUT settings to also change the key repeat timeout. To support - // this backward compatibility, we'll use the long press timeout as default value. return AppGlobals.getIntCoreSetting(Settings.Secure.KEY_REPEAT_TIMEOUT_MS, - getLongPressTimeout()); + DEFAULT_KEY_REPEAT_TIMEOUT_MS); } /** diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 145af2e7ab67..f98e1dd41b1b 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -81,6 +81,8 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; +import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE; +import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; import static android.view.WindowManager.LayoutParams.TYPE_TOAST; @@ -12029,7 +12031,8 @@ public final class ViewRootImpl implements ViewParent, || motionEventAction == MotionEvent.ACTION_MOVE || motionEventAction == MotionEvent.ACTION_UP; boolean desiredType = windowType == TYPE_BASE_APPLICATION || windowType == TYPE_APPLICATION - || windowType == TYPE_APPLICATION_STARTING || windowType == TYPE_DRAWN_APPLICATION; + || windowType == TYPE_APPLICATION_STARTING || windowType == TYPE_DRAWN_APPLICATION + || windowType == TYPE_NOTIFICATION_SHADE || windowType == TYPE_STATUS_BAR; // use toolkitSetFrameRate flag to gate the change return desiredAction && desiredType && sToolkitSetFrameRateReadOnlyFlagValue; } diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index a3e0016f9174..28fd2b488426 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -1936,7 +1936,8 @@ public class LockPatternUtils { * If the user is not secured, ie doesn't have an LSKF, then decrypt the user's synthetic * password and use it to unlock various cryptographic keys associated with the user. This * primarily includes unlocking the user's credential-encrypted (CE) storage. It also includes - * deriving or decrypting the vendor auth secret and sending it to the AuthSecret HAL. + * unlocking the user's Keystore super keys, and deriving or decrypting the vendor auth secret + * and sending it to the AuthSecret HAL in order to unlock Secure Element firmware updates. * <p> * These tasks would normally be done when the LSKF is verified. This method is where these * tasks are done when the user doesn't have an LSKF. It's called when the user is started. diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp index 8fa179b496b6..f9d00edce3fa 100644 --- a/core/jni/android_media_AudioRecord.cpp +++ b/core/jni/android_media_AudioRecord.cpp @@ -212,14 +212,11 @@ static jint android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject w return (jint) AUDIORECORD_ERROR_SETUP_INVALIDFORMAT; } - size_t bytesPerSample = audio_bytes_per_sample(format); - if (buffSizeInBytes == 0) { ALOGE("Error creating AudioRecord: frameCount is 0."); return (jint) AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT; } - size_t frameSize = channelCount * bytesPerSample; - size_t frameCount = buffSizeInBytes / frameSize; + size_t frameCount = buffSizeInBytes / audio_bytes_per_frame(channelCount, format); // create an uninitialized AudioRecord object Parcel* parcel = parcelForJavaObject(env, jAttributionSource); diff --git a/keystore/java/android/security/AndroidKeyStoreMaintenance.java b/keystore/java/android/security/AndroidKeyStoreMaintenance.java index b7ea04fdfe07..2beb434566e5 100644 --- a/keystore/java/android/security/AndroidKeyStoreMaintenance.java +++ b/keystore/java/android/security/AndroidKeyStoreMaintenance.java @@ -51,7 +51,7 @@ public class AndroidKeyStoreMaintenance { * @return 0 if successful or a {@code ResponseCode} * @hide */ - public static int onUserAdded(@NonNull int userId) { + public static int onUserAdded(int userId) { StrictMode.noteDiskWrite(); try { getService().onUserAdded(userId); @@ -66,6 +66,30 @@ public class AndroidKeyStoreMaintenance { } /** + * Tells Keystore to create a user's super keys and store them encrypted by the given secret. + * + * @param userId - Android user id of the user + * @param password - a secret derived from the user's synthetic password + * @param allowExisting - true if the keys already existing should not be considered an error + * @return 0 if successful or a {@code ResponseCode} + * @hide + */ + public static int initUserSuperKeys(int userId, @NonNull byte[] password, + boolean allowExisting) { + StrictMode.noteDiskWrite(); + try { + getService().initUserSuperKeys(userId, password, allowExisting); + return 0; + } catch (ServiceSpecificException e) { + Log.e(TAG, "initUserSuperKeys failed", e); + return e.errorCode; + } catch (Exception e) { + Log.e(TAG, "Can not connect to keystore", e); + return SYSTEM_ERROR; + } + } + + /** * Informs Keystore 2.0 about removing a user * * @param userId - Android user id of the user being removed @@ -110,6 +134,28 @@ public class AndroidKeyStoreMaintenance { } /** + * Tells Keystore that a user's LSKF is being removed, ie the user's lock screen is changing to + * Swipe or None. Keystore uses this notification to delete the user's auth-bound keys. + * + * @param userId - Android user id of the user + * @return 0 if successful or a {@code ResponseCode} + * @hide + */ + public static int onUserLskfRemoved(int userId) { + StrictMode.noteDiskWrite(); + try { + getService().onUserLskfRemoved(userId); + return 0; + } catch (ServiceSpecificException e) { + Log.e(TAG, "onUserLskfRemoved failed", e); + return e.errorCode; + } catch (Exception e) { + Log.e(TAG, "Can not connect to keystore", e); + return SYSTEM_ERROR; + } + } + + /** * Informs Keystore 2.0 that an app was uninstalled and the corresponding namespace is to * be cleared. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java index fc34772f2fce..63cef9e41f98 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java @@ -107,7 +107,7 @@ public class PipMenuView extends FrameLayout { private static final int POST_INTERACTION_DISMISS_DELAY = 2000; private static final long MENU_SHOW_ON_EXPAND_START_DELAY = 30; - private static final float MENU_BACKGROUND_ALPHA = 0.3f; + private static final float MENU_BACKGROUND_ALPHA = 0.54f; private static final float DISABLED_ACTION_ALPHA = 0.54f; private int mMenuState; diff --git a/libs/WindowManager/Shell/tests/flicker/pip/Android.bp b/libs/WindowManager/Shell/tests/flicker/pip/Android.bp index 4d11dfb37c05..386983ce6aae 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/Android.bp +++ b/libs/WindowManager/Shell/tests/flicker/pip/Android.bp @@ -124,6 +124,10 @@ android_test { ":WMShellFlickerTestsPipCommon-src", ], static_libs: ["WMShellFlickerTestsBase"], + test_suites: [ + "device-tests", + "csuite", + ], } csuite_test { diff --git a/libs/WindowManager/Shell/tests/flicker/pip/csuiteDefaultTemplate.xml b/libs/WindowManager/Shell/tests/flicker/pip/csuiteDefaultTemplate.xml index 6df65391ea61..89ecc29d977b 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/csuiteDefaultTemplate.xml +++ b/libs/WindowManager/Shell/tests/flicker/pip/csuiteDefaultTemplate.xml @@ -71,9 +71,9 @@ <!-- Enable mocking GPS location by the test app --> <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"> <option name="run-command" - value="appops set com.android.wm.shell.flicker.pip.apps android:mock_location allow"/> + value="appops set com.android.shell android:mock_location allow"/> <option name="teardown-command" - value="appops set com.android.wm.shell.flicker.pip.apps android:mock_location deny"/> + value="appops set com.android.shell android:mock_location deny"/> </target_preparer> <!-- Needed for pushing the trace config file --> diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt index bd8b0056a6a3..42191d1c5feb 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt @@ -34,7 +34,7 @@ abstract class AppsEnterPipTransition(flicker: LegacyFlickerTest) : EnterPipTran @FlickerBuilderProvider override fun buildFlicker(): FlickerBuilder { return FlickerBuilder(instrumentation).apply { - withoutScreenRecorder() + instrumentation.uiAutomation.adoptShellPermissionIdentity() setup { flicker.scenario.setIsTablet(tapl.isTablet) } transition() } diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java index 7faa13c80c62..447d3bbddceb 100644 --- a/media/java/android/media/AudioRecord.java +++ b/media/java/android/media/AudioRecord.java @@ -1176,6 +1176,7 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, case AudioFormat.ENCODING_PCM_FLOAT: case AudioFormat.ENCODING_PCM_16BIT: case AudioFormat.ENCODING_PCM_8BIT: + case AudioFormat.ENCODING_E_AC3_JOC: mAudioFormat = audioFormat; break; default: @@ -1188,20 +1189,12 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, // Convenience method for the contructor's audio buffer size check. - // preconditions: - // mChannelCount is valid - // mAudioFormat is AudioFormat.ENCODING_PCM_8BIT, AudioFormat.ENCODING_PCM_16BIT, - // or AudioFormat.ENCODING_PCM_FLOAT // postcondition: // mNativeBufferSizeInBytes is valid (multiple of frame size, positive) private void audioBuffSizeCheck(int audioBufferSize) throws IllegalArgumentException { - // NB: this section is only valid with PCM data. - // To update when supporting compressed formats - int frameSizeInBytes = mChannelCount - * (AudioFormat.getBytesPerSample(mAudioFormat)); - if ((audioBufferSize % frameSizeInBytes != 0) || (audioBufferSize < 1)) { + if ((audioBufferSize % getFormat().getFrameSizeInBytes() != 0) || (audioBufferSize < 1)) { throw new IllegalArgumentException("Invalid audio buffer size " + audioBufferSize - + " (frame size " + frameSizeInBytes + ")"); + + " (frame size " + getFormat().getFrameSizeInBytes() + ")"); } mNativeBufferSizeInBytes = audioBufferSize; diff --git a/native/android/TEST_MAPPING b/native/android/TEST_MAPPING index fd394fc43477..7c710982e4f6 100644 --- a/native/android/TEST_MAPPING +++ b/native/android/TEST_MAPPING @@ -22,5 +22,15 @@ ], "file_patterns": ["performance_hint.cpp"] } + ], + "postsubmit": [ + { + "name": "CtsThermalTestCases", + "file_patterns": ["thermal.cpp"] + }, + { + "name": "NativeThermalUnitTestCases", + "file_patterns": ["thermal.cpp"] + } ] } diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt index f4be33c7e6ea..9f2a9ac4798d 100644 --- a/native/android/libandroid.map.txt +++ b/native/android/libandroid.map.txt @@ -327,6 +327,7 @@ LIBANDROID { AThermal_registerThermalStatusListener; # introduced=30 AThermal_unregisterThermalStatusListener; # introduced=30 AThermal_getThermalHeadroom; # introduced=31 + AThermal_getThermalHeadroomThresholds; # introduced=VanillaIceCream APerformanceHint_getManager; # introduced=Tiramisu APerformanceHint_createSession; # introduced=Tiramisu APerformanceHint_getPreferredUpdateRateNanos; # introduced=Tiramisu @@ -348,6 +349,7 @@ LIBANDROID { LIBANDROID_PLATFORM { global: + AThermal_setIThermalServiceForTesting; APerformanceHint_setIHintManagerForTesting; APerformanceHint_sendHint; APerformanceHint_getThreadIds; diff --git a/native/android/tests/thermal/Android.bp b/native/android/tests/thermal/Android.bp new file mode 100644 index 000000000000..8540d8327ada --- /dev/null +++ b/native/android/tests/thermal/Android.bp @@ -0,0 +1,65 @@ +// Copyright (C) 2021 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 { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +cc_test { + name: "NativeThermalUnitTestCases", + + multilib: { + lib32: { + suffix: "32", + }, + lib64: { + suffix: "64", + }, + }, + + srcs: ["NativeThermalUnitTest.cpp"], + + shared_libs: [ + "libandroid", + "liblog", + "libbinder", + "libpowermanager", + "libutils", + ], + + static_libs: [ + "libbase", + "libgmock", + "libgtest", + ], + stl: "c++_shared", + + test_suites: [ + "device-tests", + ], + + cflags: [ + "-Werror", + "-Wall", + ], + + header_libs: [ + "libandroid_headers_private", + ], +} diff --git a/native/android/tests/thermal/NativeThermalUnitTest.cpp b/native/android/tests/thermal/NativeThermalUnitTest.cpp new file mode 100644 index 000000000000..6d6861a3026a --- /dev/null +++ b/native/android/tests/thermal/NativeThermalUnitTest.cpp @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2023 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. + */ + +#define LOG_TAG "NativeThermalUnitTest" + +#include <android/os/IThermalService.h> +#include <android/thermal.h> +#include <binder/IBinder.h> +#include <gmock/gmock.h> +#include <gtest/gtest.h> +#include <thermal_private.h> + +using android::binder::Status; + +using namespace testing; +using namespace android; +using namespace android::os; + +class MockIThermalService : public IThermalService { +public: + MOCK_METHOD(Status, registerThermalEventListener, + (const ::android::sp<::android::os::IThermalEventListener>& listener, + bool* _aidl_return), + (override)); + MOCK_METHOD(Status, registerThermalEventListenerWithType, + (const ::android::sp<::android::os::IThermalEventListener>& listener, int32_t type, + bool* _aidl_return), + (override)); + MOCK_METHOD(Status, unregisterThermalEventListener, + (const ::android::sp<::android::os::IThermalEventListener>& listener, + bool* _aidl_return), + (override)); + MOCK_METHOD(Status, getCurrentTemperatures, + (::std::vector<::android::os::Temperature> * _aidl_return), (override)); + MOCK_METHOD(Status, getCurrentTemperaturesWithType, + (int32_t type, ::std::vector<::android::os::Temperature>* _aidl_return), + (override)); + MOCK_METHOD(Status, registerThermalStatusListener, + (const ::android::sp<::android::os::IThermalStatusListener>& listener, + bool* _aidl_return), + (override)); + MOCK_METHOD(Status, unregisterThermalStatusListener, + (const ::android::sp<::android::os::IThermalStatusListener>& listener, + bool* _aidl_return), + (override)); + MOCK_METHOD(Status, getCurrentThermalStatus, (int32_t * _aidl_return), (override)); + MOCK_METHOD(Status, getCurrentCoolingDevices, + (::std::vector<::android::os::CoolingDevice> * _aidl_return), (override)); + MOCK_METHOD(Status, getCurrentCoolingDevicesWithType, + (int32_t type, ::std::vector<::android::os::CoolingDevice>* _aidl_return), + (override)); + MOCK_METHOD(Status, getThermalHeadroom, (int32_t forecastSeconds, float* _aidl_return), + (override)); + MOCK_METHOD(Status, getThermalHeadroomThresholds, (::std::vector<float> * _aidl_return), + (override)); + MOCK_METHOD(IBinder*, onAsBinder, (), (override)); +}; + +class NativeThermalUnitTest : public Test { +public: + void SetUp() override { + mMockIThermalService = new StrictMock<MockIThermalService>(); + AThermal_setIThermalServiceForTesting(mMockIThermalService); + mThermalManager = AThermal_acquireManager(); + } + + void TearDown() override { + AThermal_setIThermalServiceForTesting(nullptr); + AThermal_releaseManager(mThermalManager); + } + + StrictMock<MockIThermalService>* mMockIThermalService = nullptr; + AThermalManager* mThermalManager = nullptr; +}; + +static void checkThermalHeadroomThresholds(const std::vector<float>& expected, + const AThermalHeadroomThreshold* thresholds, + size_t size) { + if (thresholds == nullptr) { + FAIL() << "Unexpected null thresholds pointer"; + } + for (int i = 0; i < (int)size; i++) { + auto t = thresholds[i]; + ASSERT_EQ(i, t.thermalStatus) << "threshold " << i << " should have status " << i; + ASSERT_EQ(expected[i], t.headroom) + << "threshold " << i << " should have headroom " << expected[i]; + } +} + +TEST_F(NativeThermalUnitTest, TestGetThermalHeadroomThresholds) { + std::vector<float> expected = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + EXPECT_CALL(*mMockIThermalService, getThermalHeadroomThresholds(_)) + .Times(Exactly(1)) + .WillRepeatedly(DoAll(SetArgPointee<0>(expected), Return(Status()))); + const AThermalHeadroomThreshold* thresholds1 = nullptr; + size_t size1; + ASSERT_EQ(OK, AThermal_getThermalHeadroomThresholds(mThermalManager, &thresholds1, &size1)); + checkThermalHeadroomThresholds(expected, thresholds1, size1); + // following calls should be cached + EXPECT_CALL(*mMockIThermalService, getThermalHeadroomThresholds(_)).Times(0); + + const AThermalHeadroomThreshold* thresholds2 = nullptr; + size_t size2; + ASSERT_EQ(OK, AThermal_getThermalHeadroomThresholds(mThermalManager, &thresholds2, &size2)); + checkThermalHeadroomThresholds(expected, thresholds2, size2); +} + +TEST_F(NativeThermalUnitTest, TestGetThermalHeadroomThresholdsFailedWithServerError) { + const AThermalHeadroomThreshold* thresholds = nullptr; + size_t size; + EXPECT_CALL(*mMockIThermalService, getThermalHeadroomThresholds(_)) + .Times(Exactly(1)) + .WillOnce(Return( + Status::fromExceptionCode(binder::Status::Exception::EX_ILLEGAL_ARGUMENT))); + ASSERT_EQ(EPIPE, AThermal_getThermalHeadroomThresholds(mThermalManager, &thresholds, &size)); + ASSERT_EQ(nullptr, thresholds); +} + +TEST_F(NativeThermalUnitTest, TestGetThermalHeadroomThresholdsFailedWithFeatureDisabled) { + const AThermalHeadroomThreshold* thresholds = nullptr; + size_t size; + EXPECT_CALL(*mMockIThermalService, getThermalHeadroomThresholds(_)) + .Times(Exactly(1)) + .WillOnce(Return(Status::fromExceptionCode( + binder::Status::Exception::EX_UNSUPPORTED_OPERATION))); + ASSERT_EQ(ENOSYS, AThermal_getThermalHeadroomThresholds(mThermalManager, &thresholds, &size)); + ASSERT_EQ(nullptr, thresholds); +} + +TEST_F(NativeThermalUnitTest, TestGetThermalHeadroomThresholdsFailedWithNullPtr) { + const AThermalHeadroomThreshold* thresholds = nullptr; + size_t size; + size_t* nullSize = nullptr; + ASSERT_EQ(EINVAL, + AThermal_getThermalHeadroomThresholds(mThermalManager, &thresholds, nullSize)); + ASSERT_EQ(nullptr, thresholds); + ASSERT_EQ(EINVAL, AThermal_getThermalHeadroomThresholds(mThermalManager, nullptr, &size)); +} + +TEST_F(NativeThermalUnitTest, TestGetThermalHeadroomThresholdsFailedWithNonEmptyPtr) { + const AThermalHeadroomThreshold* initialized = new AThermalHeadroomThreshold[1]; + size_t size; + ASSERT_EQ(EINVAL, AThermal_getThermalHeadroomThresholds(mThermalManager, &initialized, &size)); + delete[] initialized; +} diff --git a/native/android/tests/thermal/OWNERS b/native/android/tests/thermal/OWNERS new file mode 100644 index 000000000000..e3bbee92057d --- /dev/null +++ b/native/android/tests/thermal/OWNERS @@ -0,0 +1 @@ +include /ADPF_OWNERS diff --git a/native/android/thermal.cpp b/native/android/thermal.cpp index 1f6ef4755aff..b43f2f16a7cb 100644 --- a/native/android/thermal.cpp +++ b/native/android/thermal.cpp @@ -16,27 +16,32 @@ #define LOG_TAG "thermal" -#include <cerrno> -#include <thread> -#include <limits> - -#include <android/thermal.h> +#include <android-base/thread_annotations.h> #include <android/os/BnThermalStatusListener.h> #include <android/os/IThermalService.h> +#include <android/thermal.h> #include <binder/IServiceManager.h> +#include <thermal_private.h> #include <utils/Log.h> +#include <cerrno> +#include <limits> +#include <thread> + using android::sp; using namespace android; using namespace android::os; struct ThermalServiceListener : public BnThermalStatusListener { - public: - virtual binder::Status onStatusChange(int32_t status) override; - ThermalServiceListener(AThermalManager *manager) {mMgr = manager;} - private: - AThermalManager *mMgr; +public: + virtual binder::Status onStatusChange(int32_t status) override; + ThermalServiceListener(AThermalManager *manager) { + mMgr = manager; + } + +private: + AThermalManager *mMgr; }; struct ListenerCallback { @@ -44,22 +49,29 @@ struct ListenerCallback { void* data; }; +static IThermalService *gIThermalServiceForTesting = nullptr; + struct AThermalManager { - public: - static AThermalManager* createAThermalManager(); - AThermalManager() = delete; - ~AThermalManager(); - status_t notifyStateChange(int32_t status); - status_t getCurrentThermalStatus(int32_t *status); - status_t addListener(AThermal_StatusCallback, void *data); - status_t removeListener(AThermal_StatusCallback, void *data); - status_t getThermalHeadroom(int32_t forecastSeconds, float *result); - private: - AThermalManager(sp<IThermalService> service); - sp<IThermalService> mThermalSvc; - sp<ThermalServiceListener> mServiceListener; - std::vector<ListenerCallback> mListeners; - std::mutex mMutex; +public: + static AThermalManager *createAThermalManager(); + AThermalManager() = delete; + ~AThermalManager(); + status_t notifyStateChange(int32_t status); + status_t getCurrentThermalStatus(int32_t *status); + status_t addListener(AThermal_StatusCallback, void *data); + status_t removeListener(AThermal_StatusCallback, void *data); + status_t getThermalHeadroom(int32_t forecastSeconds, float *result); + status_t getThermalHeadroomThresholds(const AThermalHeadroomThreshold **, size_t *size); + +private: + AThermalManager(sp<IThermalService> service); + sp<IThermalService> mThermalSvc; + std::mutex mListenerMutex; + sp<ThermalServiceListener> mServiceListener GUARDED_BY(mListenerMutex); + std::vector<ListenerCallback> mListeners GUARDED_BY(mListenerMutex); + std::mutex mThresholdsMutex; + const AThermalHeadroomThreshold *mThresholds = nullptr; // GUARDED_BY(mThresholdsMutex) + size_t mThresholdsCount GUARDED_BY(mThresholdsMutex); }; binder::Status ThermalServiceListener::onStatusChange(int32_t status) { @@ -70,6 +82,9 @@ binder::Status ThermalServiceListener::onStatusChange(int32_t status) { } AThermalManager* AThermalManager::createAThermalManager() { + if (gIThermalServiceForTesting) { + return new AThermalManager(gIThermalServiceForTesting); + } sp<IBinder> binder = defaultServiceManager()->checkService(String16("thermalservice")); @@ -81,12 +96,10 @@ AThermalManager* AThermalManager::createAThermalManager() { } AThermalManager::AThermalManager(sp<IThermalService> service) - : mThermalSvc(service), - mServiceListener(nullptr) { -} + : mThermalSvc(std::move(service)), mServiceListener(nullptr) {} AThermalManager::~AThermalManager() { - std::unique_lock<std::mutex> lock(mMutex); + std::unique_lock<std::mutex> listenerLock(mListenerMutex); mListeners.clear(); if (mServiceListener != nullptr) { @@ -94,10 +107,13 @@ AThermalManager::~AThermalManager() { mThermalSvc->unregisterThermalStatusListener(mServiceListener, &success); mServiceListener = nullptr; } + listenerLock.unlock(); + std::unique_lock<std::mutex> lock(mThresholdsMutex); + delete[] mThresholds; } status_t AThermalManager::notifyStateChange(int32_t status) { - std::unique_lock<std::mutex> lock(mMutex); + std::unique_lock<std::mutex> lock(mListenerMutex); AThermalStatus thermalStatus = static_cast<AThermalStatus>(status); for (auto listener : mListeners) { @@ -107,7 +123,7 @@ status_t AThermalManager::notifyStateChange(int32_t status) { } status_t AThermalManager::addListener(AThermal_StatusCallback callback, void *data) { - std::unique_lock<std::mutex> lock(mMutex); + std::unique_lock<std::mutex> lock(mListenerMutex); if (callback == nullptr) { // Callback can not be nullptr @@ -141,7 +157,7 @@ status_t AThermalManager::addListener(AThermal_StatusCallback callback, void *da } status_t AThermalManager::removeListener(AThermal_StatusCallback callback, void *data) { - std::unique_lock<std::mutex> lock(mMutex); + std::unique_lock<std::mutex> lock(mListenerMutex); auto it = std::remove_if(mListeners.begin(), mListeners.end(), @@ -198,6 +214,32 @@ status_t AThermalManager::getThermalHeadroom(int32_t forecastSeconds, float *res return OK; } +status_t AThermalManager::getThermalHeadroomThresholds(const AThermalHeadroomThreshold **result, + size_t *size) { + std::unique_lock<std::mutex> lock(mThresholdsMutex); + if (mThresholds == nullptr) { + auto thresholds = std::make_unique<std::vector<float>>(); + binder::Status ret = mThermalSvc->getThermalHeadroomThresholds(thresholds.get()); + if (!ret.isOk()) { + if (ret.exceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION) { + // feature is not enabled + return ENOSYS; + } + return EPIPE; + } + mThresholdsCount = thresholds->size(); + auto t = new AThermalHeadroomThreshold[mThresholdsCount]; + for (int i = 0; i < (int)mThresholdsCount; i++) { + t[i].headroom = (*thresholds)[i]; + t[i].thermalStatus = static_cast<AThermalStatus>(i); + } + mThresholds = t; + } + *size = mThresholdsCount; + *result = mThresholds; + return OK; +} + /** * Acquire an instance of the thermal manager. This must be freed using * {@link AThermal_releaseManager}. @@ -291,14 +333,24 @@ int AThermal_unregisterThermalStatusListener(AThermalManager *manager, * threshold. Returns NaN if the device does not support this functionality or if * this function is called significantly faster than once per second. */ -float AThermal_getThermalHeadroom(AThermalManager *manager, - int forecastSeconds) { +float AThermal_getThermalHeadroom(AThermalManager *manager, int forecastSeconds) { float result = 0.0f; status_t ret = manager->getThermalHeadroom(forecastSeconds, &result); - if (ret != OK) { result = std::numeric_limits<float>::quiet_NaN(); } - return result; } + +int AThermal_getThermalHeadroomThresholds(AThermalManager *manager, + const AThermalHeadroomThreshold **outThresholds, + size_t *size) { + if (outThresholds == nullptr || *outThresholds != nullptr || size == nullptr) { + return EINVAL; + } + return manager->getThermalHeadroomThresholds(outThresholds, size); +} + +void AThermal_setIThermalServiceForTesting(void *iThermalService) { + gIThermalServiceForTesting = static_cast<IThermalService *>(iThermalService); +} diff --git a/packages/SystemUI/src/com/android/keyguard/logging/ScrimLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/ScrimLogger.kt new file mode 100644 index 000000000000..a068769cb515 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/logging/ScrimLogger.kt @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.keyguard.logging + +import com.android.systemui.log.LogBuffer +import com.android.systemui.log.core.LogLevel +import com.android.systemui.log.dagger.ScrimLog +import com.google.errorprone.annotations.CompileTimeConstant +import javax.inject.Inject + +/** + * A logger to log scrim state. + * + * To enable logcat echoing for this buffer use this command: + * ``` + * $ adb shell cmd statusbar echo -b ScrimLog:VERBOSE + * ``` + */ +class ScrimLogger +@Inject +constructor( + @ScrimLog val buffer: LogBuffer, +) { + companion object { + val TAG = ScrimLogger::class.simpleName!! + } + + fun d( + tag: String, + @CompileTimeConstant msg: String, + arg: Any, + ) = log("$tag::$TAG", LogLevel.DEBUG, msg, arg) + + fun log( + tag: String, + level: LogLevel, + @CompileTimeConstant msg: String, + arg: Any, + ) = + buffer.log( + tag, + level, + { + str1 = msg + str2 = arg.toString() + }, + { "$str1: $str2" } + ) +} diff --git a/packages/SystemUI/src/com/android/systemui/flags/ConditionalRestarter.kt b/packages/SystemUI/src/com/android/systemui/flags/ConditionalRestarter.kt index dd5860484a55..906896fb920e 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/ConditionalRestarter.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/ConditionalRestarter.kt @@ -17,9 +17,9 @@ package com.android.systemui.flags import android.util.Log +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.flags.ConditionalRestarter.Condition -import com.android.systemui.util.kotlin.UnflaggedApplication -import com.android.systemui.util.kotlin.UnflaggedBackground import java.util.concurrent.TimeUnit import javax.inject.Inject import javax.inject.Named @@ -39,8 +39,8 @@ constructor( private val systemExitRestarter: SystemExitRestarter, private val conditions: Set<@JvmSuppressWildcards Condition>, @Named(RESTART_DELAY) private val restartDelaySec: Long, - @UnflaggedApplication private val applicationScope: CoroutineScope, - @UnflaggedBackground private val backgroundDispatcher: CoroutineContext, + @Application private val applicationScope: CoroutineScope, + @Background private val backgroundDispatcher: CoroutineContext, ) : Restarter { private var pendingReason = "" diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt index b2c413645737..093319f6434e 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt @@ -604,10 +604,6 @@ object Flags { val WARN_ON_BLOCKING_BINDER_TRANSACTIONS = unreleasedFlag("warn_on_blocking_binder_transactions") - @JvmField - val COROUTINE_TRACING = - unreleasedFlag("coroutine_tracing") - // TODO(b/283071711): Tracking bug @JvmField val TRIM_RESOURCES_WITH_BACKGROUND_TRIM_AT_LOCK = diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepository.kt index 54031dcc9525..cb0f18630324 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepository.kt @@ -22,6 +22,7 @@ import android.content.Context import android.graphics.Point import androidx.core.animation.Animator import androidx.core.animation.ValueAnimator +import com.android.keyguard.logging.ScrimLogger import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.shared.model.BiometricUnlockModel import com.android.systemui.keyguard.shared.model.BiometricUnlockSource @@ -33,6 +34,8 @@ import com.android.systemui.statusbar.CircleReveal import com.android.systemui.statusbar.LiftReveal import com.android.systemui.statusbar.LightRevealEffect import com.android.systemui.statusbar.PowerButtonReveal +import javax.inject.Inject +import kotlin.math.max import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow @@ -42,8 +45,6 @@ import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map -import javax.inject.Inject -import kotlin.math.max val DEFAULT_REVEAL_EFFECT = LiftReveal @@ -72,8 +73,13 @@ constructor( keyguardRepository: KeyguardRepository, val context: Context, powerInteractor: PowerInteractor, + private val scrimLogger: ScrimLogger, ) : LightRevealScrimRepository { + companion object { + val TAG = LightRevealScrimRepository::class.simpleName!! + } + /** The reveal effect used if the device was locked/unlocked via the power button. */ private val powerButtonRevealEffect: Flow<LightRevealEffect?> = flowOf( @@ -120,25 +126,25 @@ constructor( /** The reveal effect we'll use for the next non-biometric unlock (tap, power button, etc). */ private val nonBiometricRevealEffect: Flow<LightRevealEffect?> = - powerInteractor - .detailedWakefulness - .flatMapLatest { wakefulnessModel -> - when { - wakefulnessModel.isAwakeOrAsleepFrom(WakeSleepReason.POWER_BUTTON) -> - powerButtonRevealEffect - wakefulnessModel.isAwakeFrom(TAP) -> - tapRevealEffect - else -> - flowOf(LiftReveal) - } - } + powerInteractor.detailedWakefulness.flatMapLatest { wakefulnessModel -> + when { + wakefulnessModel.isAwakeOrAsleepFrom(WakeSleepReason.POWER_BUTTON) -> + powerButtonRevealEffect + wakefulnessModel.isAwakeFrom(TAP) -> tapRevealEffect + else -> flowOf(LiftReveal) + } + } private val revealAmountAnimator = ValueAnimator.ofFloat(0f, 1f).apply { duration = 500 } override val revealAmount: Flow<Float> = callbackFlow { val updateListener = Animator.AnimatorUpdateListener { - trySend((it as ValueAnimator).animatedValue as Float) + val value = (it as ValueAnimator).animatedValue + trySend(value as Float) + if (value <= 0.0f || value >= 1.0f) { + scrimLogger.d(TAG, "revealAmount", value) + } } revealAmountAnimator.addUpdateListener(updateListener) awaitClose { revealAmountAnimator.removeUpdateListener(updateListener) } @@ -146,6 +152,7 @@ constructor( override fun startRevealAmountAnimator(reveal: Boolean) { if (reveal) revealAmountAnimator.start() else revealAmountAnimator.reverse() + scrimLogger.d(TAG, "startRevealAmountAnimator, reveal", reveal) } override val revealEffect = @@ -156,13 +163,21 @@ constructor( ) { biometricUnlockState, biometricReveal, nonBiometricReveal -> // Use the biometric reveal for any flavor of wake and unlocking. - when (biometricUnlockState) { - BiometricUnlockModel.WAKE_AND_UNLOCK, - BiometricUnlockModel.WAKE_AND_UNLOCK_PULSING, - BiometricUnlockModel.WAKE_AND_UNLOCK_FROM_DREAM -> biometricReveal - else -> nonBiometricReveal - } - ?: DEFAULT_REVEAL_EFFECT + val revealEffect = + when (biometricUnlockState) { + BiometricUnlockModel.WAKE_AND_UNLOCK, + BiometricUnlockModel.WAKE_AND_UNLOCK_PULSING, + BiometricUnlockModel.WAKE_AND_UNLOCK_FROM_DREAM -> biometricReveal + else -> nonBiometricReveal + } + ?: DEFAULT_REVEAL_EFFECT + + scrimLogger.d( + TAG, + "revealEffect", + "$revealEffect, biometricUnlockState: ${biometricUnlockState.name}" + ) + return@combine revealEffect } .distinctUntilChanged() @@ -173,8 +188,7 @@ constructor( x, y, startRadius = 0, - endRadius = - max(max(x, display.width - x), max(y, display.height - y)), + endRadius = max(max(x, display.width - x), max(y, display.height - y)), ) } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt index 6115d90430b3..2d43897c2565 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt @@ -16,6 +16,7 @@ package com.android.systemui.keyguard.domain.interactor +import com.android.keyguard.logging.ScrimLogger import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.keyguard.data.repository.LightRevealScrimRepository @@ -37,6 +38,7 @@ constructor( private val transitionInteractor: KeyguardTransitionInteractor, private val lightRevealScrimRepository: LightRevealScrimRepository, @Application private val scope: CoroutineScope, + private val scrimLogger: ScrimLogger, ) { init { @@ -46,6 +48,7 @@ constructor( private fun listenForStartedKeyguardTransitionStep() { scope.launch { transitionInteractor.startedKeyguardTransitionStep.collect { + scrimLogger.d(TAG, "listenForStartedKeyguardTransitionStep", it) if (willTransitionChangeEndState(it)) { lightRevealScrimRepository.startRevealAmountAnimator( willBeRevealedInState(it.to) @@ -100,5 +103,7 @@ constructor( KeyguardState.OCCLUDED -> true } } + + val TAG = LightRevealScrimInteractor::class.simpleName!! } } diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java index 17ff1b1ae888..0d81940cacbd 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java @@ -517,6 +517,16 @@ public class LogModule { } /** + * Provides a {@link LogBuffer} for Scrims like LightRevealScrim. + */ + @Provides + @SysUISingleton + @ScrimLog + public static LogBuffer provideScrimLogBuffer(LogBufferFactory factory) { + return factory.create("ScrimLog", 100); + } + + /** * Provides a {@link LogBuffer} for dream-related logs. */ @Provides diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/ScrimLog.kt b/packages/SystemUI/src/com/android/systemui/log/dagger/ScrimLog.kt new file mode 100644 index 000000000000..e78a162e723f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/ScrimLog.kt @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.log.dagger + +import javax.inject.Qualifier + +/** A [com.android.systemui.log.LogBuffer] for Scrims like LightRevealScrim */ +@Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class ScrimLog diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt index 37073a6b5a50..374e8717f819 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt @@ -22,6 +22,7 @@ import android.os.Handler import android.view.LayoutInflater import android.view.ViewStub import androidx.constraintlayout.motion.widget.MotionLayout +import com.android.keyguard.logging.ScrimLogger import com.android.systemui.battery.BatteryMeterView import com.android.systemui.battery.BatteryMeterViewController import com.android.systemui.biometrics.AuthRippleView @@ -140,8 +141,14 @@ abstract class ShadeViewProviderModule { @SysUISingleton fun providesLightRevealScrim( notificationShadeWindowView: NotificationShadeWindowView, + scrimLogger: ScrimLogger, ): LightRevealScrim { - return notificationShadeWindowView.requireViewById(R.id.light_reveal_scrim) + val scrim = + notificationShadeWindowView.requireViewById<LightRevealScrim>( + R.id.light_reveal_scrim + ) + scrim.scrimLogger = scrimLogger + return scrim } @Provides diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt index 3120128c7967..39b7930ed386 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt @@ -18,6 +18,7 @@ import android.view.MotionEvent import android.view.View import android.view.animation.PathInterpolator import com.android.app.animation.Interpolators +import com.android.keyguard.logging.ScrimLogger import com.android.systemui.shade.TouchLogger import com.android.systemui.statusbar.LightRevealEffect.Companion.getPercentPastThreshold import com.android.systemui.util.getColorWithAlpha @@ -89,7 +90,7 @@ object LiftReveal : LightRevealEffect { } } -class LinearLightRevealEffect(private val isVertical: Boolean) : LightRevealEffect { +data class LinearLightRevealEffect(private val isVertical: Boolean) : LightRevealEffect { // Interpolator that reveals >80% of the content at 0.5 progress, makes revealing faster private val interpolator = @@ -155,7 +156,7 @@ class LinearLightRevealEffect(private val isVertical: Boolean) : LightRevealEffe } } -class CircleReveal( +data class CircleReveal( /** X-value of the circle center of the reveal. */ val centerX: Int, /** Y-value of the circle center of the reveal. */ @@ -181,7 +182,7 @@ class CircleReveal( } } -class PowerButtonReveal( +data class PowerButtonReveal( /** Approximate Y-value of the center of the power button on the physical device. */ val powerButtonY: Float ) : LightRevealEffect { @@ -253,7 +254,9 @@ constructor( ) : View(context, attrs) { /** Listener that is called if the scrim's opaqueness changes */ - lateinit var isScrimOpaqueChangedListener: Consumer<Boolean> + var isScrimOpaqueChangedListener: Consumer<Boolean>? = null + + var scrimLogger: ScrimLogger? = null /** * How much of the underlying views are revealed, in percent. 0 means they will be completely @@ -263,7 +266,9 @@ constructor( set(value) { if (field != value) { field = value - + if (value <= 0.0f || value >= 1.0f) { + scrimLogger?.d(TAG, "revealAmount", "$value on ${logString()}") + } revealEffect.setRevealAmountOnScrim(value, this) updateScrimOpaque() Trace.traceCounter( @@ -285,6 +290,7 @@ constructor( field = value revealEffect.setRevealAmountOnScrim(revealAmount, this) + scrimLogger?.d(TAG, "revealEffect", "$value on ${logString()}") invalidate() } } @@ -301,6 +307,7 @@ constructor( */ internal var viewWidth: Int = initialWidth ?: 0 private set + internal var viewHeight: Int = initialHeight ?: 0 private set @@ -342,7 +349,8 @@ constructor( private set(value) { if (field != value) { field = value - isScrimOpaqueChangedListener.accept(field) + isScrimOpaqueChangedListener?.accept(field) + scrimLogger?.d(TAG, "isScrimOpaque", "$value on ${logString()}") } } @@ -360,11 +368,13 @@ constructor( override fun setAlpha(alpha: Float) { super.setAlpha(alpha) + scrimLogger?.d(TAG, "alpha", "$alpha on ${logString()}") updateScrimOpaque() } override fun setVisibility(visibility: Int) { super.setVisibility(visibility) + scrimLogger?.d(TAG, "visibility", "$visibility on ${logString()}") updateScrimOpaque() } @@ -424,11 +434,7 @@ constructor( } override fun onDraw(canvas: Canvas) { - if ( - revealGradientWidth <= 0 || - revealGradientHeight <= 0 || - revealAmount == 0f - ) { + if (revealGradientWidth <= 0 || revealGradientHeight <= 0 || revealAmount == 0f) { if (revealAmount < 1f) { canvas.drawColor(revealGradientEndColor) } @@ -461,4 +467,8 @@ constructor( PorterDuff.Mode.MULTIPLY ) } + + private fun logString(): String { + return this::class.simpleName!! + "@" + hashCode() + } } diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt index 2afb43515be7..36a1e8a072c9 100644 --- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt +++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt @@ -49,6 +49,7 @@ import com.android.systemui.unfold.updates.RotationChangeProvider import com.android.systemui.unfold.util.ScaleAwareTransitionProgressProvider.Companion.areAnimationsEnabled import com.android.systemui.util.concurrency.ThreadFactory import com.android.app.tracing.traceSection +import com.android.keyguard.logging.ScrimLogger import com.android.wm.shell.displayareahelper.DisplayAreaHelper import java.util.Optional import java.util.concurrent.Executor @@ -69,7 +70,8 @@ constructor( @Main private val executor: Executor, private val threadFactory: ThreadFactory, private val rotationChangeProvider: RotationChangeProvider, - private val displayTracker: DisplayTracker + private val displayTracker: DisplayTracker, + private val scrimLogger: ScrimLogger, ) { private val transitionListener = TransitionListener() @@ -179,8 +181,8 @@ constructor( ) .apply { revealEffect = createLightRevealEffect() - isScrimOpaqueChangedListener = Consumer {} revealAmount = calculateRevealAmount() + scrimLogger = this@UnfoldLightRevealOverlayAnimation.scrimLogger } newRoot.setView(newView, params) diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/CoroutinesModule.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/CoroutinesModule.kt index 81737c79905e..cc9335edfc14 100644 --- a/packages/SystemUI/src/com/android/systemui/util/kotlin/CoroutinesModule.kt +++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/CoroutinesModule.kt @@ -5,8 +5,7 @@ import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.dagger.qualifiers.Tracing -import com.android.systemui.flags.FeatureFlagsClassic -import com.android.systemui.flags.Flags +import com.android.systemui.Flags.coroutineTracing import com.android.app.tracing.TraceUtils.Companion.coroutineTracingIsEnabled import com.android.app.tracing.TraceContextElement import dagger.Module @@ -15,32 +14,9 @@ import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi -import javax.inject.Qualifier import kotlin.coroutines.CoroutineContext import kotlin.coroutines.EmptyCoroutineContext -/** Key associated with a [Boolean] flag that enables or disables the coroutine tracing feature. */ -@Qualifier -annotation class CoroutineTracingEnabledKey - -/** - * Same as [@Application], but does not make use of flags. This should only be used when early usage - * of [@Application] would introduce a circular dependency on [FeatureFlagsClassic]. - */ -@Qualifier -@MustBeDocumented -@Retention(AnnotationRetention.RUNTIME) -annotation class UnflaggedApplication - -/** - * Same as [@Background], but does not make use of flags. This should only be used when early usage - * of [@Application] would introduce a circular dependency on [FeatureFlagsClassic]. - */ -@Qualifier -@MustBeDocumented -@Retention(AnnotationRetention.RUNTIME) -annotation class UnflaggedBackground - /** Providers for various coroutines-related constructs. */ @Module class CoroutinesModule { @@ -53,11 +29,6 @@ class CoroutinesModule { @Provides @SysUISingleton - @UnflaggedApplication - fun unflaggedApplicationScope(): CoroutineScope = CoroutineScope(Dispatchers.Main.immediate) - - @Provides - @SysUISingleton @Main @Deprecated( "Use @Main CoroutineContext instead", @@ -98,28 +69,14 @@ class CoroutinesModule { return Dispatchers.IO + tracingCoroutineContext } - @Provides - @UnflaggedBackground - @SysUISingleton - fun unflaggedBackgroundCoroutineContext(): CoroutineContext { - return Dispatchers.IO - } - @OptIn(ExperimentalCoroutinesApi::class) @Provides @Tracing @SysUISingleton - fun tracingCoroutineContext( - @CoroutineTracingEnabledKey enableTracing: Boolean - ): CoroutineContext = if (enableTracing) TraceContextElement() else EmptyCoroutineContext - - companion object { - @[Provides CoroutineTracingEnabledKey] - fun provideIsCoroutineTracingEnabledKey(featureFlags: FeatureFlagsClassic): Boolean { - return if (featureFlags.isEnabled(Flags.COROUTINE_TRACING)) { - coroutineTracingIsEnabled = true - true - } else false - } + fun tracingCoroutineContext(): CoroutineContext { + return if (coroutineTracing()) { + coroutineTracingIsEnabled = true + TraceContextElement() + } else EmptyCoroutineContext } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt index 799bd5ac5739..7242cb20dc77 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt @@ -31,6 +31,7 @@ import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.se import com.android.systemui.power.domain.interactor.PowerInteractorFactory import com.android.systemui.statusbar.CircleReveal import com.android.systemui.statusbar.LightRevealEffect +import com.android.systemui.util.mockito.mock import junit.framework.Assert.assertEquals import junit.framework.Assert.assertFalse import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -60,15 +61,11 @@ class LightRevealScrimRepositoryTest : SysuiTestCase() { MockitoAnnotations.initMocks(this) fakeKeyguardRepository = FakeKeyguardRepository() powerRepository = FakePowerRepository() - powerInteractor = PowerInteractorFactory.create( - repository = powerRepository - ).powerInteractor - - underTest = LightRevealScrimRepositoryImpl( - fakeKeyguardRepository, - context, - powerInteractor, - ) + powerInteractor = + PowerInteractorFactory.create(repository = powerRepository).powerInteractor + + underTest = + LightRevealScrimRepositoryImpl(fakeKeyguardRepository, context, powerInteractor, mock()) } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt index 03a1f7a3d6ab..b483085cf1e5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt @@ -26,6 +26,7 @@ import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.statusbar.LightRevealEffect import com.android.systemui.statusbar.LightRevealScrim +import com.android.systemui.util.mockito.mock import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach @@ -80,7 +81,8 @@ class LightRevealScrimInteractorTest : SysuiTestCase() { LightRevealScrimInteractor( keyguardTransitionInteractor, fakeLightRevealScrimRepository, - testScope.backgroundScope + testScope.backgroundScope, + mock() ) } diff --git a/ravenwood/framework-minus-apex-ravenwood-policies.txt b/ravenwood/framework-minus-apex-ravenwood-policies.txt index 3e54c7a06288..aa2d470d7d9c 100644 --- a/ravenwood/framework-minus-apex-ravenwood-policies.txt +++ b/ravenwood/framework-minus-apex-ravenwood-policies.txt @@ -121,3 +121,15 @@ class com.android.modules.utils.FastDataOutput stubclass class com.android.modules.utils.ModifiedUtf8 stubclass class com.android.modules.utils.TypedXmlPullParser stubclass class com.android.modules.utils.TypedXmlSerializer stubclass + +# Uri +class android.net.Uri stubclass +class android.net.UriCodec stubclass + +# Context: just enough to support wrapper, no further functionality +class android.content.Context stub + method <init> ()V stub + +# Text +class android.text.TextUtils stub + method isEmpty (Ljava/lang/CharSequence;)Z stub diff --git a/ravenwood/ravenwood-annotation-allowed-classes.txt b/ravenwood/ravenwood-annotation-allowed-classes.txt index 1ac6bf0a7c4d..0290bbe64439 100644 --- a/ravenwood/ravenwood-annotation-allowed-classes.txt +++ b/ravenwood/ravenwood-annotation-allowed-classes.txt @@ -10,3 +10,13 @@ android.os.IBinder android.os.Process android.os.SystemClock android.os.UserHandle + +android.content.ClipData +android.content.ClipData$Item +android.content.ClipDescription +android.content.ComponentName +android.content.ContentUris +android.content.ContentValues +android.content.Intent +android.content.IntentFilter +android.content.UriMatcher diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 7292ea6b19cb..14aab13bf638 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -531,19 +531,6 @@ public class AppOpsService extends IAppOpsService.Stub { } } - // Functions for uid mode access and manipulation. - public SparseIntArray getNonDefaultUidModes() { - return mAppOpsCheckingService.getNonDefaultUidModes(uid); - } - - public int getUidMode(int op) { - return mAppOpsCheckingService.getUidMode(uid, op); - } - - public boolean setUidMode(int op, int mode) { - return mAppOpsCheckingService.setUidMode(uid, op, mode); - } - @SuppressWarnings("GuardedBy") int evalMode(int op, int mode) { return getUidStateTracker().evalMode(uid, op, mode); @@ -613,15 +600,6 @@ public class AppOpsService extends IAppOpsService.Stub { this.packageName = packageName; } - @Mode int getMode() { - return mAppOpsCheckingService.getPackageMode(packageName, this.op, - UserHandle.getUserId(this.uid)); - } - void setMode(@Mode int mode) { - mAppOpsCheckingService.setPackageMode(packageName, this.op, mode, - UserHandle.getUserId(this.uid)); - } - void removeAttributionsWithNoTime() { for (int i = mAttributions.size() - 1; i >= 0; i--) { if (!mAttributions.valueAt(i).hasAnyTime()) { @@ -653,7 +631,11 @@ public class AppOpsService extends IAppOpsService.Stub { mAttributions.valueAt(i).createAttributedOpEntryLocked()); } - return new OpEntry(op, getMode(), attributionEntries); + return new OpEntry( + op, + mAppOpsCheckingService.getPackageMode( + this.packageName, this.op, UserHandle.getUserId(this.uid)), + attributionEntries); } @NonNull OpEntry createSingleAttributionEntryLocked(@Nullable String attributionTag) { @@ -668,7 +650,11 @@ public class AppOpsService extends IAppOpsService.Stub { } } - return new OpEntry(op, getMode(), attributionEntries); + return new OpEntry( + op, + mAppOpsCheckingService.getPackageMode( + this.packageName, this.op, UserHandle.getUserId(this.uid)), + attributionEntries); } boolean isRunning() { @@ -1384,8 +1370,10 @@ public class AppOpsService extends IAppOpsService.Stub { } final int code = foregroundOps.keyAt(fgi); - if (uidState.getUidMode(code) != AppOpsManager.opToDefaultMode(code) - && uidState.getUidMode(code) == AppOpsManager.MODE_FOREGROUND) { + if (mAppOpsCheckingService.getUidMode(uidState.uid, code) + != AppOpsManager.opToDefaultMode(code) + && mAppOpsCheckingService.getUidMode(uidState.uid, code) + == AppOpsManager.MODE_FOREGROUND) { mHandler.sendMessage(PooledLambda.obtainMessage( AppOpsService::notifyOpChangedForAllPkgsInUid, this, code, uidState.uid, true)); @@ -1405,7 +1393,11 @@ public class AppOpsService extends IAppOpsService.Stub { if (op == null) { continue; } - if (op.getMode() == AppOpsManager.MODE_FOREGROUND) { + if (mAppOpsCheckingService.getPackageMode( + op.packageName, + op.op, + UserHandle.getUserId(op.uid)) + == AppOpsManager.MODE_FOREGROUND) { mHandler.sendMessage(PooledLambda.obtainMessage( AppOpsService::notifyOpChanged, this, listenerSet.valueAt(cbi), code, uidState.uid, @@ -1497,7 +1489,7 @@ public class AppOpsService extends IAppOpsService.Stub { @Nullable private ArrayList<AppOpsManager.OpEntry> collectUidOps(@NonNull UidState uidState, @Nullable int[] ops) { - final SparseIntArray opModes = uidState.getNonDefaultUidModes(); + final SparseIntArray opModes = mAppOpsCheckingService.getNonDefaultUidModes(uidState.uid); if (opModes == null) { return null; } @@ -1778,7 +1770,11 @@ public class AppOpsService extends IAppOpsService.Stub { Ops ops = getOpsLocked(uid, packageName, null, false, null, /* edit */ false); if (ops != null) { ops.remove(op.op); - op.setMode(AppOpsManager.opToDefaultMode(op.op)); + mAppOpsCheckingService.setPackageMode( + packageName, + op.op, + AppOpsManager.opToDefaultMode(op.op), + UserHandle.getUserId(op.uid)); if (ops.size() <= 0) { UidState uidState = ops.uidState; ArrayMap<String, Ops> pkgOps = uidState.pkgOps; @@ -1848,15 +1844,16 @@ public class AppOpsService extends IAppOpsService.Stub { uidState = new UidState(uid); mUidStates.put(uid, uidState); } - if (uidState.getUidMode(code) != AppOpsManager.opToDefaultMode(code)) { - previousMode = uidState.getUidMode(code); + if (mAppOpsCheckingService.getUidMode(uidState.uid, code) + != AppOpsManager.opToDefaultMode(code)) { + previousMode = mAppOpsCheckingService.getUidMode(uidState.uid, code); } else { // doesn't look right but is legacy behavior. previousMode = MODE_DEFAULT; } mIgnoredCallback = permissionPolicyCallback; - if (!uidState.setUidMode(code, mode)) { + if (!mAppOpsCheckingService.setUidMode(uidState.uid, code, mode)) { return; } if (mode != MODE_ERRORED && mode != previousMode) { @@ -2133,10 +2130,15 @@ public class AppOpsService extends IAppOpsService.Stub { synchronized (this) { Op op = getOpLocked(code, uid, packageName, null, false, pvr.bypass, /* edit */ true); if (op != null) { - if (op.getMode() != mode) { - previousMode = op.getMode(); + if (mAppOpsCheckingService.getPackageMode( + op.packageName, op.op, UserHandle.getUserId(op.uid)) + != mode) { + previousMode = + mAppOpsCheckingService.getPackageMode( + op.packageName, op.op, UserHandle.getUserId(op.uid)); mIgnoredCallback = permissionPolicyCallback; - op.setMode(mode); + mAppOpsCheckingService.setPackageMode(op.packageName, op.op, mode, + UserHandle.getUserId(op.uid)); } } } @@ -2274,7 +2276,7 @@ public class AppOpsService extends IAppOpsService.Stub { for (int i = mUidStates.size() - 1; i >= 0; i--) { UidState uidState = mUidStates.valueAt(i); - SparseIntArray opModes = uidState.getNonDefaultUidModes(); + SparseIntArray opModes = mAppOpsCheckingService.getNonDefaultUidModes(uidState.uid); if (opModes != null && (uidState.uid == reqUid || reqUid == -1)) { final int uidOpCount = opModes.size(); for (int j = uidOpCount - 1; j >= 0; j--) { @@ -2283,7 +2285,7 @@ public class AppOpsService extends IAppOpsService.Stub { int previousMode = opModes.valueAt(j); int newMode = isUidOpGrantedByRole(uidState.uid, code) ? MODE_ALLOWED : AppOpsManager.opToDefaultMode(code); - uidState.setUidMode(code, newMode); + mAppOpsCheckingService.setUidMode(uidState.uid, code, newMode); for (String packageName : getPackagesForUid(uidState.uid)) { callbacks = addCallbacks(callbacks, code, uidState.uid, packageName, previousMode, mOpModeWatchers.get(code)); @@ -2325,14 +2327,22 @@ public class AppOpsService extends IAppOpsService.Stub { continue; } if (AppOpsManager.opAllowsReset(curOp.op)) { - int previousMode = curOp.getMode(); + int previousMode = + mAppOpsCheckingService.getPackageMode( + curOp.packageName, + curOp.op, + UserHandle.getUserId(curOp.uid)); int newMode = isPackageOpGrantedByRole(packageName, uidState.uid, curOp.op) ? MODE_ALLOWED : AppOpsManager.opToDefaultMode( curOp.op); if (previousMode == newMode) { continue; } - curOp.setMode(newMode); + mAppOpsCheckingService.setPackageMode( + curOp.packageName, + curOp.op, + newMode, + UserHandle.getUserId(curOp.uid)); changed = true; uidChanged = true; final int uid = curOp.uidState.uid; @@ -2592,15 +2602,22 @@ public class AppOpsService extends IAppOpsService.Stub { code = AppOpsManager.opToSwitch(code); UidState uidState = getUidStateLocked(uid, false); if (uidState != null - && uidState.getUidMode(code) != AppOpsManager.opToDefaultMode(code)) { - final int rawMode = uidState.getUidMode(code); + && mAppOpsCheckingService.getUidMode(uidState.uid, code) + != AppOpsManager.opToDefaultMode(code)) { + final int rawMode = mAppOpsCheckingService.getUidMode(uidState.uid, code); return raw ? rawMode : uidState.evalMode(code, rawMode); } Op op = getOpLocked(code, uid, packageName, null, false, pvr.bypass, /* edit */ false); if (op == null) { return AppOpsManager.opToDefaultMode(code); } - return raw ? op.getMode() : op.uidState.evalMode(op.op, op.getMode()); + return raw + ? mAppOpsCheckingService.getPackageMode( + op.packageName, op.op, UserHandle.getUserId(op.uid)) + : op.uidState.evalMode( + op.op, + mAppOpsCheckingService.getPackageMode( + op.packageName, op.op, UserHandle.getUserId(op.uid))); } } @@ -2836,8 +2853,11 @@ public class AppOpsService extends IAppOpsService.Stub { } // If there is a non-default per UID policy (we set UID op mode only if // non-default) it takes over, otherwise use the per package policy. - if (uidState.getUidMode(switchCode) != AppOpsManager.opToDefaultMode(switchCode)) { - final int uidMode = uidState.evalMode(code, uidState.getUidMode(switchCode)); + if (mAppOpsCheckingService.getUidMode(uidState.uid, switchCode) + != AppOpsManager.opToDefaultMode(switchCode)) { + final int uidMode = + uidState.evalMode( + code, mAppOpsCheckingService.getUidMode(uidState.uid, switchCode)); if (uidMode != AppOpsManager.MODE_ALLOWED) { if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code " + switchCode + " (" + code + ") uid " + uid + " package " @@ -2850,7 +2870,13 @@ public class AppOpsService extends IAppOpsService.Stub { } else { final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, uid, true) : op; - final int mode = switchOp.uidState.evalMode(switchOp.op, switchOp.getMode()); + final int mode = + switchOp.uidState.evalMode( + switchOp.op, + mAppOpsCheckingService.getPackageMode( + switchOp.packageName, + switchOp.op, + UserHandle.getUserId(switchOp.uid))); if (mode != AppOpsManager.MODE_ALLOWED) { if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + mode + " for code " + switchCode + " (" + code + ") uid " + uid + " package " @@ -3372,8 +3398,11 @@ public class AppOpsService extends IAppOpsService.Stub { final int switchCode = AppOpsManager.opToSwitch(code); // If there is a non-default per UID policy (we set UID op mode only if // non-default) it takes over, otherwise use the per package policy. - if (uidState.getUidMode(switchCode) != AppOpsManager.opToDefaultMode(switchCode)) { - final int uidMode = uidState.evalMode(code, uidState.getUidMode(switchCode)); + if (mAppOpsCheckingService.getUidMode(uidState.uid, switchCode) + != AppOpsManager.opToDefaultMode(switchCode)) { + final int uidMode = + uidState.evalMode( + code, mAppOpsCheckingService.getUidMode(uidState.uid, switchCode)); if (!shouldStartForMode(uidMode, startIfModeDefault)) { if (DEBUG) { Slog.d(TAG, "startOperation: uid reject #" + uidMode + " for code " @@ -3388,7 +3417,13 @@ public class AppOpsService extends IAppOpsService.Stub { } else { final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, uid, true) : op; - final int mode = switchOp.uidState.evalMode(switchOp.op, switchOp.getMode()); + final int mode = + switchOp.uidState.evalMode( + switchOp.op, + mAppOpsCheckingService.getPackageMode( + switchOp.packageName, + switchOp.op, + UserHandle.getUserId(switchOp.uid))); if (mode != AppOpsManager.MODE_ALLOWED && (!startIfModeDefault || mode != MODE_DEFAULT)) { if (DEBUG) Slog.d(TAG, "startOperation: reject #" + mode + " for code " @@ -3478,8 +3513,11 @@ public class AppOpsService extends IAppOpsService.Stub { final int switchCode = AppOpsManager.opToSwitch(code); // If there is a non-default mode per UID policy (we set UID op mode only if // non-default) it takes over, otherwise use the per package policy. - if (uidState.getUidMode(switchCode) != AppOpsManager.opToDefaultMode(switchCode)) { - final int uidMode = uidState.evalMode(code, uidState.getUidMode(switchCode)); + if (mAppOpsCheckingService.getUidMode(uidState.uid, switchCode) + != AppOpsManager.opToDefaultMode(switchCode)) { + final int uidMode = + uidState.evalMode( + code, mAppOpsCheckingService.getUidMode(uidState.uid, switchCode)); if (!shouldStartForMode(uidMode, startIfModeDefault)) { if (DEBUG) { Slog.d(TAG, "startOperation: uid reject #" + uidMode + " for code " @@ -3491,7 +3529,13 @@ public class AppOpsService extends IAppOpsService.Stub { } else { final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, uid, true) : op; - final int mode = switchOp.uidState.evalMode(switchOp.op, switchOp.getMode()); + final int mode = + switchOp.uidState.evalMode( + switchOp.op, + mAppOpsCheckingService.getPackageMode( + switchOp.packageName, + switchOp.op, + UserHandle.getUserId(switchOp.uid))); if (mode != AppOpsManager.MODE_ALLOWED && (!startIfModeDefault || mode != MODE_DEFAULT)) { if (DEBUG) { @@ -5620,7 +5664,8 @@ public class AppOpsService extends IAppOpsService.Stub { } for (int i=0; i<mUidStates.size(); i++) { UidState uidState = mUidStates.valueAt(i); - final SparseIntArray opModes = uidState.getNonDefaultUidModes(); + final SparseIntArray opModes = + mAppOpsCheckingService.getNonDefaultUidModes(uidState.uid); final ArrayMap<String, Ops> pkgOps = uidState.pkgOps; if (dumpWatchers || dumpHistory) { @@ -5648,7 +5693,12 @@ public class AppOpsService extends IAppOpsService.Stub { } if (!hasMode) { for (int opi = 0; !hasMode && opi < ops.size(); opi++) { - if (ops.valueAt(opi).getMode() == dumpMode) { + final Op op = ops.valueAt(opi); + if (mAppOpsCheckingService.getPackageMode( + op.packageName, + op.op, + UserHandle.getUserId(op.uid)) + == dumpMode) { hasMode = true; } } @@ -5699,7 +5749,12 @@ public class AppOpsService extends IAppOpsService.Stub { if (dumpOp >= 0 && dumpOp != opCode) { continue; } - if (dumpMode >= 0 && dumpMode != op.getMode()) { + if (dumpMode >= 0 + && dumpMode + != mAppOpsCheckingService.getPackageMode( + op.packageName, + op.op, + UserHandle.getUserId(op.uid))) { continue; } if (!printedPackage) { @@ -5707,14 +5762,25 @@ public class AppOpsService extends IAppOpsService.Stub { printedPackage = true; } pw.print(" "); pw.print(AppOpsManager.opToName(opCode)); - pw.print(" ("); pw.print(AppOpsManager.modeToName(op.getMode())); + pw.print(" ("); + pw.print( + AppOpsManager.modeToName( + mAppOpsCheckingService.getPackageMode( + op.packageName, + op.op, + UserHandle.getUserId(op.uid)))); final int switchOp = AppOpsManager.opToSwitch(opCode); if (switchOp != opCode) { pw.print(" / switch "); pw.print(AppOpsManager.opToName(switchOp)); final Op switchObj = ops.get(switchOp); - int mode = switchObj == null - ? AppOpsManager.opToDefaultMode(switchOp) : switchObj.getMode(); + int mode = + switchObj == null + ? AppOpsManager.opToDefaultMode(switchOp) + : mAppOpsCheckingService.getPackageMode( + switchObj.packageName, + switchObj.op, + UserHandle.getUserId(switchObj.uid)); pw.print("="); pw.print(AppOpsManager.modeToName(mode)); } pw.println("): "); @@ -5848,7 +5914,13 @@ public class AppOpsService extends IAppOpsService.Stub { for (int pkgNum = 0; pkgNum < numPkgOps; pkgNum++) { Ops ops = uidState.pkgOps.valueAt(pkgNum); Op op = ops != null ? ops.get(code) : null; - if (op == null || (op.getMode() != MODE_ALLOWED && op.getMode() != MODE_FOREGROUND)) { + if (op == null) { + continue; + } + final int mode = + mAppOpsCheckingService.getPackageMode( + op.packageName, op.op, UserHandle.getUserId(op.uid)); + if (mode != MODE_ALLOWED && mode != MODE_FOREGROUND) { continue; } int numAttrTags = op.mAttributions.size(); diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java index 3de188f08fb1..93d9b8d30a2e 100644 --- a/services/core/java/com/android/server/display/ColorFade.java +++ b/services/core/java/com/android/server/display/ColorFade.java @@ -411,6 +411,33 @@ final class ColorFade { } /** + * Destroys ColorFade animation and its resources + * + * This method should be called when the ColorFade is no longer in use; i.e. when + * the {@link #mDisplayId display} has been removed. + */ + public void destroy() { + if (DEBUG) { + Slog.d(TAG, "destroy"); + } + if (mPrepared) { + if (mCreatedResources) { + attachEglContext(); + try { + destroyScreenshotTexture(); + destroyGLShaders(); + destroyGLBuffers(); + destroyEglSurface(); + } finally { + detachEglContext(); + } + } + destroyEglContext(); + destroySurface(); + } + } + + /** * Draws an animation frame showing the color fade activated at the * specified level. * @@ -793,6 +820,12 @@ final class ColorFade { } } + private void destroyEglContext() { + if (mEglDisplay != null && mEglContext != null) { + EGL14.eglDestroyContext(mEglDisplay, mEglContext); + } + } + private static FloatBuffer createNativeFloatBuffer(int size) { ByteBuffer bb = ByteBuffer.allocateDirect(size * 4); bb.order(ByteOrder.nativeOrder()); diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java index be03a808e166..f994c0556c82 100644 --- a/services/core/java/com/android/server/display/DisplayPowerState.java +++ b/services/core/java/com/android/server/display/DisplayPowerState.java @@ -320,7 +320,9 @@ final class DisplayPowerState { public void stop() { mStopped = true; mPhotonicModulator.interrupt(); - dismissColorFade(); + if (mColorFade != null) { + mColorFade.destroy(); + } mCleanListener = null; mHandler.removeCallbacksAndMessages(null); } diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index 568618e0a065..57e424d944f5 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -243,6 +243,10 @@ public class LockSettingsService extends ILockSettings.Stub { private static final String MIGRATED_FRP2 = "migrated_frp2"; private static final String MIGRATED_KEYSTORE_NS = "migrated_keystore_namespace"; private static final String MIGRATED_SP_CE_ONLY = "migrated_all_users_to_sp_and_bound_ce"; + private static final String MIGRATED_SP_FULL = "migrated_all_users_to_sp_and_bound_keys"; + + private static final boolean FIX_UNLOCKED_DEVICE_REQUIRED_KEYS = + android.security.Flags.fixUnlockedDeviceRequiredKeys(); // Duration that LockSettingsService will store the gatekeeper password for. This allows // multiple biometric enrollments without prompting the user to enter their password via @@ -856,9 +860,11 @@ public class LockSettingsService extends ILockSettings.Stub { @Override public void onReceive(Context context, Intent intent) { if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) { - // Notify keystore that a new user was added. - final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); - AndroidKeyStoreMaintenance.onUserAdded(userHandle); + if (!FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) { + // Notify keystore that a new user was added. + final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); + AndroidKeyStoreMaintenance.onUserAdded(userHandle); + } } else if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) { final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); mStorage.prefetchUser(userHandle); @@ -1022,24 +1028,53 @@ public class LockSettingsService extends ILockSettings.Stub { } mEarlyCreatedUsers = null; // no longer needed - // Also do a one-time migration of all users to SP-based credentials with the CE key - // encrypted by the SP. This is needed for the system user on the first boot of a - // device, as the system user is special and never goes through the user creation flow - // that other users do. It is also needed for existing users on a device upgraded from - // Android 13 or earlier, where users with no LSKF didn't necessarily have an SP, and if - // they did have an SP then their CE key wasn't encrypted by it. + // Do a one-time migration for any unsecured users: create the user's synthetic password + // if not already done, encrypt the user's CE key with the synthetic password if not + // already done, and create the user's Keystore super keys if not already done. + // + // This is needed for the following cases: + // + // - Finalizing the creation of the system user on the first boot of a device, as the + // system user is special and doesn't go through the normal user creation flow. + // + // - Upgrading from Android 13 or earlier, where unsecured users didn't necessarily have + // a synthetic password, and if they did have a synthetic password their CE key wasn't + // encrypted by it. Also, unsecured users didn't have Keystore super keys. // - // If this gets interrupted (e.g. by the device powering off), there shouldn't be a - // problem since this will run again on the next boot, and setCeStorageProtection() is - // okay with the CE key being already protected by the given secret. - if (getString(MIGRATED_SP_CE_ONLY, null, 0) == null) { - for (UserInfo user : mUserManager.getAliveUsers()) { - removeStateForReusedUserIdIfNecessary(user.id, user.serialNumber); - synchronized (mSpManager) { - migrateUserToSpWithBoundCeKeyLocked(user.id); + // - Upgrading from Android 14, where unsecured users didn't have Keystore super keys. + // + // The end result is that all users, regardless of whether they are secured or not, have + // a synthetic password with all keys initialized and protected by it. + // + // Note: if this migration gets interrupted (e.g. by the device powering off), there + // shouldn't be a problem since this will run again on the next boot, and + // setCeStorageProtection() and initKeystoreSuperKeys(..., true) are idempotent. + if (FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) { + if (!getBoolean(MIGRATED_SP_FULL, false, 0)) { + for (UserInfo user : mUserManager.getAliveUsers()) { + removeStateForReusedUserIdIfNecessary(user.id, user.serialNumber); + synchronized (mSpManager) { + migrateUserToSpWithBoundKeysLocked(user.id); + } + } + setBoolean(MIGRATED_SP_FULL, true, 0); + } + } else { + if (getString(MIGRATED_SP_CE_ONLY, null, 0) == null) { + for (UserInfo user : mUserManager.getAliveUsers()) { + removeStateForReusedUserIdIfNecessary(user.id, user.serialNumber); + synchronized (mSpManager) { + migrateUserToSpWithBoundCeKeyLocked(user.id); + } } + setString(MIGRATED_SP_CE_ONLY, "true", 0); + } + + if (getBoolean(MIGRATED_SP_FULL, false, 0)) { + // The FIX_UNLOCKED_DEVICE_REQUIRED_KEYS flag was enabled but then got disabled. + // Ensure the full migration runs again the next time the flag is enabled... + setBoolean(MIGRATED_SP_FULL, false, 0); } - setString(MIGRATED_SP_CE_ONLY, "true", 0); } mThirdPartyAppsStarted = true; @@ -1070,6 +1105,37 @@ public class LockSettingsService extends ILockSettings.Stub { } } + @GuardedBy("mSpManager") + private void migrateUserToSpWithBoundKeysLocked(@UserIdInt int userId) { + if (isUserSecure(userId)) { + Slogf.d(TAG, "User %d is secured; no migration needed", userId); + return; + } + long protectorId = getCurrentLskfBasedProtectorId(userId); + if (protectorId == SyntheticPasswordManager.NULL_PROTECTOR_ID) { + Slogf.i(TAG, "Migrating unsecured user %d to SP-based credential", userId); + initializeSyntheticPassword(userId); + return; + } + Slogf.i(TAG, "Existing unsecured user %d has a synthetic password", userId); + AuthenticationResult result = mSpManager.unlockLskfBasedProtector( + getGateKeeperService(), protectorId, LockscreenCredential.createNone(), userId, + null); + SyntheticPassword sp = result.syntheticPassword; + if (sp == null) { + Slogf.wtf(TAG, "Failed to unwrap synthetic password for unsecured user %d", userId); + return; + } + // While setCeStorageProtection() is idempotent, it does log some error messages when called + // again. Skip it if we know it was already handled by an earlier upgrade to Android 14. + if (getString(MIGRATED_SP_CE_ONLY, null, 0) == null) { + Slogf.i(TAG, "Encrypting CE key of user %d with synthetic password", userId); + setCeStorageProtection(userId, sp); + } + Slogf.i(TAG, "Initializing Keystore super keys for user %d", userId); + initKeystoreSuperKeys(userId, sp, /* allowExisting= */ true); + } + /** * Returns the lowest password quality that still presents the same UI for entering it. * @@ -1351,6 +1417,20 @@ public class LockSettingsService extends ILockSettings.Stub { AndroidKeyStoreMaintenance.onUserPasswordChanged(userHandle, password); } + @VisibleForTesting /** Note: this method is overridden in unit tests */ + void initKeystoreSuperKeys(@UserIdInt int userId, SyntheticPassword sp, boolean allowExisting) { + final byte[] password = sp.deriveKeyStorePassword(); + try { + int res = AndroidKeyStoreMaintenance.initUserSuperKeys(userId, password, allowExisting); + if (res != 0) { + throw new IllegalStateException("Failed to initialize Keystore super keys for user " + + userId); + } + } finally { + Arrays.fill(password, (byte) 0); + } + } + private void unlockKeystore(int userId, SyntheticPassword sp) { Authorization.onLockScreenEvent(false, userId, sp.deriveKeyStorePassword(), null); } @@ -2074,6 +2154,9 @@ public class LockSettingsService extends ILockSettings.Stub { return; } onSyntheticPasswordUnlocked(userId, result.syntheticPassword); + if (FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) { + unlockKeystore(userId, result.syntheticPassword); + } unlockCeStorage(userId, result.syntheticPassword); } } @@ -2353,6 +2436,16 @@ public class LockSettingsService extends ILockSettings.Stub { } private void createNewUser(@UserIdInt int userId, int userSerialNumber) { + + // Delete all Keystore keys for userId, just in case any were left around from a removed + // user with the same userId. This should be unnecessary, but we've been doing this for a + // long time, so for now we keep doing it just in case it's ever important. Don't wait + // until initKeystoreSuperKeys() to do this; that can be delayed if the user is being + // created during early boot, and maybe something will use Keystore before then. + if (FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) { + AndroidKeyStoreMaintenance.onUserAdded(userId); + } + synchronized (mUserCreationAndRemovalLock) { // During early boot, don't actually create the synthetic password yet, but rather // automatically delay it to later. We do this because protecting the synthetic @@ -2759,7 +2852,7 @@ public class LockSettingsService extends ILockSettings.Stub { /** * Creates the synthetic password (SP) for the given user, protects it with an empty LSKF, and - * protects the user's CE key with a key derived from the SP. + * protects the user's CE storage key and Keystore super keys with keys derived from the SP. * * <p>This is called just once in the lifetime of the user: at user creation time (possibly * delayed until the time when Weaver is guaranteed to be available), or when upgrading from @@ -2778,6 +2871,9 @@ public class LockSettingsService extends ILockSettings.Stub { LockscreenCredential.createNone(), sp, userId); setCurrentLskfBasedProtectorId(protectorId, userId); setCeStorageProtection(userId, sp); + if (FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) { + initKeystoreSuperKeys(userId, sp, /* allowExisting= */ false); + } onSyntheticPasswordCreated(userId, sp); Slogf.i(TAG, "Successfully initialized synthetic password for user %d", userId); return sp; @@ -2870,11 +2966,10 @@ public class LockSettingsService extends ILockSettings.Stub { /** * Changes the user's LSKF by creating an LSKF-based protector that uses the new LSKF (which may * be empty) and replacing the old LSKF-based protector with it. The SP itself is not changed. - * - * Also maintains the invariants described in {@link SyntheticPasswordManager} by - * setting/clearing the protection (by the SP) on the user's auth-bound Keystore keys when the - * LSKF is added/removed, respectively. If an LSKF is being added, then the Gatekeeper auth - * token is also refreshed. + * <p> + * Also maintains the invariants described in {@link SyntheticPasswordManager} by enrolling / + * deleting the synthetic password into Gatekeeper as the LSKF is set / cleared, and asking + * Keystore to delete the user's auth-bound keys when the LSKF is cleared. */ @GuardedBy("mSpManager") private long setLockCredentialWithSpLocked(LockscreenCredential credential, @@ -2893,7 +2988,9 @@ public class LockSettingsService extends ILockSettings.Stub { if (!mSpManager.hasSidForUser(userId)) { mSpManager.newSidForUser(getGateKeeperService(), sp, userId); mSpManager.verifyChallenge(getGateKeeperService(), sp, 0L, userId); - setKeystorePassword(sp.deriveKeyStorePassword(), userId); + if (!FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) { + setKeystorePassword(sp.deriveKeyStorePassword(), userId); + } } } else { // Cache all profile password if they use unified work challenge. This will later be @@ -2904,7 +3001,11 @@ public class LockSettingsService extends ILockSettings.Stub { gateKeeperClearSecureUserId(userId); unlockCeStorage(userId, sp); unlockKeystore(userId, sp); - setKeystorePassword(null, userId); + if (FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) { + AndroidKeyStoreMaintenance.onUserLskfRemoved(userId); + } else { + setKeystorePassword(null, userId); + } removeBiometricsForUser(userId); } setCurrentLskfBasedProtectorId(newProtectorId, userId); diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java index 8e9c21f5f35f..cc205d4a53bd 100644 --- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java +++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java @@ -90,10 +90,15 @@ import java.util.Set; * * - The user's credential-encrypted storage is always protected by the SP. * - * - The user's auth-bound Keystore keys are protected by the SP, but only while an LSKF is set. - * This works by setting the user's Keystore and Gatekeeper passwords to SP-derived secrets, but - * only while an LSKF is set. When the LSKF is removed, these passwords are cleared, - * invalidating the user's auth-bound keys. + * - The user's Keystore superencryption keys are always protected by the SP. These in turn + * protect the Keystore keys that require user authentication, an unlocked device, or both. + * + * - A secret derived from the synthetic password is enrolled in Gatekeeper for the user, but only + * while the user has a (nonempty) LSKF. This enrollment has an associated ID called the Secure + * user ID or SID. This use of Gatekeeper, which is separate from the use of GateKeeper that may + * be used in the LSKF-based protector, makes it so that unlocking the synthetic password + * generates a HardwareAuthToken (but only when the user has LSKF). That HardwareAuthToken can + * be provided to KeyMint to authorize the use of the user's authentication-bound Keystore keys. * * Files stored on disk for each user: * For the SP itself, stored under NULL_PROTECTOR_ID: diff --git a/services/core/java/com/android/server/power/ThermalManagerService.java b/services/core/java/com/android/server/power/ThermalManagerService.java index 99064bc1884d..d17207b8f261 100644 --- a/services/core/java/com/android/server/power/ThermalManagerService.java +++ b/services/core/java/com/android/server/power/ThermalManagerService.java @@ -28,6 +28,7 @@ import android.hardware.thermal.V1_0.ThermalStatusCode; import android.hardware.thermal.V1_1.IThermalCallback; import android.os.Binder; import android.os.CoolingDevice; +import android.os.Flags; import android.os.Handler; import android.os.HwBinder; import android.os.IBinder; @@ -181,7 +182,7 @@ public class ThermalManagerService extends SystemService { onTemperatureChanged(temperatures.get(i), false); } onTemperatureMapChangedLocked(); - mTemperatureWatcher.updateSevereThresholds(); + mTemperatureWatcher.updateThresholds(); mHalReady.set(true); } } @@ -506,6 +507,20 @@ public class ThermalManagerService extends SystemService { } @Override + public float[] getThermalHeadroomThresholds() { + if (!mHalReady.get()) { + throw new IllegalStateException("Thermal HAL connection is not initialized"); + } + if (!Flags.allowThermalHeadroomThresholds()) { + throw new UnsupportedOperationException("Thermal headroom thresholds not enabled"); + } + synchronized (mTemperatureWatcher.mSamples) { + return Arrays.copyOf(mTemperatureWatcher.mHeadroomThresholds, + mTemperatureWatcher.mHeadroomThresholds.length); + } + } + + @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { dumpInternal(fd, pw, args); } @@ -580,6 +595,12 @@ public class ThermalManagerService extends SystemService { mHalWrapper.getTemperatureThresholds(false, 0)); } } + if (Flags.allowThermalHeadroomThresholds()) { + synchronized (mTemperatureWatcher.mSamples) { + pw.println("Temperature headroom thresholds:"); + pw.println(Arrays.toString(mTemperatureWatcher.mHeadroomThresholds)); + } + } } finally { Binder.restoreCallingIdentity(token); } @@ -964,7 +985,14 @@ public class ThermalManagerService extends SystemService { connectToHal(); } if (mInstance != null) { - Slog.i(TAG, "Thermal HAL AIDL service connected."); + try { + Slog.i(TAG, "Thermal HAL AIDL service connected with version " + + mInstance.getInterfaceVersion()); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to read interface version from Thermal HAL", e); + connectToHal(); + return; + } registerThermalChangedCallback(); } } @@ -1440,26 +1468,55 @@ public class ThermalManagerService extends SystemService { ArrayMap<String, Float> mSevereThresholds = new ArrayMap<>(); @GuardedBy("mSamples") + float[] mHeadroomThresholds = new float[ThrottlingSeverity.SHUTDOWN + 1]; + @GuardedBy("mSamples") private long mLastForecastCallTimeMillis = 0; private static final int INACTIVITY_THRESHOLD_MILLIS = 10000; @VisibleForTesting long mInactivityThresholdMillis = INACTIVITY_THRESHOLD_MILLIS; - void updateSevereThresholds() { + void updateThresholds() { synchronized (mSamples) { List<TemperatureThreshold> thresholds = mHalWrapper.getTemperatureThresholds(true, Temperature.TYPE_SKIN); + if (Flags.allowThermalHeadroomThresholds()) { + Arrays.fill(mHeadroomThresholds, Float.NaN); + } for (int t = 0; t < thresholds.size(); ++t) { TemperatureThreshold threshold = thresholds.get(t); if (threshold.hotThrottlingThresholds.length <= ThrottlingSeverity.SEVERE) { continue; } - float temperature = + float severeThreshold = threshold.hotThrottlingThresholds[ThrottlingSeverity.SEVERE]; - if (!Float.isNaN(temperature)) { - mSevereThresholds.put(threshold.name, - threshold.hotThrottlingThresholds[ThrottlingSeverity.SEVERE]); + if (!Float.isNaN(severeThreshold)) { + mSevereThresholds.put(threshold.name, severeThreshold); + for (int severity = ThrottlingSeverity.LIGHT; + severity <= ThrottlingSeverity.SHUTDOWN; severity++) { + if (Flags.allowThermalHeadroomThresholds() + && threshold.hotThrottlingThresholds.length > severity) { + updateHeadroomThreshold(severity, + threshold.hotThrottlingThresholds[severity], + severeThreshold); + } + } + } + } + } + } + + // For a older device with multiple SKIN sensors, we will set a severity's headroom + // threshold based on the minimum value of all as a workaround. + void updateHeadroomThreshold(int severity, float threshold, float severeThreshold) { + if (!Float.isNaN(threshold)) { + synchronized (mSamples) { + float headroom = normalizeTemperature(threshold, severeThreshold); + if (Float.isNaN(mHeadroomThresholds[severity])) { + mHeadroomThresholds[severity] = headroom; + } else { + float lastHeadroom = mHeadroomThresholds[severity]; + mHeadroomThresholds[severity] = Math.min(lastHeadroom, headroom); } } } @@ -1541,15 +1598,13 @@ public class ThermalManagerService extends SystemService { private static final float DEGREES_BETWEEN_ZERO_AND_ONE = 30.0f; @VisibleForTesting - float normalizeTemperature(float temperature, float severeThreshold) { - synchronized (mSamples) { - float zeroNormalized = severeThreshold - DEGREES_BETWEEN_ZERO_AND_ONE; - if (temperature <= zeroNormalized) { - return 0.0f; - } - float delta = temperature - zeroNormalized; - return delta / DEGREES_BETWEEN_ZERO_AND_ONE; + static float normalizeTemperature(float temperature, float severeThreshold) { + float zeroNormalized = severeThreshold - DEGREES_BETWEEN_ZERO_AND_ONE; + if (temperature <= zeroNormalized) { + return 0.0f; } + float delta = temperature - zeroNormalized; + return delta / DEGREES_BETWEEN_ZERO_AND_ONE; } private static final int MINIMUM_SAMPLE_COUNT = 3; diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index 21820939ba03..f1cddc643422 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -2557,11 +2557,10 @@ static void nativeSetMotionClassifierEnabled(JNIEnv* env, jobject nativeImplObj, static void nativeSetKeyRepeatConfiguration(JNIEnv* env, jobject nativeImplObj, jint timeoutMs, jint delayMs) { NativeInputManager* im = getNativeInputManager(env, nativeImplObj); - im->getInputManager()->getDispatcher().setKeyRepeatConfiguration(static_cast<nsecs_t>( - timeoutMs) * - 1000000, - static_cast<nsecs_t>(delayMs) * - 1000000); + im->getInputManager()->getDispatcher().setKeyRepeatConfiguration(std::chrono::milliseconds( + timeoutMs), + std::chrono::milliseconds( + delayMs)); } static jobject createInputSensorInfo(JNIEnv* env, jstring name, jstring vendor, jint version, diff --git a/services/tests/displayservicetests/Android.bp b/services/tests/displayservicetests/Android.bp index 6e4069fbe4bd..3bafe7296fff 100644 --- a/services/tests/displayservicetests/Android.bp +++ b/services/tests/displayservicetests/Android.bp @@ -7,19 +7,12 @@ package { default_applicable_licenses: ["frameworks_base_license"], } -// Include all test java files. -filegroup { - name: "displayservicetests-sources", - srcs: [ - "src/**/*.java", - ], -} - android_test { name: "DisplayServiceTests", srcs: [ "src/**/*.java", + "src/**/*.kt", ], libs: [ @@ -33,6 +26,8 @@ android_test { "frameworks-base-testutils", "junit", "junit-params", + "kotlin-test", + "mockito-kotlin2", "mockingservicestests-utils-mockito", "platform-compat-test-rules", "platform-test-annotations", diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerStateTest.kt b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerStateTest.kt new file mode 100644 index 000000000000..49fa2545e001 --- /dev/null +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerStateTest.kt @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.display + +import android.view.Display +import androidx.test.filters.SmallTest +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.mockito.junit.MockitoJUnit + +import org.mockito.kotlin.mock +import org.mockito.kotlin.verify + +@SmallTest +class DisplayPowerStateTest { + + private lateinit var displayPowerState: DisplayPowerState + + @get:Rule + val mockitoRule = MockitoJUnit.rule() + + private val mockBlanker = mock<DisplayBlanker>() + private val mockColorFade = mock<ColorFade>() + + @Before + fun setUp() { + displayPowerState = DisplayPowerState(mockBlanker, mockColorFade, 123, Display.STATE_ON) + } + + @Test + fun `destroys ColorFade on stop`() { + displayPowerState.stop() + + verify(mockColorFade).destroy() + } +}
\ No newline at end of file diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java index 1c33d0de4568..18961c0feef9 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java @@ -34,6 +34,7 @@ import android.service.gatekeeper.IGateKeeperService; import com.android.internal.widget.LockscreenCredential; import com.android.server.ServiceThread; +import com.android.server.locksettings.SyntheticPasswordManager.SyntheticPassword; import com.android.server.locksettings.recoverablekeystore.RecoverableKeyStoreManager; import com.android.server.pm.UserManagerInternal; @@ -203,6 +204,10 @@ public class LockSettingsServiceTestable extends LockSettingsService { } @Override + void initKeystoreSuperKeys(int userId, SyntheticPassword sp, boolean allowExisting) { + } + + @Override protected boolean isCredentialSharableWithParent(int userId) { UserInfo userInfo = mUserManager.getUserInfo(userId); return userInfo.isCloneProfile() || userInfo.isManagedProfile(); diff --git a/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java index 13c011ad2f68..44dad593810a 100644 --- a/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java @@ -18,9 +18,11 @@ package com.android.server.power; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; @@ -28,6 +30,7 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.timeout; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -49,6 +52,7 @@ import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.server.SystemService; +import com.android.server.power.ThermalManagerService.TemperatureWatcher; import com.android.server.power.ThermalManagerService.ThermalHalWrapper; import org.junit.Before; @@ -65,6 +69,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; +import java.util.Map; /** * atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server @@ -415,9 +420,9 @@ public class ThermalManagerServiceTest { @Test public void testTemperatureWatcherUpdateSevereThresholds() throws RemoteException { - ThermalManagerService.TemperatureWatcher watcher = mService.mTemperatureWatcher; + TemperatureWatcher watcher = mService.mTemperatureWatcher; watcher.mSevereThresholds.erase(); - watcher.updateSevereThresholds(); + watcher.updateThresholds(); assertEquals(1, watcher.mSevereThresholds.size()); assertEquals("skin1", watcher.mSevereThresholds.keyAt(0)); Float threshold = watcher.mSevereThresholds.get("skin1"); @@ -426,9 +431,60 @@ public class ThermalManagerServiceTest { } @Test + public void testTemperatureWatcherUpdateHeadroomThreshold() { + TemperatureWatcher watcher = mService.mTemperatureWatcher; + synchronized (watcher.mSamples) { + Arrays.fill(watcher.mHeadroomThresholds, Float.NaN); + } + watcher.updateHeadroomThreshold(ThrottlingSeverity.LIGHT, 40, 49); + watcher.updateHeadroomThreshold(ThrottlingSeverity.MODERATE, 46, 49); + watcher.updateHeadroomThreshold(ThrottlingSeverity.SEVERE, 49, 49); + watcher.updateHeadroomThreshold(ThrottlingSeverity.CRITICAL, 64, 49); + watcher.updateHeadroomThreshold(ThrottlingSeverity.EMERGENCY, 70, 49); + watcher.updateHeadroomThreshold(ThrottlingSeverity.SHUTDOWN, 79, 49); + synchronized (watcher.mSamples) { + assertArrayEquals(new float[]{Float.NaN, 0.7f, 0.9f, 1.0f, 1.5f, 1.7f, 2.0f}, + watcher.mHeadroomThresholds, 0.01f); + } + + // when another sensor reports different threshold, we expect to see smaller one to be used + watcher.updateHeadroomThreshold(ThrottlingSeverity.LIGHT, 37, 52); + watcher.updateHeadroomThreshold(ThrottlingSeverity.MODERATE, 46, 52); + watcher.updateHeadroomThreshold(ThrottlingSeverity.SEVERE, 52, 52); + watcher.updateHeadroomThreshold(ThrottlingSeverity.CRITICAL, 64, 52); + watcher.updateHeadroomThreshold(ThrottlingSeverity.EMERGENCY, 100, 52); + watcher.updateHeadroomThreshold(ThrottlingSeverity.SHUTDOWN, 200, 52); + synchronized (watcher.mSamples) { + assertArrayEquals(new float[]{Float.NaN, 0.5f, 0.8f, 1.0f, 1.4f, 1.7f, 2.0f}, + watcher.mHeadroomThresholds, 0.01f); + } + } + + @Test + public void testGetThermalHeadroomThresholdsOnlyReadOnce() throws Exception { + float[] expected = new float[]{Float.NaN, 0.1f, 0.2f, 0.3f, 0.4f, Float.NaN, 0.6f}; + when(mIThermalServiceMock.getThermalHeadroomThresholds()).thenReturn(expected); + Map<Integer, Float> thresholds1 = mPowerManager.getThermalHeadroomThresholds(); + verify(mIThermalServiceMock, times(1)).getThermalHeadroomThresholds(); + for (int status = PowerManager.THERMAL_STATUS_LIGHT; + status <= PowerManager.THERMAL_STATUS_SHUTDOWN; status++) { + if (Float.isNaN(expected[status])) { + assertFalse(thresholds1.containsKey(status)); + } else { + assertEquals(expected[status], thresholds1.get(status), 0.01f); + } + } + reset(mIThermalServiceMock); + Map<Integer, Float> thresholds2 = mPowerManager.getThermalHeadroomThresholds(); + verify(mIThermalServiceMock, times(0)).getThermalHeadroomThresholds(); + assertNotSame(thresholds1, thresholds2); + assertEquals(thresholds1, thresholds2); + } + + @Test public void testTemperatureWatcherGetSlopeOf() throws RemoteException { - ThermalManagerService.TemperatureWatcher watcher = mService.mTemperatureWatcher; - List<ThermalManagerService.TemperatureWatcher.Sample> samples = new ArrayList<>(); + TemperatureWatcher watcher = mService.mTemperatureWatcher; + List<TemperatureWatcher.Sample> samples = new ArrayList<>(); for (int i = 0; i < 30; ++i) { samples.add(watcher.createSampleForTesting(i, (float) (i / 2 * 2))); } @@ -437,21 +493,23 @@ public class ThermalManagerServiceTest { @Test public void testTemperatureWatcherNormalizeTemperature() throws RemoteException { - ThermalManagerService.TemperatureWatcher watcher = mService.mTemperatureWatcher; - assertEquals(0.5f, watcher.normalizeTemperature(25.0f, 40.0f), 0.0f); + assertEquals(0.5f, + TemperatureWatcher.normalizeTemperature(25.0f, 40.0f), 0.0f); // Temperatures more than 30 degrees below the SEVERE threshold should be clamped to 0.0f - assertEquals(0.0f, watcher.normalizeTemperature(0.0f, 40.0f), 0.0f); + assertEquals(0.0f, + TemperatureWatcher.normalizeTemperature(0.0f, 40.0f), 0.0f); // Temperatures above the SEVERE threshold should not be clamped - assertEquals(2.0f, watcher.normalizeTemperature(70.0f, 40.0f), 0.0f); + assertEquals(2.0f, + TemperatureWatcher.normalizeTemperature(70.0f, 40.0f), 0.0f); } @Test public void testTemperatureWatcherGetForecast() throws RemoteException { - ThermalManagerService.TemperatureWatcher watcher = mService.mTemperatureWatcher; + TemperatureWatcher watcher = mService.mTemperatureWatcher; - ArrayList<ThermalManagerService.TemperatureWatcher.Sample> samples = new ArrayList<>(); + ArrayList<TemperatureWatcher.Sample> samples = new ArrayList<>(); // Add a single sample samples.add(watcher.createSampleForTesting(0, 25.0f)); @@ -478,7 +536,7 @@ public class ThermalManagerServiceTest { @Test public void testTemperatureWatcherGetForecastUpdate() throws Exception { - ThermalManagerService.TemperatureWatcher watcher = mService.mTemperatureWatcher; + TemperatureWatcher watcher = mService.mTemperatureWatcher; // Reduce the inactivity threshold to speed up testing watcher.mInactivityThresholdMillis = 2000; @@ -499,7 +557,7 @@ public class ThermalManagerServiceTest { } // Helper function to hold mSamples lock, avoid GuardedBy lint errors - private boolean isWatcherSamplesEmpty(ThermalManagerService.TemperatureWatcher watcher) { + private boolean isWatcherSamplesEmpty(TemperatureWatcher watcher) { synchronized (watcher.mSamples) { return watcher.mSamples.isEmpty(); } diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java index 13a045858ab1..f3dfcd7db8e3 100644 --- a/telecomm/java/android/telecom/InCallService.java +++ b/telecomm/java/android/telecom/InCallService.java @@ -384,8 +384,14 @@ public abstract class InCallService extends Service { /** Manages the binder calls so that the implementor does not need to deal with it. */ private final class InCallServiceBinder extends IInCallService.Stub { + private boolean mInCallAdapterSet; @Override public void setInCallAdapter(IInCallAdapter inCallAdapter) { + if (mInCallAdapterSet) { + Log.i(this, "setInCallAdapter: InCallAdapter already set, skipping..."); + return; + } + mInCallAdapterSet = true; mHandler.obtainMessage(MSG_SET_IN_CALL_ADAPTER, inCallAdapter).sendToTarget(); } diff --git a/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/GraphicsActivity.java b/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/GraphicsActivity.java index ae7c2a99b808..4548a7df6874 100644 --- a/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/GraphicsActivity.java +++ b/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/GraphicsActivity.java @@ -78,14 +78,15 @@ public class GraphicsActivity extends Activity { // TODO(b/293651105): Unhardcode category fps range mapping private static final FpsRange FRAME_RATE_CATEGORY_HIGH = new FpsRange(90, 120); private static final FpsRange FRAME_RATE_CATEGORY_NORMAL = new FpsRange(60, 90); - private static final FpsRange FRAME_RATE_CATEGORY_LOW = new FpsRange(30, 60); + private static final FpsRange FRAME_RATE_CATEGORY_LOW = new FpsRange(30, 30); private DisplayManager mDisplayManager; private SurfaceView mSurfaceView; private Handler mHandler = new Handler(Looper.getMainLooper()); private final Object mLock = new Object(); private Surface mSurface = null; - private float mDeviceFrameRate; + private float mDisplayModeRefreshRate; + private float mDisplayRefreshRate; private ModeChangedEvents mModeChangedEvents = new ModeChangedEvents(); private enum ActivityState { RUNNING, PAUSED, DESTROYED } @@ -123,14 +124,20 @@ public class GraphicsActivity extends Activity { return; } synchronized (mLock) { - Display.Mode mode = mDisplayManager.getDisplay(displayId).getMode(); + Display display = mDisplayManager.getDisplay(displayId); + Display.Mode mode = display.getMode(); mModeChangedEvents.add(mode); - float frameRate = mode.getRefreshRate(); - if (frameRate != mDeviceFrameRate) { + float displayModeRefreshRate = mode.getRefreshRate(); + float displayRefreshRate = display.getRefreshRate(); + if (displayModeRefreshRate != mDisplayModeRefreshRate + || displayRefreshRate != mDisplayRefreshRate) { Log.i(TAG, - String.format("Frame rate changed: %.2f --> %.2f", mDeviceFrameRate, - frameRate)); - mDeviceFrameRate = frameRate; + String.format("Refresh rate changed: (mode) %.2f --> %.2f, " + + "(display) %.2f --> %.2f", + mDisplayModeRefreshRate, displayModeRefreshRate, + mDisplayRefreshRate, displayRefreshRate)); + mDisplayModeRefreshRate = displayModeRefreshRate; + mDisplayRefreshRate = displayRefreshRate; mLock.notify(); } } @@ -317,8 +324,10 @@ public class GraphicsActivity extends Activity { super.onCreate(savedInstanceState); synchronized (mLock) { mDisplayManager = getSystemService(DisplayManager.class); - Display.Mode mode = getDisplay().getMode(); - mDeviceFrameRate = mode.getRefreshRate(); + Display display = getDisplay(); + Display.Mode mode = display.getMode(); + mDisplayModeRefreshRate = mode.getRefreshRate(); + mDisplayRefreshRate = display.getRefreshRate(); // Insert the initial mode so we have the full display mode history. mModeChangedEvents.add(mode); mDisplayManager.registerDisplayListener(mDisplayListener, mHandler); @@ -516,22 +525,25 @@ public class GraphicsActivity extends Activity { if (expectedFrameRate > FRAME_RATE_TOLERANCE) { // expectedFrameRate > 0 // Wait until we switch to a compatible frame rate. Log.i(TAG, - "Verifying expected frame rate: actual (device)=" + mDeviceFrameRate - + " expected=" + expectedFrameRate); + String.format( + "Verifying expected frame rate: actual=%.2f, expected=%.2f", + multiplesAllowed ? mDisplayModeRefreshRate : mDisplayRefreshRate, + expectedFrameRate)); if (multiplesAllowed) { - while (!isFrameRateMultiple(mDeviceFrameRate, expectedFrameRate) + while (!isFrameRateMultiple(mDisplayModeRefreshRate, expectedFrameRate) && !waitForEvents(gracePeriodEndTimeNanos, surfaces)) { // Empty } } else { - while (!frameRateEquals(mDeviceFrameRate, expectedFrameRate) + while (!frameRateEquals(mDisplayRefreshRate, expectedFrameRate) && !waitForEvents(gracePeriodEndTimeNanos, surfaces)) { // Empty } } nowNanos = System.nanoTime(); if (nowNanos >= gracePeriodEndTimeNanos) { - throw new FrameRateTimeoutException(expectedFrameRate, mDeviceFrameRate); + throw new FrameRateTimeoutException(expectedFrameRate, + multiplesAllowed ? mDisplayModeRefreshRate : mDisplayRefreshRate); } } @@ -541,7 +553,10 @@ public class GraphicsActivity extends Activity { while (endTimeNanos > nowNanos) { int numModeChangedEvents = mModeChangedEvents.size(); if (waitForEvents(endTimeNanos, surfaces)) { - Log.i(TAG, String.format("Stable frame rate %.2f verified", mDeviceFrameRate)); + Log.i(TAG, + String.format("Stable frame rate %.2f verified", + multiplesAllowed ? mDisplayModeRefreshRate + : mDisplayRefreshRate)); return; } nowNanos = System.nanoTime(); diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java index 12c7841556fc..4a3a79803b65 100644 --- a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java +++ b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java @@ -286,11 +286,15 @@ public class Parcel_host { } public static byte[] nativeReadBlob(long nativePtr) { + var p = getInstance(nativePtr); + if (p.mSize - p.mPos < 4) { + // Match native impl that returns "null" when not enough data + return null; + } final var size = nativeReadInt(nativePtr); if (size == -1) { return null; } - var p = getInstance(nativePtr); try { p.ensureDataAvailable(align4(size)); } catch (Exception e) { |