summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Ravenwood.bp1
-rw-r--r--core/api/current.txt1
-rw-r--r--core/java/android/content/ClipData.java10
-rw-r--r--core/java/android/content/ClipDescription.java1
-rw-r--r--core/java/android/content/ComponentName.java1
-rw-r--r--core/java/android/content/ContentUris.java1
-rw-r--r--core/java/android/content/ContentValues.java1
-rw-r--r--core/java/android/content/Intent.java10
-rw-r--r--core/java/android/content/IntentFilter.java1
-rw-r--r--core/java/android/content/TEST_MAPPING8
-rw-r--r--core/java/android/content/UriMatcher.java1
-rw-r--r--core/java/android/credentials/flags.aconfig7
-rw-r--r--core/java/android/os/IThermalService.aidl5
-rw-r--r--core/java/android/os/PowerManager.java64
-rw-r--r--core/java/android/os/TEST_MAPPING6
-rw-r--r--core/java/android/os/flags.aconfig7
-rw-r--r--core/java/android/permission/flags.aconfig1
-rw-r--r--core/java/android/util/TEST_MAPPING6
-rw-r--r--core/java/android/util/proto/TEST_MAPPING6
-rw-r--r--core/java/android/view/ViewConfiguration.java12
-rw-r--r--core/java/android/view/ViewRootImpl.java5
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java3
-rw-r--r--core/jni/android_media_AudioRecord.cpp5
-rw-r--r--keystore/java/android/security/AndroidKeyStoreMaintenance.java48
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/pip/Android.bp4
-rw-r--r--libs/WindowManager/Shell/tests/flicker/pip/csuiteDefaultTemplate.xml4
-rw-r--r--libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt2
-rw-r--r--media/java/android/media/AudioRecord.java13
-rw-r--r--native/android/TEST_MAPPING10
-rw-r--r--native/android/libandroid.map.txt2
-rw-r--r--native/android/tests/thermal/Android.bp65
-rw-r--r--native/android/tests/thermal/NativeThermalUnitTest.cpp158
-rw-r--r--native/android/tests/thermal/OWNERS1
-rw-r--r--native/android/thermal.cpp124
-rw-r--r--packages/SystemUI/src/com/android/keyguard/logging/ScrimLogger.kt63
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/ConditionalRestarter.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/Flags.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepository.kt62
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/ScrimLog.kt22
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt32
-rw-r--r--packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/kotlin/CoroutinesModule.kt55
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt4
-rw-r--r--ravenwood/framework-minus-apex-ravenwood-policies.txt12
-rw-r--r--ravenwood/ravenwood-annotation-allowed-classes.txt10
-rw-r--r--services/core/java/com/android/server/appop/AppOpsService.java188
-rw-r--r--services/core/java/com/android/server/display/ColorFade.java33
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerState.java4
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsService.java153
-rw-r--r--services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java13
-rw-r--r--services/core/java/com/android/server/power/ThermalManagerService.java85
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp9
-rw-r--r--services/tests/displayservicetests/Android.bp11
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/DisplayPowerStateTest.kt51
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java82
-rw-r--r--telecomm/java/android/telecom/InCallService.java6
-rw-r--r--tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/GraphicsActivity.java47
-rw-r--r--tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java6
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) {