Merge "replace the hardcode for min/max sample rate with audio.h in jni" into main
diff --git a/api/coverage/tools/ExtractFlaggedApis.kt b/api/coverage/tools/ExtractFlaggedApis.kt
index 5efda98..bf67187 100644
--- a/api/coverage/tools/ExtractFlaggedApis.kt
+++ b/api/coverage/tools/ExtractFlaggedApis.kt
@@ -75,10 +75,10 @@
fun getClassFlag(classItem: ClassItem): String? {
var classFlag = getFlagAnnotation(classItem)
var cur = classItem
- // If a class is not an inner class, use its @FlaggedApi annotation value.
+ // If a class is not a nested class, use its @FlaggedApi annotation value.
// Otherwise, use the flag value of the closest outer class that is annotated by @FlaggedApi.
- while (cur.isInnerClass() && classFlag == null) {
- cur = cur.parent() as ClassItem
+ while (classFlag == null) {
+ cur = cur.containingClass() ?: break
classFlag = getFlagAnnotation(cur)
}
return classFlag
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 5aa89b9..805cfb7 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -3738,6 +3738,7 @@
method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public android.content.Intent registerReceiverForAllUsers(@Nullable android.content.BroadcastReceiver, @NonNull android.content.IntentFilter, @Nullable String, @Nullable android.os.Handler, int);
method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public abstract void sendBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, @Nullable String, @Nullable android.os.Bundle);
method public void sendBroadcastMultiplePermissions(@NonNull android.content.Intent, @NonNull String[], @Nullable android.app.BroadcastOptions);
+ method @FlaggedApi("android.os.ordered_broadcast_multiple_permissions") public void sendOrderedBroadcastMultiplePermissions(@NonNull android.content.Intent, @NonNull String[], @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle, @Nullable android.os.Bundle);
method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public void startActivityAsUser(@NonNull @RequiresPermission android.content.Intent, @NonNull android.os.UserHandle);
method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public void startActivityAsUser(@NonNull @RequiresPermission android.content.Intent, @Nullable android.os.Bundle, @NonNull android.os.UserHandle);
field public static final String AMBIENT_CONTEXT_SERVICE = "ambient_context";
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index af56cb4..d1bd88c 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1524,6 +1524,17 @@
public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
String receiverPermission, int appOp, Bundle options, BroadcastReceiver resultReceiver,
Handler scheduler, int initialCode, String initialData, Bundle initialExtras) {
+ String[] receiverPermissions = receiverPermission == null ? null
+ : new String[] {receiverPermission};
+ sendOrderedBroadcastAsUserMultiplePermissions(intent, user, receiverPermissions, appOp,
+ options, resultReceiver, scheduler, initialCode, initialData, initialExtras);
+ }
+
+ @Override
+ public void sendOrderedBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
+ String[] receiverPermissions, int appOp, Bundle options,
+ BroadcastReceiver resultReceiver, Handler scheduler, int initialCode,
+ String initialData, Bundle initialExtras) {
IIntentReceiver rd = null;
if (resultReceiver != null) {
if (mPackageInfo != null) {
@@ -1543,8 +1554,6 @@
}
}
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
- String[] receiverPermissions = receiverPermission == null ? null
- : new String[] {receiverPermission};
try {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
@@ -1571,6 +1580,20 @@
}
@Override
+ public void sendOrderedBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions,
+ String receiverAppOp, BroadcastReceiver resultReceiver, Handler scheduler,
+ int initialCode, String initialData, @Nullable Bundle initialExtras,
+ @Nullable Bundle options) {
+ int intAppOp = AppOpsManager.OP_NONE;
+ if (!TextUtils.isEmpty(receiverAppOp)) {
+ intAppOp = AppOpsManager.strOpToOp(receiverAppOp);
+ }
+ sendOrderedBroadcastAsUserMultiplePermissions(intent, getUser(), receiverPermissions,
+ intAppOp, options, resultReceiver, scheduler, initialCode, initialData,
+ initialExtras);
+ }
+
+ @Override
public void sendOrderedBroadcast(Intent intent, int initialCode, String receiverPermission,
String receiverAppOp, BroadcastReceiver resultReceiver, Handler scheduler,
String initialData, @Nullable Bundle initialExtras, Bundle options) {
diff --git a/core/java/android/app/admin/OWNERS b/core/java/android/app/admin/OWNERS
index 308f1d6..4f3f5d9 100644
--- a/core/java/android/app/admin/OWNERS
+++ b/core/java/android/app/admin/OWNERS
@@ -1,7 +1,6 @@
# Bug component: 142675
# Assign bugs to device-policy-manager-triage@google.com
-file:WorkDeviceExperience_OWNERS
file:EnterprisePlatformSecurity_OWNERS
yamasani@google.com #{LAST_RESORT_SUGGESTION}
\ No newline at end of file
diff --git a/core/java/android/app/assist/OWNERS b/core/java/android/app/assist/OWNERS
index e4ffd7f..b53bdc2 100644
--- a/core/java/android/app/assist/OWNERS
+++ b/core/java/android/app/assist/OWNERS
@@ -1,2 +1 @@
-hackz@google.com
-volnov@google.com
\ No newline at end of file
+srazdan@google.com
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index a6eed50..b121da3 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2916,6 +2916,23 @@
@Nullable String initialData, @Nullable Bundle initialExtras);
/**
+ * Similar to above but takes array of names of permissions that a receiver must hold in order
+ * to receive your broadcast. If empty, no permissions are required.
+ *
+ * @see #sendOrderedBroadcastAsUser(Intent, UserHandle, String,
+ * BroadcastReceiver, Handler, int, String, Bundle)
+ * @hide
+ */
+ @SuppressWarnings("HiddenAbstractMethod")
+ @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
+ public void sendOrderedBroadcastAsUserMultiplePermissions(Intent intent,
+ UserHandle user, String[] receiverPermissions, int appOp, Bundle options,
+ BroadcastReceiver resultReceiver, Handler scheduler, int initialCode,
+ String initialData, Bundle initialExtras) {
+ throw new RuntimeException("Not implemented. Must override in a subclass.");
+ }
+
+ /**
* Version of
* {@link #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String,
* Bundle)} that allows you to specify the App Op to enforce restrictions on which receivers
@@ -2997,6 +3014,21 @@
}
/**
+ * Like {@link #sendOrderedBroadcast(Intent, String, String, BroadcastReceiver, Handler, int,
+ * String, Bundle)}, but also allows specification of a list of multiple permissions.
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_ORDERED_BROADCAST_MULTIPLE_PERMISSIONS)
+ @SystemApi
+ public void sendOrderedBroadcastMultiplePermissions(
+ @NonNull Intent intent, @NonNull String[] receiverPermissions,
+ @Nullable String receiverAppOp, @Nullable BroadcastReceiver resultReceiver,
+ @Nullable Handler scheduler, int initialCode, @Nullable String initialData,
+ @Nullable Bundle initialExtras, @Nullable Bundle options) {
+ throw new RuntimeException("Not implemented. Must override in a subclass.");
+ }
+
+ /**
* <p>Perform a {@link #sendBroadcast(Intent)} that is "sticky," meaning the
* Intent you are sending stays around after the broadcast is complete,
* so that others can quickly retrieve that data through the return
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index a475c29..79fa6ea 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -652,6 +652,16 @@
resultReceiver, scheduler, initialCode, initialData, initialExtras);
}
+ /** @hide */
+ @Override
+ public void sendOrderedBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
+ @Nullable String[] receiverPermission, int appOp, @Nullable Bundle options,
+ @Nullable BroadcastReceiver resultReceiver, @Nullable Handler scheduler,
+ int initialCode, @Nullable String initialData, @Nullable Bundle initialExtras) {
+ mBase.sendOrderedBroadcastAsUserMultiplePermissions(intent, user, receiverPermission, appOp,
+ options, resultReceiver, scheduler, initialCode, initialData, initialExtras);
+ }
+
@Override
public void sendOrderedBroadcast(@RequiresPermission @NonNull Intent intent,
@Nullable String receiverPermission, @Nullable String receiverAppOp,
@@ -661,6 +671,17 @@
scheduler, initialCode, initialData, initialExtras);
}
+ /** @hide */
+ @Override
+ public void sendOrderedBroadcastMultiplePermissions(
+ @NonNull Intent intent, @NonNull String[] receiverPermissions,
+ @Nullable String receiverAppOp, @Nullable BroadcastReceiver resultReceiver,
+ @Nullable Handler scheduler, int initialCode, @Nullable String initialData,
+ @Nullable Bundle initialExtras, @Nullable Bundle options) {
+ mBase.sendOrderedBroadcastMultiplePermissions(intent, receiverPermissions, receiverAppOp,
+ resultReceiver, scheduler, initialCode, initialData, initialExtras, options);
+ }
+
@Override
public void sendOrderedBroadcast(@RequiresPermission @NonNull Intent intent, int initialCode,
@Nullable String receiverPermission, @Nullable String receiverAppOp,
diff --git a/core/java/android/hardware/OWNERS b/core/java/android/hardware/OWNERS
index 51ad151..43d3f54 100644
--- a/core/java/android/hardware/OWNERS
+++ b/core/java/android/hardware/OWNERS
@@ -5,7 +5,7 @@
sumir@google.com
# Camera
-per-file *Camera*=cychen@google.com,epeev@google.com,etalvala@google.com,shuzhenwang@google.com,zhijunhe@google.com,jchowdhary@google.com
+per-file *Camera*=file:platform/frameworks/av:/camera/OWNERS
# Sensor Privacy
per-file *SensorPrivacy* = file:platform/frameworks/native:/libs/sensorprivacy/OWNERS
diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig
index ca69457..200c1d8 100644
--- a/core/java/android/os/flags.aconfig
+++ b/core/java/android/os/flags.aconfig
@@ -68,6 +68,14 @@
}
flag {
+ name: "ordered_broadcast_multiple_permissions"
+ is_exported: true
+ namespace: "bluetooth"
+ description: "Guards the Context.sendOrderedBroadcastMultiplePermissions API"
+ bug: "345802719"
+}
+
+flag {
name: "battery_saver_supported_check_api"
namespace: "backstage_power"
description: "Guards a new API in PowerManager to check if battery saver is supported or not."
diff --git a/core/java/android/view/autofill/OWNERS b/core/java/android/view/autofill/OWNERS
index 898947a..7f3b4e5 100644
--- a/core/java/android/view/autofill/OWNERS
+++ b/core/java/android/view/autofill/OWNERS
@@ -1,10 +1,11 @@
# Bug component: 351486
-simranjit@google.com
haoranzhang@google.com
+jiewenlei@google.com
+simranjit@google.com
skxu@google.com
+shuc@google.com
yunicorn@google.com
-reemabajwa@google.com
# Bug component: 543785 = per-file *Augmented*
per-file *Augmented* = wangqi@google.com
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index 8236783..511c680 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -109,4 +109,5 @@
boolean isWeakEscrowTokenActive(long handle, int userId);
boolean isWeakEscrowTokenValid(long handle, in byte[] token, int userId);
void unlockUserKeyIfUnsecured(int userId);
+ boolean writeRepairModeCredential(int userId);
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index e46b8d7..f4ad487 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -449,6 +449,21 @@
}
/**
+ * Save the current password data to the repair mode file.
+ *
+ * @return true if success or false otherwise.
+ */
+ public boolean writeRepairModeCredential(int userId) {
+ throwIfCalledOnMainThread();
+ try {
+ return getLockSettings().writeRepairModeCredential(userId);
+ } catch (RemoteException re) {
+ Log.e(TAG, "Failed to write repair mode credential", re);
+ return false;
+ }
+ }
+
+ /**
* Check to see if a credential matches the saved one.
* If credential matches, return an opaque attestation that the challenge was verified.
*
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index 0734e68..11c220b 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -261,6 +261,8 @@
public float lineEndY = Float.MIN_VALUE;
@Nullable
Animator activationAnimator;
+ @Nullable
+ Animator deactivationAnimator;
}
/**
@@ -667,7 +669,7 @@
*/
private void resetPattern() {
if (mKeepDotActivated && !mPattern.isEmpty()) {
- resetLastActivatedCellProgress();
+ resetPatternCellSize();
}
mPattern.clear();
mPatternPath.reset();
@@ -676,14 +678,20 @@
invalidate();
}
- private void resetLastActivatedCellProgress() {
- final ArrayList<Cell> pattern = mPattern;
- final Cell lastCell = pattern.get(pattern.size() - 1);
- final CellState cellState = mCellStates[lastCell.row][lastCell.column];
- if (cellState.activationAnimator != null) {
- cellState.activationAnimator.cancel();
+ private void resetPatternCellSize() {
+ for (int i = 0; i < mCellStates.length; i++) {
+ for (int j = 0; j < mCellStates[i].length; j++) {
+ CellState cellState = mCellStates[i][j];
+ if (cellState.activationAnimator != null) {
+ cellState.activationAnimator.cancel();
+ }
+ if (cellState.deactivationAnimator != null) {
+ cellState.deactivationAnimator.cancel();
+ }
+ cellState.activationAnimationProgress = 0f;
+ cellState.radius = mDotSize / 2f;
+ }
}
- cellState.activationAnimationProgress = 0f;
}
/**
@@ -819,12 +827,16 @@
!mPatternDrawLookup[fillInGapCell.row][fillInGapCell.column]) {
addCellToPattern(fillInGapCell);
if (mKeepDotActivated) {
- startCellDeactivatedAnimation(fillInGapCell);
+ if (mFadePattern) {
+ startCellDeactivatedAnimation(fillInGapCell, /* fillInGap= */ true);
+ } else {
+ startCellActivatedAnimation(fillInGapCell);
+ }
}
}
if (mKeepDotActivated && lastCell != null) {
- startCellDeactivatedAnimation(lastCell);
+ startCellDeactivatedAnimation(lastCell, /* fillInGap= */ false);
}
addCellToPattern(cell);
@@ -872,17 +884,25 @@
}
private void startCellActivatedAnimation(Cell cell) {
- startCellActivationAnimation(cell, CELL_ACTIVATE);
+ startCellActivationAnimation(cell, CELL_ACTIVATE, /* fillInGap= */ false);
}
- private void startCellDeactivatedAnimation(Cell cell) {
- startCellActivationAnimation(cell, CELL_DEACTIVATE);
+ private void startCellDeactivatedAnimation(Cell cell, boolean fillInGap) {
+ startCellActivationAnimation(cell, CELL_DEACTIVATE, /* fillInGap= */ fillInGap);
}
- private void startCellActivationAnimation(Cell cell, int activate) {
+ /**
+ * Start cell animation.
+ * @param cell The cell to be animated.
+ * @param activate Whether the cell is being activated or deactivated.
+ * @param fillInGap Whether the cell is a gap cell, i.e. filled in based on current pattern.
+ */
+ private void startCellActivationAnimation(Cell cell, int activate, boolean fillInGap) {
final CellState cellState = mCellStates[cell.row][cell.column];
- if (cellState.activationAnimator != null) {
+ // When mKeepDotActivated is true, don't cancel the previous animator since it would leave
+ // a dot in an in-between size if the next dot is reached before the animation is finished.
+ if (cellState.activationAnimator != null && !mKeepDotActivated) {
cellState.activationAnimator.cancel();
}
AnimatorSet animatorSet = new AnimatorSet();
@@ -898,24 +918,37 @@
.with(createLineEndAnimation(cellState, startX, startY,
getCenterXForColumn(cell.column), getCenterYForRow(cell.row)));
if (mDotSize != mDotSizeActivated) {
- animatorSetBuilder.with(createDotRadiusAnimation(cellState));
+ animatorSetBuilder.with(createDotRadiusAnimation(cellState, activate, fillInGap));
}
if (mDotColor != mDotActivatedColor) {
- animatorSetBuilder.with(createDotActivationColorAnimation(cellState, activate));
+ animatorSetBuilder.with(
+ createDotActivationColorAnimation(cellState, activate, fillInGap));
}
- animatorSet.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- cellState.activationAnimator = null;
- invalidate();
- }
- });
- cellState.activationAnimator = animatorSet;
+ if (activate == CELL_ACTIVATE) {
+ animatorSet.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ cellState.activationAnimator = null;
+ invalidate();
+ }
+ });
+ cellState.activationAnimator = animatorSet;
+ } else {
+ animatorSet.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ cellState.deactivationAnimator = null;
+ invalidate();
+ }
+ });
+ cellState.deactivationAnimator = animatorSet;
+ }
animatorSet.start();
}
- private Animator createDotActivationColorAnimation(CellState cellState, int activate) {
+ private Animator createDotActivationColorAnimation(
+ CellState cellState, int activate, boolean fillInGap) {
ValueAnimator.AnimatorUpdateListener updateListener =
valueAnimator -> {
cellState.activationAnimationProgress =
@@ -934,7 +967,7 @@
deactivateAnimator.setDuration(DOT_ACTIVATION_DURATION_MILLIS);
AnimatorSet set = new AnimatorSet();
- if (mKeepDotActivated) {
+ if (mKeepDotActivated && !fillInGap) {
set.play(activate == CELL_ACTIVATE ? activateAnimator : deactivateAnimator);
} else {
// 'activate' ignored in this case, do full deactivate -> activate cycle
@@ -977,7 +1010,7 @@
return valueAnimator;
}
- private Animator createDotRadiusAnimation(CellState state) {
+ private Animator createDotRadiusAnimation(CellState state, int activate, boolean fillInGap) {
float defaultRadius = mDotSize / 2f;
float activatedRadius = mDotSizeActivated / 2f;
@@ -998,7 +1031,19 @@
deactivationAnimator.setDuration(DOT_RADIUS_DECREASE_DURATION_MILLIS);
AnimatorSet set = new AnimatorSet();
- set.playSequentially(activationAnimator, deactivationAnimator);
+ if (mKeepDotActivated) {
+ if (mFadePattern) {
+ if (fillInGap) {
+ set.playSequentially(activationAnimator, deactivationAnimator);
+ } else {
+ set.play(activate == CELL_ACTIVATE ? activationAnimator : deactivationAnimator);
+ }
+ } else if (activate == CELL_ACTIVATE) {
+ set.play(activationAnimator);
+ }
+ } else {
+ set.playSequentially(activationAnimator, deactivationAnimator);
+ }
return set;
}
@@ -1176,9 +1221,15 @@
// report pattern detected
if (!mPattern.isEmpty()) {
setPatternInProgress(false);
- cancelLineAnimations();
if (mKeepDotActivated) {
+ // When mKeepDotActivated is true, cancelling dot animations and resetting dot radii
+ // are handled in #resetPattern(), since we want to keep the dots activated until
+ // the pattern are reset.
deactivateLastCell();
+ } else {
+ // When mKeepDotActivated is false, cancelling animations and resetting dot radii
+ // are handled here.
+ cancelLineAnimations();
}
notifyPatternDetected();
// Also clear pattern if fading is enabled
@@ -1198,7 +1249,7 @@
private void deactivateLastCell() {
Cell lastCell = mPattern.get(mPattern.size() - 1);
- startCellDeactivatedAnimation(lastCell);
+ startCellDeactivatedAnimation(lastCell, /* fillInGap= */ false);
}
private void cancelLineAnimations() {
diff --git a/core/java/com/android/internal/widget/OWNERS b/core/java/com/android/internal/widget/OWNERS
index e2672f5..cf2f202 100644
--- a/core/java/com/android/internal/widget/OWNERS
+++ b/core/java/com/android/internal/widget/OWNERS
@@ -9,18 +9,18 @@
per-file *LockSettings* = file:/services/core/java/com/android/server/locksettings/OWNERS
# Notification related
-per-file *Notification* = file:/services/core/java/com/android/server/notification/OWNERS
-per-file *Messaging* = file:/services/core/java/com/android/server/notification/OWNERS
-per-file *Message* = file:/services/core/java/com/android/server/notification/OWNERS
-per-file *Conversation* = file:/services/core/java/com/android/server/notification/OWNERS
-per-file *People* = file:/services/core/java/com/android/server/notification/OWNERS
-per-file *ImageResolver* = file:/services/core/java/com/android/server/notification/OWNERS
-per-file CallLayout.java = file:/services/core/java/com/android/server/notification/OWNERS
-per-file CachingIconView.java = file:/services/core/java/com/android/server/notification/OWNERS
-per-file ImageFloatingTextView.java = file:/services/core/java/com/android/server/notification/OWNERS
-per-file ObservableTextView.java = file:/services/core/java/com/android/server/notification/OWNERS
-per-file RemeasuringLinearLayout.java = file:/services/core/java/com/android/server/notification/OWNERS
-per-file ViewClippingUtil.java = file:/services/core/java/com/android/server/notification/OWNERS
+per-file *Notification* = file:/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS
+per-file *Messaging* = file:/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS
+per-file *Message* = file:/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS
+per-file *Conversation* = file:/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS
+per-file *People* = file:/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS
+per-file *ImageResolver* = file:/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS
+per-file CallLayout.java = file:/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS
+per-file CachingIconView.java = file:/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS
+per-file ImageFloatingTextView.java = file:/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS
+per-file ObservableTextView.java = file:/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS
+per-file RemeasuringLinearLayout.java = file:/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS
+per-file ViewClippingUtil.java = file:/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS
# Appwidget related
per-file *RemoteViews* = file:/services/appwidget/java/com/android/server/appwidget/OWNERS
diff --git a/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java b/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java
index b90480a..92a7d8e 100644
--- a/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java
@@ -68,6 +68,7 @@
import java.nio.charset.StandardCharsets;
import java.util.List;
+import java.util.concurrent.CompletableFuture;
@RunWith(AndroidJUnit4.class)
@SmallTest
@@ -316,6 +317,40 @@
assertNotEquals(UserHandle.USER_CURRENT_OR_SELF, LockPatternUtils.USER_REPAIR_MODE);
}
+ @Test
+ public void testWriteRepairModeCredential_mainThread() {
+ createTestLockSettings();
+ var context = InstrumentationRegistry.getTargetContext();
+
+ var future = new CompletableFuture<Exception>();
+ context.getMainThreadHandler().post(() -> {
+ try {
+ mLockPatternUtils.writeRepairModeCredential(USER_ID);
+ future.complete(null);
+ } catch (Exception e) {
+ future.complete(e);
+ }
+ });
+
+ var e = future.join();
+ assertThat(e).isNotNull();
+ assertThat(e.getMessage()).contains("should not be called from the main thread");
+ }
+
+ @Test
+ public void testWriteRepairModeCredential() throws Exception {
+ var ils = createTestLockSettings();
+
+ when(ils.writeRepairModeCredential(USER_ID)).thenReturn(false);
+ assertThat(mLockPatternUtils.writeRepairModeCredential(USER_ID)).isFalse();
+
+ when(ils.writeRepairModeCredential(USER_ID)).thenReturn(true);
+ assertThat(mLockPatternUtils.writeRepairModeCredential(USER_ID)).isTrue();
+
+ when(ils.writeRepairModeCredential(USER_ID)).thenThrow(new RemoteException());
+ assertThat(mLockPatternUtils.writeRepairModeCredential(USER_ID)).isFalse();
+ }
+
private TestStrongAuthTracker createStrongAuthTracker() {
final Context context = new ContextWrapper(InstrumentationRegistry.getTargetContext());
return new TestStrongAuthTracker(context, Looper.getMainLooper());
diff --git a/data/etc/OWNERS b/data/etc/OWNERS
index 701d145..85dae63 100644
--- a/data/etc/OWNERS
+++ b/data/etc/OWNERS
@@ -1,6 +1,5 @@
include /PACKAGE_MANAGER_OWNERS
-alanstokes@google.com
cbrubaker@google.com
hackbod@android.com
hackbod@google.com
diff --git a/libs/WindowManager/Shell/OWNERS b/libs/WindowManager/Shell/OWNERS
index ebebd8a..cb422ea 100644
--- a/libs/WindowManager/Shell/OWNERS
+++ b/libs/WindowManager/Shell/OWNERS
@@ -1,5 +1,5 @@
xutan@google.com
# Give submodule owners in shell resource approval
-per-file res*/*/*.xml = atsjenk@google.com, hwwang@google.com, jorgegil@google.com, lbill@google.com, madym@google.com, nmusgrave@google.com, pbdr@google.com, tkachenkoi@google.com, mpodolian@google.com, liranb@google.com
+per-file res*/*/*.xml = atsjenk@google.com, hwwang@google.com, jorgegil@google.com, lbill@google.com, madym@google.com, vaniadesmonda@google.com, pbdr@google.com, tkachenkoi@google.com, mpodolian@google.com, liranb@google.com
per-file res*/*/tv_*.xml = bronger@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/util/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/util/OWNERS
new file mode 100644
index 0000000..482aaab
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/util/OWNERS
@@ -0,0 +1 @@
+per-file KtProtolog.kt = file:platform/development:/tools/winscope/OWNERS
diff --git a/libs/WindowManager/Shell/tests/OWNERS b/libs/WindowManager/Shell/tests/OWNERS
index 0f24bb5..2a0a28e 100644
--- a/libs/WindowManager/Shell/tests/OWNERS
+++ b/libs/WindowManager/Shell/tests/OWNERS
@@ -9,7 +9,7 @@
chenghsiuchang@google.com
atsjenk@google.com
jorgegil@google.com
-nmusgrave@google.com
+vaniadesmonda@google.com
pbdr@google.com
tkachenkoi@google.com
mpodolian@google.com
diff --git a/location/Android.bp b/location/Android.bp
index 7f3442c..10ca97d 100644
--- a/location/Android.bp
+++ b/location/Android.bp
@@ -30,9 +30,6 @@
"app-compat-annotations",
"unsupportedappusage", // for android.compat.annotation.UnsupportedAppUsage
],
- hidden_api_packages: [
- "com.android.internal.location",
- ],
aidl: {
include_dirs: [
"frameworks/base/location/java",
diff --git a/location/java/com/android/internal/location/package-info.java b/location/java/com/android/internal/location/package-info.java
new file mode 100644
index 0000000..25573c1
--- /dev/null
+++ b/location/java/com/android/internal/location/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+/**
+ * Exclude from API surfaces
+ *
+ * @hide
+ */
+package com.android.internal.location;
diff --git a/nfc/Android.bp b/nfc/Android.bp
index 421f06d..2a01b3f 100644
--- a/nfc/Android.bp
+++ b/nfc/Android.bp
@@ -59,9 +59,6 @@
"android.nfc",
"com.android.nfc",
],
- hidden_api_packages: [
- "com.android.nfc",
- ],
impl_library_visibility: [
"//frameworks/base:__subpackages__",
"//cts/tests/tests/nfc",
diff --git a/services/core/java/com/android/server/CertBlacklister.java b/services/core/java/com/android/server/CertBlacklister.java
deleted file mode 100644
index e726c6a..0000000
--- a/services/core/java/com/android/server/CertBlacklister.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import android.content.Context;
-import android.content.ContentResolver;
-import android.database.ContentObserver;
-import android.os.Binder;
-import android.os.FileUtils;
-import android.provider.Settings;
-import android.util.Slog;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-import libcore.io.IoUtils;
-
-/**
- * <p>CertBlacklister provides a simple mechanism for updating the platform denylists for SSL
- * certificate public keys and serial numbers.
- */
-public class CertBlacklister extends Binder {
-
- private static final String TAG = "CertBlacklister";
-
- private static final String DENYLIST_ROOT = System.getenv("ANDROID_DATA") + "/misc/keychain/";
-
- public static final String PUBKEY_PATH = DENYLIST_ROOT + "pubkey_blacklist.txt";
- public static final String SERIAL_PATH = DENYLIST_ROOT + "serial_blacklist.txt";
-
- public static final String PUBKEY_BLACKLIST_KEY = "pubkey_blacklist";
- public static final String SERIAL_BLACKLIST_KEY = "serial_blacklist";
-
- private static class BlacklistObserver extends ContentObserver {
-
- private final String mKey;
- private final String mName;
- private final String mPath;
- private final File mTmpDir;
- private final ContentResolver mContentResolver;
-
- public BlacklistObserver(String key, String name, String path, ContentResolver cr) {
- super(null);
- mKey = key;
- mName = name;
- mPath = path;
- mTmpDir = new File(mPath).getParentFile();
- mContentResolver = cr;
- }
-
- @Override
- public void onChange(boolean selfChange) {
- super.onChange(selfChange);
- writeDenylist();
- }
-
- public String getValue() {
- return Settings.Secure.getString(mContentResolver, mKey);
- }
-
- private void writeDenylist() {
- new Thread("BlacklistUpdater") {
- public void run() {
- synchronized(mTmpDir) {
- String blacklist = getValue();
- if (blacklist != null) {
- Slog.i(TAG, "Certificate blacklist changed, updating...");
- FileOutputStream out = null;
- try {
- // create a temporary file
- File tmp = File.createTempFile("journal", "", mTmpDir);
- // mark it -rw-r--r--
- tmp.setReadable(true, false);
- // write to it
- out = new FileOutputStream(tmp);
- out.write(blacklist.getBytes());
- // sync to disk
- FileUtils.sync(out);
- // atomic rename
- tmp.renameTo(new File(mPath));
- Slog.i(TAG, "Certificate blacklist updated");
- } catch (IOException e) {
- Slog.e(TAG, "Failed to write blacklist", e);
- } finally {
- IoUtils.closeQuietly(out);
- }
- }
- }
- }
- }.start();
- }
- }
-
- public CertBlacklister(Context context) {
- registerObservers(context.getContentResolver());
- }
-
- private BlacklistObserver buildPubkeyObserver(ContentResolver cr) {
- return new BlacklistObserver(PUBKEY_BLACKLIST_KEY,
- "pubkey",
- PUBKEY_PATH,
- cr);
- }
-
- private BlacklistObserver buildSerialObserver(ContentResolver cr) {
- return new BlacklistObserver(SERIAL_BLACKLIST_KEY,
- "serial",
- SERIAL_PATH,
- cr);
- }
-
- private void registerObservers(ContentResolver cr) {
- // set up the public key denylist observer
- cr.registerContentObserver(
- Settings.Secure.getUriFor(PUBKEY_BLACKLIST_KEY),
- true,
- buildPubkeyObserver(cr)
- );
-
- // set up the serial number denylist observer
- cr.registerContentObserver(
- Settings.Secure.getUriFor(SERIAL_BLACKLIST_KEY),
- true,
- buildSerialObserver(cr)
- );
- }
-}
diff --git a/services/core/java/com/android/server/CertBlocklister.java b/services/core/java/com/android/server/CertBlocklister.java
new file mode 100644
index 0000000..9e23f88
--- /dev/null
+++ b/services/core/java/com/android/server/CertBlocklister.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.os.Binder;
+import android.os.FileUtils;
+import android.provider.Settings;
+import android.util.Slog;
+
+import libcore.io.IoUtils;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * <p>CertBlocklister provides a simple mechanism for updating the platform denylists for SSL
+ * certificate public keys and serial numbers.
+ */
+public class CertBlocklister extends Binder {
+
+ private static final String TAG = "CertBlocklister";
+
+ private static final String DENYLIST_ROOT = System.getenv("ANDROID_DATA") + "/misc/keychain/";
+
+ /* For compatibility reasons, the name of these paths cannot be changed */
+ public static final String PUBKEY_PATH = DENYLIST_ROOT + "pubkey_blacklist.txt";
+ public static final String SERIAL_PATH = DENYLIST_ROOT + "serial_blacklist.txt";
+
+ /* For compatibility reasons, the name of these keys cannot be changed */
+ public static final String PUBKEY_BLOCKLIST_KEY = "pubkey_blacklist";
+ public static final String SERIAL_BLOCKLIST_KEY = "serial_blacklist";
+
+ private static class BlocklistObserver extends ContentObserver {
+
+ private final String mKey;
+ private final String mName;
+ private final String mPath;
+ private final File mTmpDir;
+ private final ContentResolver mContentResolver;
+
+ BlocklistObserver(String key, String name, String path, ContentResolver cr) {
+ super(null);
+ mKey = key;
+ mName = name;
+ mPath = path;
+ mTmpDir = new File(mPath).getParentFile();
+ mContentResolver = cr;
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ super.onChange(selfChange);
+ new Thread("BlocklistUpdater") {
+ public void run() {
+ writeDenylist();
+ }
+ }.start();
+ }
+
+ public String getValue() {
+ return Settings.Secure.getStringForUser(
+ mContentResolver, mKey, mContentResolver.getUserId());
+ }
+
+ private void writeDenylist() {
+ synchronized (mTmpDir) {
+ String blocklist = getValue();
+ if (blocklist == null) {
+ return;
+ }
+ if (mPath.equals(SERIAL_PATH)) {
+ Slog.w(TAG, "The certificate blocklist based on serials is deprecated. "
+ + "Please use the pubkey blocklist instead.");
+ }
+ Slog.i(TAG, "Certificate blocklist changed, updating...");
+ FileOutputStream out = null;
+ try {
+ // Create a temporary file and rename it atomically.
+ File tmp = File.createTempFile("journal", "", mTmpDir);
+ tmp.setReadable(true /* readable */, false /* ownerOnly */);
+ out = new FileOutputStream(tmp);
+ out.write(blocklist.getBytes());
+ FileUtils.sync(out);
+ tmp.renameTo(new File(mPath));
+ Slog.i(TAG, "Certificate blocklist updated");
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to write blocklist", e);
+ } finally {
+ IoUtils.closeQuietly(out);
+ }
+ }
+ }
+ }
+
+ public CertBlocklister(Context context) {
+ registerObservers(context.getContentResolver());
+ }
+
+ private BlocklistObserver buildPubkeyObserver(ContentResolver cr) {
+ return new BlocklistObserver(PUBKEY_BLOCKLIST_KEY,
+ "pubkey",
+ PUBKEY_PATH,
+ cr);
+ }
+
+ private BlocklistObserver buildSerialObserver(ContentResolver cr) {
+ return new BlocklistObserver(SERIAL_BLOCKLIST_KEY,
+ "serial",
+ SERIAL_PATH,
+ cr);
+ }
+
+ private void registerObservers(ContentResolver cr) {
+ // set up the public key denylist observer
+ cr.registerContentObserver(
+ Settings.Secure.getUriFor(PUBKEY_BLOCKLIST_KEY),
+ true,
+ buildPubkeyObserver(cr)
+ );
+
+ // set up the serial number denylist observer
+ cr.registerContentObserver(
+ Settings.Secure.getUriFor(SERIAL_BLOCKLIST_KEY),
+ true,
+ buildSerialObserver(cr)
+ );
+ }
+}
diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS
index 2545620..a627a39 100644
--- a/services/core/java/com/android/server/OWNERS
+++ b/services/core/java/com/android/server/OWNERS
@@ -48,3 +48,6 @@
# SystemConfig
per-file SystemConfig.java = file:/PACKAGE_MANAGER_OWNERS
+
+# CertBlocklister
+per-file Cert*.java = tweek@google.com, brambonne@google.com, prb@google.com, miguelaranda@google.com
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
index dfd148d..c2cb5e9 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -241,12 +241,14 @@
* opportunity to reset any settings depending on our rescue level.
*/
public static void onSettingsProviderPublished(Context context) {
- handleNativeRescuePartyResets();
- ContentResolver contentResolver = context.getContentResolver();
- DeviceConfig.setMonitorCallback(
- contentResolver,
- Executors.newSingleThreadExecutor(),
- new RescuePartyMonitorCallback(context));
+ if (!Flags.deprecateFlagsAndSettingsResets()) {
+ handleNativeRescuePartyResets();
+ ContentResolver contentResolver = context.getContentResolver();
+ DeviceConfig.setMonitorCallback(
+ contentResolver,
+ Executors.newSingleThreadExecutor(),
+ new RescuePartyMonitorCallback(context));
+ }
}
@@ -256,75 +258,81 @@
* on modules of newer versions.
*/
public static void resetDeviceConfigForPackages(List<String> packageNames) {
- if (packageNames == null) {
- return;
- }
- Set<String> namespacesToReset = new ArraySet<String>();
- Iterator<String> it = packageNames.iterator();
- RescuePartyObserver rescuePartyObserver = RescuePartyObserver.getInstanceIfCreated();
- // Get runtime package to namespace mapping if created.
- if (rescuePartyObserver != null) {
- while (it.hasNext()) {
- String packageName = it.next();
- Set<String> runtimeAffectedNamespaces =
- rescuePartyObserver.getAffectedNamespaceSet(packageName);
- if (runtimeAffectedNamespaces != null) {
- namespacesToReset.addAll(runtimeAffectedNamespaces);
+ if (!Flags.deprecateFlagsAndSettingsResets()) {
+ if (packageNames == null) {
+ return;
+ }
+ Set<String> namespacesToReset = new ArraySet<String>();
+ Iterator<String> it = packageNames.iterator();
+ RescuePartyObserver rescuePartyObserver = RescuePartyObserver.getInstanceIfCreated();
+ // Get runtime package to namespace mapping if created.
+ if (rescuePartyObserver != null) {
+ while (it.hasNext()) {
+ String packageName = it.next();
+ Set<String> runtimeAffectedNamespaces =
+ rescuePartyObserver.getAffectedNamespaceSet(packageName);
+ if (runtimeAffectedNamespaces != null) {
+ namespacesToReset.addAll(runtimeAffectedNamespaces);
+ }
}
}
- }
- // Get preset package to namespace mapping if created.
- Set<String> presetAffectedNamespaces = getPresetNamespacesForPackages(
- packageNames);
- if (presetAffectedNamespaces != null) {
- namespacesToReset.addAll(presetAffectedNamespaces);
- }
+ // Get preset package to namespace mapping if created.
+ Set<String> presetAffectedNamespaces = getPresetNamespacesForPackages(
+ packageNames);
+ if (presetAffectedNamespaces != null) {
+ namespacesToReset.addAll(presetAffectedNamespaces);
+ }
- // Clear flags under the namespaces mapped to these packages.
- // Using setProperties since DeviceConfig.resetToDefaults bans the current flag set.
- Iterator<String> namespaceIt = namespacesToReset.iterator();
- while (namespaceIt.hasNext()) {
- String namespaceToReset = namespaceIt.next();
- Properties properties = new Properties.Builder(namespaceToReset).build();
- try {
- if (!DeviceConfig.setProperties(properties)) {
- logCriticalInfo(Log.ERROR, "Failed to clear properties under "
+ // Clear flags under the namespaces mapped to these packages.
+ // Using setProperties since DeviceConfig.resetToDefaults bans the current flag set.
+ Iterator<String> namespaceIt = namespacesToReset.iterator();
+ while (namespaceIt.hasNext()) {
+ String namespaceToReset = namespaceIt.next();
+ Properties properties = new Properties.Builder(namespaceToReset).build();
+ try {
+ if (!DeviceConfig.setProperties(properties)) {
+ logCriticalInfo(Log.ERROR, "Failed to clear properties under "
+ namespaceToReset
+ ". Running `device_config get_sync_disabled_for_tests` will confirm"
+ " if config-bulk-update is enabled.");
+ }
+ } catch (DeviceConfig.BadConfigException exception) {
+ logCriticalInfo(Log.WARN, "namespace " + namespaceToReset
+ + " is already banned, skip reset.");
}
- } catch (DeviceConfig.BadConfigException exception) {
- logCriticalInfo(Log.WARN, "namespace " + namespaceToReset
- + " is already banned, skip reset.");
}
}
}
private static Set<String> getPresetNamespacesForPackages(List<String> packageNames) {
Set<String> resultSet = new ArraySet<String>();
- try {
- String flagVal = DeviceConfig.getString(NAMESPACE_CONFIGURATION,
- NAMESPACE_TO_PACKAGE_MAPPING_FLAG, "");
- String[] mappingEntries = flagVal.split(",");
- for (int i = 0; i < mappingEntries.length; i++) {
- if (TextUtils.isEmpty(mappingEntries[i])) {
- continue;
- }
- String[] splittedEntry = mappingEntries[i].split(":");
- if (splittedEntry.length != 2) {
- throw new RuntimeException("Invalid mapping entry: " + mappingEntries[i]);
- }
- String namespace = splittedEntry[0];
- String packageName = splittedEntry[1];
+ if (!Flags.deprecateFlagsAndSettingsResets()) {
+ try {
+ String flagVal = DeviceConfig.getString(NAMESPACE_CONFIGURATION,
+ NAMESPACE_TO_PACKAGE_MAPPING_FLAG, "");
+ String[] mappingEntries = flagVal.split(",");
+ for (int i = 0; i < mappingEntries.length; i++) {
+ if (TextUtils.isEmpty(mappingEntries[i])) {
+ continue;
+ }
+ String[] splitEntry = mappingEntries[i].split(":");
+ if (splitEntry.length != 2) {
+ throw new RuntimeException("Invalid mapping entry: " + mappingEntries[i]);
+ }
+ String namespace = splitEntry[0];
+ String packageName = splitEntry[1];
- if (packageNames.contains(packageName)) {
- resultSet.add(namespace);
+ if (packageNames.contains(packageName)) {
+ resultSet.add(namespace);
+ }
}
+ } catch (Exception e) {
+ resultSet.clear();
+ Slog.e(TAG, "Failed to read preset package to namespaces mapping.", e);
+ } finally {
+ return resultSet;
}
- } catch (Exception e) {
- resultSet.clear();
- Slog.e(TAG, "Failed to read preset package to namespaces mapping.", e);
- } finally {
+ } else {
return resultSet;
}
}
@@ -342,43 +350,54 @@
}
public void onNamespaceUpdate(@NonNull String updatedNamespace) {
- startObservingPackages(mContext, updatedNamespace);
+ if (!Flags.deprecateFlagsAndSettingsResets()) {
+ startObservingPackages(mContext, updatedNamespace);
+ }
}
public void onDeviceConfigAccess(@NonNull String callingPackage,
@NonNull String namespace) {
- RescuePartyObserver.getInstance(mContext).recordDeviceConfigAccess(
- callingPackage,
- namespace);
+
+ if (!Flags.deprecateFlagsAndSettingsResets()) {
+ RescuePartyObserver.getInstance(mContext).recordDeviceConfigAccess(
+ callingPackage,
+ namespace);
+ }
}
}
private static void startObservingPackages(Context context, @NonNull String updatedNamespace) {
- RescuePartyObserver rescuePartyObserver = RescuePartyObserver.getInstance(context);
- Set<String> callingPackages = rescuePartyObserver.getCallingPackagesSet(updatedNamespace);
- if (callingPackages == null) {
- return;
+ if (!Flags.deprecateFlagsAndSettingsResets()) {
+ RescuePartyObserver rescuePartyObserver = RescuePartyObserver.getInstance(context);
+ Set<String> callingPackages = rescuePartyObserver.getCallingPackagesSet(
+ updatedNamespace);
+ if (callingPackages == null) {
+ return;
+ }
+ List<String> callingPackageList = new ArrayList<>();
+ callingPackageList.addAll(callingPackages);
+ Slog.i(TAG, "Starting to observe: " + callingPackageList + ", updated namespace: "
+ + updatedNamespace);
+ PackageWatchdog.getInstance(context).startObservingHealth(
+ rescuePartyObserver,
+ callingPackageList,
+ DEFAULT_OBSERVING_DURATION_MS);
}
- List<String> callingPackageList = new ArrayList<>();
- callingPackageList.addAll(callingPackages);
- Slog.i(TAG, "Starting to observe: " + callingPackageList + ", updated namespace: "
- + updatedNamespace);
- PackageWatchdog.getInstance(context).startObservingHealth(
- rescuePartyObserver,
- callingPackageList,
- DEFAULT_OBSERVING_DURATION_MS);
}
private static void handleNativeRescuePartyResets() {
- if (SettingsToPropertiesMapper.isNativeFlagsResetPerformed()) {
- String[] resetNativeCategories = SettingsToPropertiesMapper.getResetNativeCategories();
- for (int i = 0; i < resetNativeCategories.length; i++) {
- // Don't let RescueParty reset the namespace for RescueParty switches.
- if (NAMESPACE_CONFIGURATION.equals(resetNativeCategories[i])) {
- continue;
+ if (!Flags.deprecateFlagsAndSettingsResets()) {
+ if (SettingsToPropertiesMapper.isNativeFlagsResetPerformed()) {
+ String[] resetNativeCategories =
+ SettingsToPropertiesMapper.getResetNativeCategories();
+ for (int i = 0; i < resetNativeCategories.length; i++) {
+ // Don't let RescueParty reset the namespace for RescueParty switches.
+ if (NAMESPACE_CONFIGURATION.equals(resetNativeCategories[i])) {
+ continue;
+ }
+ DeviceConfig.resetToDefaults(DEVICE_CONFIG_RESET_MODE,
+ resetNativeCategories[i]);
}
- DeviceConfig.resetToDefaults(DEVICE_CONFIG_RESET_MODE,
- resetNativeCategories[i]);
}
}
}
@@ -400,6 +419,13 @@
}
}
+ private static int getMaxRescueLevel() {
+ if (!SystemProperties.getBoolean(PROP_DISABLE_FACTORY_RESET_FLAG, false)) {
+ return Level.factoryReset();
+ }
+ return Level.reboot();
+ }
+
/**
* Get the rescue level to perform if this is the n-th attempt at mitigating failure.
*
@@ -409,19 +435,30 @@
* @return the rescue level for the n-th mitigation attempt.
*/
private static int getRescueLevel(int mitigationCount, boolean mayPerformReboot) {
- if (mitigationCount == 1) {
- return LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS;
- } else if (mitigationCount == 2) {
- return LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES;
- } else if (mitigationCount == 3) {
- return LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS;
- } else if (mitigationCount == 4) {
- return Math.min(getMaxRescueLevel(mayPerformReboot), LEVEL_WARM_REBOOT);
- } else if (mitigationCount >= 5) {
- return Math.min(getMaxRescueLevel(mayPerformReboot), LEVEL_FACTORY_RESET);
+ if (!Flags.deprecateFlagsAndSettingsResets()) {
+ if (mitigationCount == 1) {
+ return LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS;
+ } else if (mitigationCount == 2) {
+ return LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES;
+ } else if (mitigationCount == 3) {
+ return LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS;
+ } else if (mitigationCount == 4) {
+ return Math.min(getMaxRescueLevel(mayPerformReboot), LEVEL_WARM_REBOOT);
+ } else if (mitigationCount >= 5) {
+ return Math.min(getMaxRescueLevel(mayPerformReboot), LEVEL_FACTORY_RESET);
+ } else {
+ Slog.w(TAG, "Expected positive mitigation count, was " + mitigationCount);
+ return LEVEL_NONE;
+ }
} else {
- Slog.w(TAG, "Expected positive mitigation count, was " + mitigationCount);
- return LEVEL_NONE;
+ if (mitigationCount == 1) {
+ return Level.reboot();
+ } else if (mitigationCount >= 2) {
+ return Math.min(getMaxRescueLevel(), Level.factoryReset());
+ } else {
+ Slog.w(TAG, "Expected positive mitigation count, was " + mitigationCount);
+ return LEVEL_NONE;
+ }
}
}
@@ -451,13 +488,13 @@
return Math.min(getMaxRescueLevel(mayPerformReboot), RESCUE_LEVEL_WARM_REBOOT);
} else if (mitigationCount == 4) {
return Math.min(getMaxRescueLevel(mayPerformReboot),
- RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS);
+ RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS);
} else if (mitigationCount == 5) {
return Math.min(getMaxRescueLevel(mayPerformReboot),
- RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES);
+ RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES);
} else if (mitigationCount == 6) {
return Math.min(getMaxRescueLevel(mayPerformReboot),
- RESCUE_LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS);
+ RESCUE_LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS);
} else if (mitigationCount >= 7) {
return Math.min(getMaxRescueLevel(mayPerformReboot), RESCUE_LEVEL_FACTORY_RESET);
} else {
@@ -465,6 +502,22 @@
}
}
+ /**
+ * Get the rescue level to perform if this is the n-th attempt at mitigating failure.
+ *
+ * @param mitigationCount the mitigation attempt number (1 = first attempt etc.).
+ * @return the rescue level for the n-th mitigation attempt.
+ */
+ private static @RescueLevels int getRescueLevel(int mitigationCount) {
+ if (mitigationCount == 1) {
+ return Level.reboot();
+ } else if (mitigationCount >= 2) {
+ return Math.min(getMaxRescueLevel(), Level.factoryReset());
+ } else {
+ return Level.none();
+ }
+ }
+
private static void executeRescueLevel(Context context, @Nullable String failedPackage,
int level) {
Slog.w(TAG, "Attempting rescue level " + levelToString(level));
@@ -537,13 +590,22 @@
executeWarmReboot(context, level, failedPackage);
break;
case RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
- resetAllSettingsIfNecessary(context, Settings.RESET_MODE_UNTRUSTED_DEFAULTS, level);
+ if (!Flags.deprecateFlagsAndSettingsResets()) {
+ resetAllSettingsIfNecessary(context, Settings.RESET_MODE_UNTRUSTED_DEFAULTS,
+ level);
+ }
break;
case RESCUE_LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES:
- resetAllSettingsIfNecessary(context, Settings.RESET_MODE_UNTRUSTED_CHANGES, level);
+ if (!Flags.deprecateFlagsAndSettingsResets()) {
+ resetAllSettingsIfNecessary(context, Settings.RESET_MODE_UNTRUSTED_CHANGES,
+ level);
+ }
break;
case RESCUE_LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS:
- resetAllSettingsIfNecessary(context, Settings.RESET_MODE_TRUSTED_DEFAULTS, level);
+ if (!Flags.deprecateFlagsAndSettingsResets()) {
+ resetAllSettingsIfNecessary(context, Settings.RESET_MODE_TRUSTED_DEFAULTS,
+ level);
+ }
break;
case RESCUE_LEVEL_FACTORY_RESET:
// Before the completion of Reboot, if any crash happens then PackageWatchdog
@@ -560,6 +622,12 @@
private static void executeWarmReboot(Context context, int level,
@Nullable String failedPackage) {
+ if (Flags.deprecateFlagsAndSettingsResets()) {
+ if (shouldThrottleReboot()) {
+ return;
+ }
+ }
+
// Request the reboot from a separate thread to avoid deadlock on PackageWatchdog
// when device shutting down.
setRebootProperty(true);
@@ -579,6 +647,11 @@
private static void executeFactoryReset(Context context, int level,
@Nullable String failedPackage) {
+ if (Flags.deprecateFlagsAndSettingsResets()) {
+ if (shouldThrottleReboot()) {
+ return;
+ }
+ }
setFactoryResetProperty(true);
long now = System.currentTimeMillis();
setLastFactoryResetTimeMs(now);
@@ -655,30 +728,32 @@
private static void resetAllSettingsIfNecessary(Context context, int mode,
int level) throws Exception {
- // No need to reset Settings again if they are already reset in the current level once.
- if (getMaxRescueLevelAttempted() >= level) {
- return;
- }
- setMaxRescueLevelAttempted(level);
- // Try our best to reset all settings possible, and once finished
- // rethrow any exception that we encountered
- Exception res = null;
- final ContentResolver resolver = context.getContentResolver();
- try {
- Settings.Global.resetToDefaultsAsUser(resolver, null, mode,
- UserHandle.SYSTEM.getIdentifier());
- } catch (Exception e) {
- res = new RuntimeException("Failed to reset global settings", e);
- }
- for (int userId : getAllUserIds()) {
- try {
- Settings.Secure.resetToDefaultsAsUser(resolver, null, mode, userId);
- } catch (Exception e) {
- res = new RuntimeException("Failed to reset secure settings for " + userId, e);
+ if (!Flags.deprecateFlagsAndSettingsResets()) {
+ // No need to reset Settings again if they are already reset in the current level once.
+ if (getMaxRescueLevelAttempted() >= level) {
+ return;
}
- }
- if (res != null) {
- throw res;
+ setMaxRescueLevelAttempted(level);
+ // Try our best to reset all settings possible, and once finished
+ // rethrow any exception that we encountered
+ Exception res = null;
+ final ContentResolver resolver = context.getContentResolver();
+ try {
+ Settings.Global.resetToDefaultsAsUser(resolver, null, mode,
+ UserHandle.SYSTEM.getIdentifier());
+ } catch (Exception e) {
+ res = new RuntimeException("Failed to reset global settings", e);
+ }
+ for (int userId : getAllUserIds()) {
+ try {
+ Settings.Secure.resetToDefaultsAsUser(resolver, null, mode, userId);
+ } catch (Exception e) {
+ res = new RuntimeException("Failed to reset secure settings for " + userId, e);
+ }
+ }
+ if (res != null) {
+ throw res;
+ }
}
}
@@ -728,18 +803,28 @@
@Override
public int onHealthCheckFailed(@Nullable VersionedPackage failedPackage,
@FailureReasons int failureReason, int mitigationCount) {
+ int impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
if (!isDisabled() && (failureReason == PackageWatchdog.FAILURE_REASON_APP_CRASH
|| failureReason == PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING)) {
if (Flags.recoverabilityDetection()) {
- return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount,
- mayPerformReboot(failedPackage), failedPackage));
+ if (!Flags.deprecateFlagsAndSettingsResets()) {
+ impact = mapRescueLevelToUserImpact(getRescueLevel(mitigationCount,
+ mayPerformReboot(failedPackage), failedPackage));
+ } else {
+ impact = mapRescueLevelToUserImpact(getRescueLevel(mitigationCount));
+ }
} else {
- return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount,
- mayPerformReboot(failedPackage)));
+ impact = mapRescueLevelToUserImpact(getRescueLevel(mitigationCount,
+ mayPerformReboot(failedPackage)));
}
- } else {
- return PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
}
+
+ Slog.i(TAG, "Checking available remediations for health check failure."
+ + " failedPackage: "
+ + (failedPackage == null ? null : failedPackage.getPackageName())
+ + " failureReason: " + failureReason
+ + " available impact: " + impact);
+ return impact;
}
@Override
@@ -748,12 +833,24 @@
if (isDisabled()) {
return false;
}
+ Slog.i(TAG, "Executing remediation."
+ + " failedPackage: "
+ + (failedPackage == null ? null : failedPackage.getPackageName())
+ + " failureReason: " + failureReason
+ + " mitigationCount: " + mitigationCount);
if (failureReason == PackageWatchdog.FAILURE_REASON_APP_CRASH
|| failureReason == PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING) {
- final int level = Flags.recoverabilityDetection() ? getRescueLevel(mitigationCount,
- mayPerformReboot(failedPackage), failedPackage)
- : getRescueLevel(mitigationCount,
- mayPerformReboot(failedPackage));
+ final int level;
+ if (Flags.recoverabilityDetection()) {
+ if (!Flags.deprecateFlagsAndSettingsResets()) {
+ level = getRescueLevel(mitigationCount, mayPerformReboot(failedPackage),
+ failedPackage);
+ } else {
+ level = getRescueLevel(mitigationCount);
+ }
+ } else {
+ level = getRescueLevel(mitigationCount, mayPerformReboot(failedPackage));
+ }
executeRescueLevel(mContext,
failedPackage == null ? null : failedPackage.getPackageName(), level);
return true;
@@ -787,8 +884,12 @@
return PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
}
if (Flags.recoverabilityDetection()) {
- return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount,
- true, /*failedPackage=*/ null));
+ if (!Flags.deprecateFlagsAndSettingsResets()) {
+ return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount,
+ true, /*failedPackage=*/ null));
+ } else {
+ return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount));
+ }
} else {
return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount, true));
}
@@ -800,9 +901,17 @@
return false;
}
boolean mayPerformReboot = !shouldThrottleReboot();
- final int level = Flags.recoverabilityDetection() ? getRescueLevel(mitigationCount,
- mayPerformReboot, /*failedPackage=*/ null)
- : getRescueLevel(mitigationCount, mayPerformReboot);
+ final int level;
+ if (Flags.recoverabilityDetection()) {
+ if (!Flags.deprecateFlagsAndSettingsResets()) {
+ level = getRescueLevel(mitigationCount, mayPerformReboot,
+ /*failedPackage=*/ null);
+ } else {
+ level = getRescueLevel(mitigationCount);
+ }
+ } else {
+ level = getRescueLevel(mitigationCount, mayPerformReboot);
+ }
executeRescueLevel(mContext, /*failedPackage=*/ null, level);
return true;
}
@@ -828,18 +937,6 @@
return isPersistentSystemApp(failingPackage.getPackageName());
}
- /**
- * Returns {@code true} if Rescue Party is allowed to attempt a reboot or factory reset.
- * Will return {@code false} if a factory reset was already offered recently.
- */
- private boolean shouldThrottleReboot() {
- Long lastResetTime = getLastFactoryResetTimeMs();
- long now = System.currentTimeMillis();
- long throttleDurationMin = SystemProperties.getLong(PROP_THROTTLE_DURATION_MIN_FLAG,
- DEFAULT_FACTORY_RESET_THROTTLE_DURATION_MIN);
- return now < lastResetTime + TimeUnit.MINUTES.toMillis(throttleDurationMin);
- }
-
private boolean isPersistentSystemApp(@NonNull String packageName) {
PackageManager pm = mContext.getPackageManager();
try {
@@ -852,20 +949,22 @@
private synchronized void recordDeviceConfigAccess(@NonNull String callingPackage,
@NonNull String namespace) {
- // Record it in calling packages to namespace map
- Set<String> namespaceSet = mCallingPackageNamespaceSetMap.get(callingPackage);
- if (namespaceSet == null) {
- namespaceSet = new ArraySet<>();
- mCallingPackageNamespaceSetMap.put(callingPackage, namespaceSet);
+ if (!Flags.deprecateFlagsAndSettingsResets()) {
+ // Record it in calling packages to namespace map
+ Set<String> namespaceSet = mCallingPackageNamespaceSetMap.get(callingPackage);
+ if (namespaceSet == null) {
+ namespaceSet = new ArraySet<>();
+ mCallingPackageNamespaceSetMap.put(callingPackage, namespaceSet);
+ }
+ namespaceSet.add(namespace);
+ // Record it in namespace to calling packages map
+ Set<String> callingPackageSet = mNamespaceCallingPackageSetMap.get(namespace);
+ if (callingPackageSet == null) {
+ callingPackageSet = new ArraySet<>();
+ }
+ callingPackageSet.add(callingPackage);
+ mNamespaceCallingPackageSetMap.put(namespace, callingPackageSet);
}
- namespaceSet.add(namespace);
- // Record it in namespace to calling packages map
- Set<String> callingPackageSet = mNamespaceCallingPackageSetMap.get(namespace);
- if (callingPackageSet == null) {
- callingPackageSet = new ArraySet<>();
- }
- callingPackageSet.add(callingPackage);
- mNamespaceCallingPackageSetMap.put(namespace, callingPackageSet);
}
private synchronized Set<String> getAffectedNamespaceSet(String failedPackage) {
@@ -881,6 +980,18 @@
}
}
+ /**
+ * Returns {@code true} if Rescue Party is allowed to attempt a reboot or factory reset.
+ * Will return {@code false} if a factory reset was already offered recently.
+ */
+ private static boolean shouldThrottleReboot() {
+ Long lastResetTime = getLastFactoryResetTimeMs();
+ long now = System.currentTimeMillis();
+ long throttleDurationMin = SystemProperties.getLong(PROP_THROTTLE_DURATION_MIN_FLAG,
+ DEFAULT_FACTORY_RESET_THROTTLE_DURATION_MIN);
+ return now < lastResetTime + TimeUnit.MINUTES.toMillis(throttleDurationMin);
+ }
+
private static int[] getAllUserIds() {
int systemUserId = UserHandle.SYSTEM.getIdentifier();
int[] userIds = { systemUserId };
@@ -919,6 +1030,22 @@
}
}
+ private static class Level {
+ static int none() {
+ return Flags.recoverabilityDetection() ? RESCUE_LEVEL_NONE : LEVEL_NONE;
+ }
+
+ static int reboot() {
+ return Flags.recoverabilityDetection() ? RESCUE_LEVEL_WARM_REBOOT : LEVEL_WARM_REBOOT;
+ }
+
+ static int factoryReset() {
+ return Flags.recoverabilityDetection()
+ ? RESCUE_LEVEL_FACTORY_RESET
+ : LEVEL_FACTORY_RESET;
+ }
+ }
+
private static String levelToString(int level) {
if (Flags.recoverabilityDetection()) {
switch (level) {
diff --git a/services/core/java/com/android/server/am/LmkdConnection.java b/services/core/java/com/android/server/am/LmkdConnection.java
index 598f086..4faadcb 100644
--- a/services/core/java/com/android/server/am/LmkdConnection.java
+++ b/services/core/java/com/android/server/am/LmkdConnection.java
@@ -91,10 +91,18 @@
@GuardedBy("mLmkdSocketLock")
private LocalSocket mLmkdSocket = null;
- // socket I/O streams
- @GuardedBy("mLmkdSocketLock")
+ // mutex to synchronize socket output stream with socket creation/destruction
+ private final Object mLmkdOutputStreamLock = new Object();
+
+ // socket output stream
+ @GuardedBy("mLmkdOutputStreamLock")
private OutputStream mLmkdOutputStream = null;
- @GuardedBy("mLmkdSocketLock")
+
+ // mutex to synchronize socket input stream with socket creation/destruction
+ private final Object mLmkdInputStreamLock = new Object();
+
+ // socket input stream
+ @GuardedBy("mLmkdInputStreamLock")
private InputStream mLmkdInputStream = null;
// buffer to store incoming data
@@ -148,9 +156,13 @@
return false;
}
// connection established
- mLmkdSocket = socket;
- mLmkdOutputStream = ostream;
- mLmkdInputStream = istream;
+ synchronized(mLmkdOutputStreamLock) {
+ synchronized(mLmkdInputStreamLock) {
+ mLmkdSocket = socket;
+ mLmkdOutputStream = ostream;
+ mLmkdInputStream = istream;
+ }
+ }
mMsgQueue.addOnFileDescriptorEventListener(mLmkdSocket.getFileDescriptor(),
EVENT_INPUT | EVENT_ERROR,
new MessageQueue.OnFileDescriptorEventListener() {
@@ -177,7 +189,13 @@
mMsgQueue.removeOnFileDescriptorEventListener(
mLmkdSocket.getFileDescriptor());
IoUtils.closeQuietly(mLmkdSocket);
- mLmkdSocket = null;
+ synchronized(mLmkdOutputStreamLock) {
+ synchronized(mLmkdInputStreamLock) {
+ mLmkdOutputStream = null;
+ mLmkdInputStream = null;
+ mLmkdSocket = null;
+ }
+ }
}
// wake up reply waiters if any
synchronized (mReplyBufLock) {
@@ -262,24 +280,33 @@
}
private boolean write(ByteBuffer buf) {
- synchronized (mLmkdSocketLock) {
- try {
- mLmkdOutputStream.write(buf.array(), 0, buf.position());
- } catch (IOException ex) {
- return false;
+ boolean result = false;
+
+ synchronized(mLmkdOutputStreamLock) {
+ if (mLmkdOutputStream != null) {
+ try {
+ mLmkdOutputStream.write(buf.array(), 0, buf.position());
+ result = true;
+ } catch (IOException ex) {
+ }
}
- return true;
}
+
+ return result;
}
private int read(ByteBuffer buf) {
- synchronized (mLmkdSocketLock) {
- try {
- return mLmkdInputStream.read(buf.array(), 0, buf.array().length);
- } catch (IOException ex) {
+ int result = -1;
+
+ synchronized(mLmkdInputStreamLock) {
+ if (mLmkdInputStream != null) {
+ try {
+ result = mLmkdInputStream.read(buf.array(), 0, buf.array().length);
+ } catch (IOException ex) {
+ }
}
- return -1;
}
+ return result;
}
/**
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 64e3e8e..97678aa 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -5491,8 +5491,9 @@
void noteAppKill(final ProcessRecord app, final @Reason int reason,
final @SubReason int subReason, final String msg) {
if (DEBUG_PROCESSES) {
- Slog.i(TAG, "note: " + app + " is being killed, reason: " + reason
- + ", sub-reason: " + subReason + ", message: " + msg);
+ Slog.i(TAG, "note: " + app + " is being killed, reason: "
+ + ApplicationExitInfo.reasonCodeToString(reason) + ", sub-reason: "
+ + ApplicationExitInfo.subreasonToString(subReason) + ", message: " + msg);
}
if (app.getPid() > 0 && !app.isolated && app.getDeathRecipient() != null) {
// We are killing it, put it into the dying process list.
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 0f3f807..73ca6fb 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -436,8 +436,13 @@
if (mBluetoothHeadset == null || mBluetoothHeadsetDevice == null) {
return false;
}
- return mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
- == BluetoothHeadset.STATE_AUDIO_CONNECTED;
+ try {
+ return mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
+ == BluetoothHeadset.STATE_AUDIO_CONNECTED;
+ } catch (Exception e) {
+ Log.e(TAG, "Exception while getting audio state of " + mBluetoothHeadsetDevice, e);
+ }
+ return false;
}
// @GuardedBy("mDeviceBroker.mSetModeLock")
@@ -1051,12 +1056,16 @@
}
private void checkScoAudioState() {
- if (mBluetoothHeadset != null
- && mBluetoothHeadsetDevice != null
- && mScoAudioState == SCO_STATE_INACTIVE
- && mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
- != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
- mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
+ try {
+ if (mBluetoothHeadset != null
+ && mBluetoothHeadsetDevice != null
+ && mScoAudioState == SCO_STATE_INACTIVE
+ && mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
+ != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
+ mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Exception while getting audio state of " + mBluetoothHeadsetDevice, e);
}
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 1564b2f..0f7904e 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -2949,6 +2949,7 @@
hideStatusBarIconLocked();
mInFullscreenMode = false;
mWindowManagerInternal.setDismissImeOnBackKeyPressed(false);
+ scheduleResetStylusHandwriting();
}
@BinderThread
diff --git a/services/core/java/com/android/server/location/altitude/AltitudeService.java b/services/core/java/com/android/server/location/altitude/AltitudeService.java
index 289d4a2..96540c2 100644
--- a/services/core/java/com/android/server/location/altitude/AltitudeService.java
+++ b/services/core/java/com/android/server/location/altitude/AltitudeService.java
@@ -25,6 +25,7 @@
import android.location.Location;
import android.location.altitude.AltitudeConverter;
import android.os.RemoteException;
+import android.util.Log;
import com.android.server.SystemService;
@@ -38,6 +39,8 @@
*/
public class AltitudeService extends IAltitudeService.Stub {
+ private static final String TAG = "AltitudeService";
+
private final AltitudeConverter mAltitudeConverter = new AltitudeConverter();
private final Context mContext;
@@ -59,6 +62,7 @@
try {
mAltitudeConverter.addMslAltitudeToLocation(mContext, location);
} catch (IOException e) {
+ Log.e(TAG, "", e);
response.success = false;
return response;
}
@@ -74,6 +78,7 @@
try {
return mAltitudeConverter.getGeoidHeight(mContext, request);
} catch (IOException e) {
+ Log.e(TAG, "", e);
GetGeoidHeightResponse response = new GetGeoidHeightResponse();
response.success = false;
return response;
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 7157646..7aae91b 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -1773,6 +1773,20 @@
}
}
+ @Override
+ public boolean writeRepairModeCredential(int userId) {
+ checkWritePermission();
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mSpManager) {
+ long protectorId = getCurrentLskfBasedProtectorId(userId);
+ return mSpManager.writeRepairModeCredentialLocked(protectorId, userId);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
/**
* @param savedCredential if the user is a profile with
* {@link UserManager#isCredentialSharableWithParent()} with unified challenge and
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 89c4f0f..9199004 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -4550,7 +4550,7 @@
PackageManagerException.INTERNAL_ERROR_SYSTEM_OVERLAY_STATIC);
}
} else {
- if ((scanFlags & SCAN_AS_VENDOR) != 0) {
+ if ((scanFlags & (SCAN_AS_VENDOR | SCAN_AS_ODM)) != 0) {
if (pkg.getTargetSdkVersion() < ScanPackageUtils.getVendorPartitionVersion()) {
Slog.w(TAG, "System overlay " + pkg.getPackageName()
+ " targets an SDK below the required SDK level of vendor"
diff --git a/services/core/java/com/android/server/rollback/Rollback.java b/services/core/java/com/android/server/rollback/Rollback.java
index d1f91c8..c4e3fa4 100644
--- a/services/core/java/com/android/server/rollback/Rollback.java
+++ b/services/core/java/com/android/server/rollback/Rollback.java
@@ -16,6 +16,8 @@
package com.android.server.rollback;
+import static android.crashrecovery.flags.Flags.deprecateFlagsAndSettingsResets;
+
import static com.android.server.rollback.RollbackManagerServiceImpl.sendFailure;
import android.Manifest;
@@ -622,8 +624,10 @@
parentSession.addChildSessionId(sessionId);
}
- // Clear flags.
- RescueParty.resetDeviceConfigForPackages(packageNames);
+ if (!deprecateFlagsAndSettingsResets()) {
+ // Clear flags.
+ RescueParty.resetDeviceConfigForPackages(packageNames);
+ }
Consumer<Intent> onResult = result -> {
mHandler.post(() -> {
diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
index c85ceac..4f28e02 100644
--- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
+++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -154,12 +154,22 @@
}
}
+ Slog.i(TAG, "Checking available remediations for health check failure."
+ + " failedPackage: "
+ + (failedPackage == null ? null : failedPackage.getPackageName())
+ + " failureReason: " + failureReason
+ + " available impact: " + impact);
return impact;
}
@Override
public boolean execute(@Nullable VersionedPackage failedPackage,
@FailureReasons int rollbackReason, int mitigationCount) {
+ Slog.i(TAG, "Executing remediation."
+ + " failedPackage: "
+ + (failedPackage == null ? null : failedPackage.getPackageName())
+ + " rollbackReason: " + rollbackReason
+ + " mitigationCount: " + mitigationCount);
if (Flags.recoverabilityDetection()) {
List<RollbackInfo> availableRollbacks = getAvailableRollbacks();
if (rollbackReason == PackageWatchdog.FAILURE_REASON_NATIVE_CRASH) {
@@ -503,6 +513,10 @@
@FailureReasons int rollbackReason) {
assertInWorkerThread();
+ Slog.i(TAG, "Rolling back package. RollbackId: " + rollback.getRollbackId()
+ + " failedPackage: "
+ + (failedPackage == null ? null : failedPackage.getPackageName())
+ + " rollbackReason: " + rollbackReason);
final RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
int reasonToLog = WatchdogRollbackLogger.mapFailureReasonToMetric(rollbackReason);
final String failedPackageToLog;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index e19f08c..37f49e3 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -2461,11 +2461,11 @@
t.traceEnd();
}
- t.traceBegin("CertBlacklister");
+ t.traceBegin("CertBlocklister");
try {
- CertBlacklister blacklister = new CertBlacklister(context);
+ CertBlocklister blocklister = new CertBlocklister(context);
} catch (Throwable e) {
- reportWtf("starting CertBlacklister", e);
+ reportWtf("starting CertBlocklister", e);
}
t.traceEnd();
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index 977a8a0..3ed6ad7 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -287,7 +287,7 @@
if (randomNum < traceFrequency) {
BackgroundThread.get().getThreadHandler().post(() -> {
try {
- mIProfcollect.trace_once("applaunch");
+ mIProfcollect.trace_system("applaunch");
} catch (RemoteException e) {
Log.e(LOG_TAG, "Failed to initiate trace: " + e.getMessage());
}
@@ -327,7 +327,7 @@
// Dex2oat could take a while before it starts. Add a short delay before start tracing.
BackgroundThread.get().getThreadHandler().postDelayed(() -> {
try {
- mIProfcollect.trace_once("dex2oat");
+ mIProfcollect.trace_system("dex2oat");
} catch (RemoteException e) {
Log.e(LOG_TAG, "Failed to initiate trace: " + e.getMessage());
}
@@ -398,14 +398,17 @@
if (randomNum >= traceFrequency) {
return;
}
- // Wait for 1s before starting tracing.
+ // For a small percentage a traces, we collect the initialization behavior.
+ boolean traceInitialization = ThreadLocalRandom.current().nextInt(10) < 1;
+ int traceDelay = traceInitialization ? 0 : 1000;
+ String traceTag = traceInitialization ? "camera_init" : "camera";
BackgroundThread.get().getThreadHandler().postDelayed(() -> {
try {
- mIProfcollect.trace_once("camera");
+ mIProfcollect.trace_process(traceTag, "android.hardware.camera.provider");
} catch (RemoteException e) {
Log.e(LOG_TAG, "Failed to initiate trace: " + e.getMessage());
}
- }, 1000);
+ }, traceDelay);
}
}, null);
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
index 3377899..f2acbc3 100644
--- a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
@@ -27,7 +27,6 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static com.android.server.RescueParty.DEFAULT_FACTORY_RESET_THROTTLE_DURATION_MIN;
import static com.android.server.RescueParty.LEVEL_FACTORY_RESET;
-import static com.android.server.RescueParty.RESCUE_LEVEL_FACTORY_RESET;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -36,7 +35,6 @@
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
import android.content.ContentResolver;
import android.content.Context;
@@ -47,6 +45,9 @@
import android.os.RecoverySystem;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.FlagsParameterization;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.DeviceConfig;
import android.provider.Settings;
@@ -61,6 +62,9 @@
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
import org.mockito.Answers;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
@@ -77,10 +81,14 @@
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
+
/**
* Test RescueParty.
*/
+@RunWith(Parameterized.class)
public class RescuePartyTest {
+ @Rule
+ public SetFlagsRule mSetFlagsRule;
private static final long CURRENT_NETWORK_TIME_MILLIS = 0L;
private static final String FAKE_NATIVE_NAMESPACE1 = "native1";
private static final String FAKE_NATIVE_NAMESPACE2 = "native2";
@@ -103,9 +111,6 @@
private static final String PROP_DISABLE_FACTORY_RESET_FLAG =
"persist.device_config.configuration.disable_rescue_party_factory_reset";
- @Rule
- public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
-
private MockitoSession mSession;
private HashMap<String, String> mSystemSettingsMap;
private HashMap<String, String> mCrashRecoveryPropertiesMap;
@@ -129,6 +134,17 @@
@Captor
private ArgumentCaptor<List<String>> mPackageListCaptor;
+ @Parameters(name = "{0}")
+ public static List<FlagsParameterization> getFlags() {
+ return FlagsParameterization.allCombinationsOf(
+ Flags.FLAG_RECOVERABILITY_DETECTION,
+ Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS);
+ }
+
+ public RescuePartyTest(FlagsParameterization flags) {
+ mSetFlagsRule = new SetFlagsRule(flags);
+ }
+
@Before
public void setUp() throws Exception {
mSession =
@@ -234,10 +250,10 @@
}
@Test
- public void testBootLoopDetectionWithExecutionForAllRescueLevels() {
+ @DisableFlags({Flags.FLAG_RECOVERABILITY_DETECTION,
+ Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS})
+ public void testBootLoop() {
// this is old test where the flag needs to be disabled
- mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
-
RescueParty.onSettingsProviderPublished(mMockContext);
verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver),
any(Executor.class),
@@ -264,10 +280,22 @@
noteBoot(5);
assertTrue(RescueParty.isFactoryResetPropertySet());
}
+ @Test
+ @EnableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
+ public void testBootLoopNoFlags() {
+ // this is old test where the flag needs to be disabled
+ noteBoot(1);
+ assertTrue(RescueParty.isRebootPropertySet());
+
+ setCrashRecoveryPropAttemptingReboot(false);
+ noteBoot(2);
+ assertTrue(RescueParty.isFactoryResetPropertySet());
+ }
@Test
- public void testBootLoopDetectionWithExecutionForAllRescueLevelsRecoverabilityDetection() {
- mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
+ @EnableFlags(Flags.FLAG_RECOVERABILITY_DETECTION)
+ @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
+ public void testBootLoopRecoverability() {
RescueParty.onSettingsProviderPublished(mMockContext);
verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver),
any(Executor.class),
@@ -281,12 +309,14 @@
final String[] expectedAllResetNamespaces = new String[]{NAMESPACE1, NAMESPACE2};
+
noteBoot(1);
noteBoot(2);
assertTrue(RescueParty.isRebootPropertySet());
noteBoot(3);
+
verifyOnlySettingsReset(Settings.RESET_MODE_UNTRUSTED_DEFAULTS);
noteBoot(4);
@@ -301,10 +331,10 @@
}
@Test
- public void testPersistentAppCrashDetectionWithExecutionForAllRescueLevels() {
+ @DisableFlags({Flags.FLAG_RECOVERABILITY_DETECTION,
+ Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS})
+ public void testPersistentAppCrash() {
// this is old test where the flag needs to be disabled
- mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
-
noteAppCrash(1, true);
noteAppCrash(2, true);
noteAppCrash(3, true);
@@ -318,8 +348,21 @@
}
@Test
- public void testPersistentAppCrashDetectionWithExecutionForAllRescueLevelsRecoverability() {
- mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
+ @EnableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
+ public void testPersistentAppCrashNoFlags() {
+ // this is old test where the flag needs to be disabled
+ noteAppCrash(1, true);
+ assertTrue(RescueParty.isRebootPropertySet());
+
+ setCrashRecoveryPropAttemptingReboot(false);
+ noteAppCrash(2, true);
+ assertTrue(RescueParty.isFactoryResetPropertySet());
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_RECOVERABILITY_DETECTION)
+ @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
+ public void testPersistentAppCrashRecoverability() {
RescueParty.onSettingsProviderPublished(mMockContext);
verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver),
any(Executor.class),
@@ -357,10 +400,10 @@
}
@Test
- public void testNonPersistentAppDoesntDoAnything() {
+ @DisableFlags({Flags.FLAG_RECOVERABILITY_DETECTION,
+ Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS})
+ public void testNonPersistentApp() {
// this is old test where the flag needs to be disabled
- mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
-
noteAppCrash(1, false);
noteAppCrash(2, false);
noteAppCrash(3, false);
@@ -371,8 +414,9 @@
}
@Test
+ @EnableFlags(Flags.FLAG_RECOVERABILITY_DETECTION)
+ @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
public void testNonPersistentAppOnlyPerformsFlagResetsRecoverabilityDetection() {
- mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
RescueParty.onSettingsProviderPublished(mMockContext);
verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver),
any(Executor.class),
@@ -408,60 +452,6 @@
}
@Test
- public void testNonPersistentAppCrashDetectionWithScopedResets() {
- // this is old test where the flag needs to be disabled
- mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
-
- RescueParty.onSettingsProviderPublished(mMockContext);
- verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver),
- any(Executor.class),
- mMonitorCallbackCaptor.capture()));
-
- // Record DeviceConfig accesses
- RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
- DeviceConfig.MonitorCallback monitorCallback = mMonitorCallbackCaptor.getValue();
- monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE1, NAMESPACE1);
- monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE1, NAMESPACE2);
- monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE2, NAMESPACE2);
- monitorCallback.onDeviceConfigAccess(CALLING_PACKAGE2, NAMESPACE3);
-
- // Fake DeviceConfig value changes
- monitorCallback.onNamespaceUpdate(NAMESPACE1);
- verify(mMockPackageWatchdog).startObservingHealth(observer,
- Arrays.asList(CALLING_PACKAGE1), RescueParty.DEFAULT_OBSERVING_DURATION_MS);
- monitorCallback.onNamespaceUpdate(NAMESPACE2);
- verify(mMockPackageWatchdog, times(2)).startObservingHealth(eq(observer),
- mPackageListCaptor.capture(),
- eq(RescueParty.DEFAULT_OBSERVING_DURATION_MS));
- monitorCallback.onNamespaceUpdate(NAMESPACE3);
- verify(mMockPackageWatchdog).startObservingHealth(observer,
- Arrays.asList(CALLING_PACKAGE2), RescueParty.DEFAULT_OBSERVING_DURATION_MS);
- assertTrue(mPackageListCaptor.getValue().containsAll(
- Arrays.asList(CALLING_PACKAGE1, CALLING_PACKAGE2)));
- // Perform and verify scoped resets
- final String[] expectedResetNamespaces = new String[]{NAMESPACE1, NAMESPACE2};
- final String[] expectedAllResetNamespaces =
- new String[]{NAMESPACE1, NAMESPACE2, NAMESPACE3};
- HashMap<String, Integer> verifiedTimesMap = new HashMap<String, Integer>();
- observer.execute(new VersionedPackage(
- CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_CRASH, 1);
-
- observer.execute(new VersionedPackage(
- CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 2);
-
- observer.execute(new VersionedPackage(
- CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 3);
-
- observer.execute(new VersionedPackage(
- CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 4);
- assertFalse(RescueParty.isRebootPropertySet());
-
- observer.execute(new VersionedPackage(
- CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 5);
- assertFalse(RescueParty.isFactoryResetPropertySet());
- }
-
- @Test
public void testIsRecoveryTriggeredReboot() {
for (int i = 0; i < LEVEL_FACTORY_RESET; i++) {
noteBoot(i + 1);
@@ -474,19 +464,6 @@
}
@Test
- public void testIsRecoveryTriggeredRebootRecoverabilityDetection() {
- mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
- for (int i = 0; i < RESCUE_LEVEL_FACTORY_RESET; i++) {
- noteBoot(i + 1);
- }
- assertFalse(RescueParty.isFactoryResetPropertySet());
- setCrashRecoveryPropAttemptingReboot(false);
- noteBoot(RESCUE_LEVEL_FACTORY_RESET + 1);
- assertTrue(RescueParty.isRecoveryTriggeredReboot());
- assertTrue(RescueParty.isFactoryResetPropertySet());
- }
-
- @Test
public void testIsRecoveryTriggeredRebootOnlyAfterRebootCompleted() {
for (int i = 0; i < LEVEL_FACTORY_RESET; i++) {
noteBoot(i + 1);
@@ -505,25 +482,6 @@
}
@Test
- public void testIsRecoveryTriggeredRebootOnlyAfterRebootCompletedRecoverabilityDetection() {
- mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
- for (int i = 0; i < RESCUE_LEVEL_FACTORY_RESET; i++) {
- noteBoot(i + 1);
- }
- int mitigationCount = RESCUE_LEVEL_FACTORY_RESET + 1;
- assertFalse(RescueParty.isFactoryResetPropertySet());
- noteBoot(mitigationCount++);
- assertFalse(RescueParty.isFactoryResetPropertySet());
- noteBoot(mitigationCount++);
- assertFalse(RescueParty.isFactoryResetPropertySet());
- noteBoot(mitigationCount++);
- setCrashRecoveryPropAttemptingReboot(false);
- noteBoot(mitigationCount + 1);
- assertTrue(RescueParty.isRecoveryTriggeredReboot());
- assertTrue(RescueParty.isFactoryResetPropertySet());
- }
-
- @Test
public void testThrottlingOnBootFailures() {
setCrashRecoveryPropAttemptingReboot(false);
long now = System.currentTimeMillis();
@@ -537,20 +495,6 @@
}
@Test
- public void testThrottlingOnBootFailuresRecoverabilityDetection() {
- mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
- setCrashRecoveryPropAttemptingReboot(false);
- long now = System.currentTimeMillis();
- long beforeTimeout = now - TimeUnit.MINUTES.toMillis(
- DEFAULT_FACTORY_RESET_THROTTLE_DURATION_MIN - 1);
- setCrashRecoveryPropLastFactoryReset(beforeTimeout);
- for (int i = 1; i <= RESCUE_LEVEL_FACTORY_RESET; i++) {
- noteBoot(i);
- }
- assertFalse(RescueParty.isRecoveryTriggeredReboot());
- }
-
- @Test
public void testThrottlingOnAppCrash() {
setCrashRecoveryPropAttemptingReboot(false);
long now = System.currentTimeMillis();
@@ -564,20 +508,6 @@
}
@Test
- public void testThrottlingOnAppCrashRecoverabilityDetection() {
- mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
- setCrashRecoveryPropAttemptingReboot(false);
- long now = System.currentTimeMillis();
- long beforeTimeout = now - TimeUnit.MINUTES.toMillis(
- DEFAULT_FACTORY_RESET_THROTTLE_DURATION_MIN - 1);
- setCrashRecoveryPropLastFactoryReset(beforeTimeout);
- for (int i = 0; i <= RESCUE_LEVEL_FACTORY_RESET; i++) {
- noteAppCrash(i + 1, true);
- }
- assertFalse(RescueParty.isRecoveryTriggeredReboot());
- }
-
- @Test
public void testNotThrottlingAfterTimeoutOnBootFailures() {
setCrashRecoveryPropAttemptingReboot(false);
long now = System.currentTimeMillis();
@@ -591,20 +521,6 @@
}
@Test
- public void testNotThrottlingAfterTimeoutOnBootFailuresRecoverabilityDetection() {
- mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
- setCrashRecoveryPropAttemptingReboot(false);
- long now = System.currentTimeMillis();
- long afterTimeout = now - TimeUnit.MINUTES.toMillis(
- DEFAULT_FACTORY_RESET_THROTTLE_DURATION_MIN + 1);
- setCrashRecoveryPropLastFactoryReset(afterTimeout);
- for (int i = 1; i <= RESCUE_LEVEL_FACTORY_RESET; i++) {
- noteBoot(i);
- }
- assertTrue(RescueParty.isRecoveryTriggeredReboot());
- }
-
- @Test
public void testNotThrottlingAfterTimeoutOnAppCrash() {
setCrashRecoveryPropAttemptingReboot(false);
long now = System.currentTimeMillis();
@@ -618,20 +534,7 @@
}
@Test
- public void testNotThrottlingAfterTimeoutOnAppCrashRecoverabilityDetection() {
- mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
- setCrashRecoveryPropAttemptingReboot(false);
- long now = System.currentTimeMillis();
- long afterTimeout = now - TimeUnit.MINUTES.toMillis(
- DEFAULT_FACTORY_RESET_THROTTLE_DURATION_MIN + 1);
- setCrashRecoveryPropLastFactoryReset(afterTimeout);
- for (int i = 0; i <= RESCUE_LEVEL_FACTORY_RESET; i++) {
- noteAppCrash(i + 1, true);
- }
- assertTrue(RescueParty.isRecoveryTriggeredReboot());
- }
-
- @Test
+ @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
public void testNativeRescuePartyResets() {
doReturn(true).when(() -> SettingsToPropertiesMapper.isNativeFlagsResetPerformed());
doReturn(FAKE_RESET_NATIVE_NAMESPACES).when(
@@ -647,7 +550,6 @@
@Test
public void testExplicitlyEnablingAndDisablingRescue() {
- mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(false));
SystemProperties.set(PROP_DISABLE_RESCUE, Boolean.toString(true));
assertEquals(RescuePartyObserver.getInstance(mMockContext).execute(sFailingPackage,
@@ -660,7 +562,6 @@
@Test
public void testDisablingRescueByDeviceConfigFlag() {
- mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(false));
SystemProperties.set(PROP_DEVICE_CONFIG_DISABLE_FLAG, Boolean.toString(true));
@@ -686,24 +587,10 @@
}
@Test
- public void testDisablingFactoryResetByDeviceConfigFlagRecoverabilityDetection() {
- mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
- SystemProperties.set(PROP_DISABLE_FACTORY_RESET_FLAG, Boolean.toString(true));
-
- for (int i = 0; i < RESCUE_LEVEL_FACTORY_RESET; i++) {
- noteBoot(i + 1);
- }
- assertFalse(RescueParty.isFactoryResetPropertySet());
-
- // Restore the property value initialized in SetUp()
- SystemProperties.set(PROP_DISABLE_FACTORY_RESET_FLAG, "");
- }
-
- @Test
+ @DisableFlags({Flags.FLAG_RECOVERABILITY_DETECTION,
+ Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS})
public void testHealthCheckLevels() {
// this is old test where the flag needs to be disabled
- mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
-
RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
// Ensure that no action is taken for cases where the failure reason is unknown
@@ -729,8 +616,9 @@
}
@Test
+ @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
+ @EnableFlags(Flags.FLAG_RECOVERABILITY_DETECTION)
public void testHealthCheckLevelsRecoverabilityDetection() {
- mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
// Ensure that no action is taken for cases where the failure reason is unknown
@@ -767,11 +655,31 @@
PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 7),
PackageHealthObserverImpact.USER_IMPACT_LEVEL_40);
}
-
@Test
+ @EnableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
+ public void testHealthCheckLevelsNoFlags() {
+ // this is old test where the flag needs to be disabled
+ RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
+
+ // Ensure that no action is taken for cases where the failure reason is unknown
+ assertEquals(observer.onHealthCheckFailed(null, PackageWatchdog.FAILURE_REASON_UNKNOWN, 1),
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_0);
+
+ // Ensure the correct user impact is returned for each mitigation count.
+ assertEquals(observer.onHealthCheckFailed(null,
+ PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 1),
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_50);
+
+ assertEquals(observer.onHealthCheckFailed(null,
+ PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 2),
+ PackageHealthObserverImpact.USER_IMPACT_LEVEL_100);
+ }
+ @Test
+ @DisableFlags({Flags.FLAG_RECOVERABILITY_DETECTION,
+ Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS})
public void testBootLoopLevels() {
// this is old test where the flag needs to be disabled
- mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
+
RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
@@ -784,8 +692,9 @@
}
@Test
+ @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
+ @EnableFlags(Flags.FLAG_RECOVERABILITY_DETECTION)
public void testBootLoopLevelsRecoverabilityDetection() {
- mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
assertEquals(observer.onBootLoop(1), PackageHealthObserverImpact.USER_IMPACT_LEVEL_40);
@@ -797,6 +706,16 @@
}
@Test
+ @EnableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
+ public void testBootLoopLevelsNoFlags() {
+ RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
+
+ assertEquals(observer.onBootLoop(1), PackageHealthObserverImpact.USER_IMPACT_LEVEL_50);
+ assertEquals(observer.onBootLoop(2), PackageHealthObserverImpact.USER_IMPACT_LEVEL_100);
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
public void testResetDeviceConfigForPackagesOnlyRuntimeMap() {
RescueParty.onSettingsProviderPublished(mMockContext);
verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver),
@@ -827,6 +746,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
public void testResetDeviceConfigForPackagesOnlyPresetMap() {
RescueParty.onSettingsProviderPublished(mMockContext);
verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver),
@@ -835,7 +755,7 @@
String presetMapping = NAMESPACE1 + ":" + CALLING_PACKAGE1 + ","
+ NAMESPACE2 + ":" + CALLING_PACKAGE2 + ","
- + NAMESPACE3 + ":" + CALLING_PACKAGE1;
+ + NAMESPACE3 + ":" + CALLING_PACKAGE1;
doReturn(presetMapping).when(() -> DeviceConfig.getString(
eq(RescueParty.NAMESPACE_CONFIGURATION),
eq(RescueParty.NAMESPACE_TO_PACKAGE_MAPPING_FLAG),
@@ -848,6 +768,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
public void testResetDeviceConfigForPackagesBothMaps() {
RescueParty.onSettingsProviderPublished(mMockContext);
verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver),
@@ -884,6 +805,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
public void testResetDeviceConfigNoExceptionWhenFlagMalformed() {
RescueParty.onSettingsProviderPublished(mMockContext);
verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver),
diff --git a/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java
index 7aec42b..00daf41 100644
--- a/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java
@@ -43,6 +43,7 @@
import android.Manifest;
import android.annotation.Nullable;
import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
import android.app.AlarmManager;
import android.app.IActivityManager;
import android.app.admin.DevicePolicyManager;
@@ -142,6 +143,7 @@
private final Map<ComponentName, ITrustAgentService.Stub> mMockTrustAgents = new HashMap<>();
private @Mock ActivityManager mActivityManager;
+ private @Mock ActivityManagerInternal mActivityManagerInternal;
private @Mock AlarmManager mAlarmManager;
private @Mock BiometricManager mBiometricManager;
private @Mock DevicePolicyManager mDevicePolicyManager;
@@ -158,6 +160,7 @@
private HandlerThread mHandlerThread;
private TrustManagerService mService;
private ITrustManager mTrustManager;
+ private ActivityManagerInternal mPreviousActivityManagerInternal;
@Before
public void setUp() throws Exception {
@@ -210,6 +213,11 @@
mMockContext.setMockPackageManager(mPackageManager);
mMockContext.addMockSystemService(UserManager.class, mUserManager);
doReturn(mWindowManager).when(() -> WindowManagerGlobal.getWindowManagerService());
+ mPreviousActivityManagerInternal = LocalServices.getService(
+ ActivityManagerInternal.class);
+ LocalServices.removeServiceForTest(ActivityManagerInternal.class);
+ LocalServices.addService(ActivityManagerInternal.class,
+ mActivityManagerInternal);
LocalServices.addService(SystemServiceManager.class, mock(SystemServiceManager.class));
grantPermission(Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE);
@@ -257,7 +265,14 @@
@After
public void tearDown() {
LocalServices.removeServiceForTest(SystemServiceManager.class);
- mHandlerThread.quit();
+ LocalServices.removeServiceForTest(ActivityManagerInternal.class);
+ if (mPreviousActivityManagerInternal != null) {
+ LocalServices.addService(ActivityManagerInternal.class,
+ mPreviousActivityManagerInternal);
+ }
+ if (mHandlerThread != null) {
+ mHandlerThread.quit();
+ }
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockscreenRepairModeTest.java b/services/tests/servicestests/src/com/android/server/locksettings/LockscreenRepairModeTest.java
index 70150c5..4396c67 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockscreenRepairModeTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockscreenRepairModeTest.java
@@ -19,6 +19,8 @@
import static com.android.internal.widget.LockPatternUtils.USER_REPAIR_MODE;
import static com.android.internal.widget.LockPatternUtils.VERIFY_FLAG_WRITE_REPAIR_MODE_PW;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
@@ -199,6 +201,27 @@
.getResponseCode());
}
+ @Test
+ public void writeRepairModeCredential_noLock() {
+ assertThat(mService.writeRepairModeCredential(PRIMARY_USER_ID)).isFalse();
+ }
+
+ @Test
+ public void writeRepairModeCredential_hasLock() {
+ mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID);
+ assertThat(mService.writeRepairModeCredential(PRIMARY_USER_ID)).isTrue();
+ }
+
+ @Test
+ public void writeRepairModeCredential_verifyRepairModeUser() {
+ mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID);
+ mService.writeRepairModeCredential(PRIMARY_USER_ID);
+ setRepairModeActive(true);
+
+ var response = mService.verifyCredential(newPin("1234"), USER_REPAIR_MODE, 0);
+ assertThat(response.isMatched()).isTrue();
+ }
+
private void setRepairModeActive(boolean active) {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.REPAIR_MODE_ACTIVE, active ? 1 : 0);
diff --git a/test-mock/src/android/test/mock/MockContext.java b/test-mock/src/android/test/mock/MockContext.java
index cf38bea..6bf7ff5 100644
--- a/test-mock/src/android/test/mock/MockContext.java
+++ b/test-mock/src/android/test/mock/MockContext.java
@@ -479,6 +479,15 @@
throw new UnsupportedOperationException();
}
+ /** @hide */
+ @Override
+ public void sendOrderedBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
+ String[] receiverPermissions, int appOp, Bundle options,
+ BroadcastReceiver resultReceiver, Handler scheduler, int initialCode,
+ String initialData, Bundle initialExtras) {
+ throw new UnsupportedOperationException();
+ }
+
@Override
public void sendOrderedBroadcast(Intent intent, String receiverPermission,
String receiverAppOp, BroadcastReceiver resultReceiver, Handler scheduler,
diff --git a/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java b/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java
index 489ef44..3722fef 100644
--- a/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java
@@ -47,6 +47,8 @@
import android.os.Handler;
import android.os.SystemProperties;
import android.os.test.TestLooper;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.DeviceConfig;
import android.util.AtomicFile;
@@ -288,7 +290,8 @@
}
@Test
- public void testBootLoopWithRescuePartyAndRollbackPackageHealthObserver() throws Exception {
+ @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
+ public void testBootLoopWithRescuePartyAndRollbackObserver() throws Exception {
PackageWatchdog watchdog = createWatchdog();
RescuePartyObserver rescuePartyObserver = setUpRescuePartyObserver(watchdog);
RollbackPackageHealthObserver rollbackObserver =
@@ -360,6 +363,56 @@
verify(rescuePartyObserver, never()).executeBootLoopMitigation(2);
}
+ @Test
+ @EnableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
+ public void testBootLoopWithRescuePartyAndRollbackObserverNoFlags() throws Exception {
+ PackageWatchdog watchdog = createWatchdog();
+ RescuePartyObserver rescuePartyObserver = setUpRescuePartyObserver(watchdog);
+ RollbackPackageHealthObserver rollbackObserver =
+ setUpRollbackPackageHealthObserver(watchdog);
+
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(1);
+ verify(rollbackObserver, never()).executeBootLoopMitigation(1);
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT; i++) {
+ watchdog.noteBoot();
+ }
+ verify(rescuePartyObserver).executeBootLoopMitigation(1);
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(2);
+ verify(rollbackObserver, never()).executeBootLoopMitigation(1);
+
+ watchdog.noteBoot();
+
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(2);
+ verify(rollbackObserver).executeBootLoopMitigation(1);
+ verify(rollbackObserver, never()).executeBootLoopMitigation(2);
+ // Update the list of available rollbacks after executing bootloop mitigation once
+ when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of(ROLLBACK_INFO_HIGH,
+ ROLLBACK_INFO_MANUAL));
+
+ watchdog.noteBoot();
+
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(2);
+ verify(rollbackObserver).executeBootLoopMitigation(2);
+ verify(rollbackObserver, never()).executeBootLoopMitigation(3);
+ // Update the list of available rollbacks after executing bootloop mitigation
+ when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of(ROLLBACK_INFO_MANUAL));
+
+ watchdog.noteBoot();
+
+ verify(rescuePartyObserver).executeBootLoopMitigation(2);
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(3);
+ verify(rollbackObserver, never()).executeBootLoopMitigation(3);
+
+ moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_DEESCALATION_WINDOW_MS + 1);
+ Mockito.reset(rescuePartyObserver);
+
+ for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT; i++) {
+ watchdog.noteBoot();
+ }
+ verify(rescuePartyObserver).executeBootLoopMitigation(1);
+ verify(rescuePartyObserver, never()).executeBootLoopMitigation(2);
+ }
+
RollbackPackageHealthObserver setUpRollbackPackageHealthObserver(PackageWatchdog watchdog) {
RollbackPackageHealthObserver rollbackObserver =
spy(new RollbackPackageHealthObserver(mSpyContext, mApexManager));
diff --git a/tests/TrustTests/AndroidManifest.xml b/tests/TrustTests/AndroidManifest.xml
index 30cf345..2f6c0dd 100644
--- a/tests/TrustTests/AndroidManifest.xml
+++ b/tests/TrustTests/AndroidManifest.xml
@@ -78,6 +78,7 @@
<action android:name="android.service.trust.TrustAgentService" />
</intent-filter>
</service>
+
<service
android:name=".IsActiveUnlockRunningTrustAgent"
android:exported="true"
@@ -88,6 +89,16 @@
</intent-filter>
</service>
+ <service
+ android:name=".UnlockAttemptTrustAgent"
+ android:exported="true"
+ android:label="Test Agent"
+ android:permission="android.permission.BIND_TRUST_AGENT">
+ <intent-filter>
+ <action android:name="android.service.trust.TrustAgentService" />
+ </intent-filter>
+ </service>
+
</application>
<!-- self-instrumenting test package. -->
diff --git a/tests/TrustTests/src/android/trust/test/UnlockAttemptTest.kt b/tests/TrustTests/src/android/trust/test/UnlockAttemptTest.kt
new file mode 100644
index 0000000..2c9361d
--- /dev/null
+++ b/tests/TrustTests/src/android/trust/test/UnlockAttemptTest.kt
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.trust.test
+
+import android.app.trust.TrustManager
+import android.content.Context
+import android.trust.BaseTrustAgentService
+import android.trust.TrustTestActivity
+import android.trust.test.lib.LockStateTrackingRule
+import android.trust.test.lib.ScreenLockRule
+import android.trust.test.lib.TestTrustListener
+import android.trust.test.lib.TrustAgentRule
+import android.util.Log
+import androidx.test.core.app.ApplicationProvider.getApplicationContext
+import androidx.test.ext.junit.rules.ActivityScenarioRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.RuleChain
+import org.junit.runner.RunWith
+
+/**
+ * Test for the impacts of reporting unlock attempts.
+ *
+ * atest TrustTests:UnlockAttemptTest
+ */
+@RunWith(AndroidJUnit4::class)
+class UnlockAttemptTest {
+ private val context = getApplicationContext<Context>()
+ private val trustManager = context.getSystemService(TrustManager::class.java) as TrustManager
+ private val userId = context.userId
+ private val activityScenarioRule = ActivityScenarioRule(TrustTestActivity::class.java)
+ private val screenLockRule = ScreenLockRule(requireStrongAuth = true)
+ private val lockStateTrackingRule = LockStateTrackingRule()
+ private val trustAgentRule =
+ TrustAgentRule<UnlockAttemptTrustAgent>(startUnlocked = false, startEnabled = false)
+
+ private val trustListener = UnlockAttemptTrustListener()
+ private val agent get() = trustAgentRule.agent
+
+ @get:Rule
+ val rule: RuleChain =
+ RuleChain.outerRule(activityScenarioRule)
+ .around(screenLockRule)
+ .around(lockStateTrackingRule)
+ .around(trustAgentRule)
+
+ @Before
+ fun setUp() {
+ trustManager.registerTrustListener(trustListener)
+ }
+
+ @Test
+ fun successfulUnlockAttempt_allowsTrustAgentToStart() =
+ runUnlockAttemptTest(enableAndVerifyTrustAgent = false, managingTrust = false) {
+ trustAgentRule.enableTrustAgent()
+
+ triggerSuccessfulUnlock()
+
+ trustAgentRule.verifyAgentIsRunning(MAX_WAIT_FOR_ENABLED_TRUST_AGENT_TO_START)
+ }
+
+ @Test
+ fun successfulUnlockAttempt_notifiesTrustAgent() =
+ runUnlockAttemptTest(enableAndVerifyTrustAgent = true, managingTrust = true) {
+ val oldSuccessfulCount = agent.successfulUnlockCallCount
+ val oldFailedCount = agent.failedUnlockCallCount
+
+ triggerSuccessfulUnlock()
+
+ assertThat(agent.successfulUnlockCallCount).isEqualTo(oldSuccessfulCount + 1)
+ assertThat(agent.failedUnlockCallCount).isEqualTo(oldFailedCount)
+ }
+
+ @Test
+ fun successfulUnlockAttempt_notifiesTrustListenerOfManagedTrust() =
+ runUnlockAttemptTest(enableAndVerifyTrustAgent = true, managingTrust = true) {
+ val oldTrustManagedChangedCount = trustListener.onTrustManagedChangedCount[userId] ?: 0
+
+ triggerSuccessfulUnlock()
+
+ assertThat(trustListener.onTrustManagedChangedCount[userId] ?: 0).isEqualTo(
+ oldTrustManagedChangedCount + 1
+ )
+ }
+
+ @Test
+ fun failedUnlockAttempt_doesNotAllowTrustAgentToStart() =
+ runUnlockAttemptTest(enableAndVerifyTrustAgent = false, managingTrust = false) {
+ trustAgentRule.enableTrustAgent()
+
+ triggerFailedUnlock()
+
+ trustAgentRule.ensureAgentIsNotRunning(MAX_WAIT_FOR_ENABLED_TRUST_AGENT_TO_START)
+ }
+
+ @Test
+ fun failedUnlockAttempt_notifiesTrustAgent() =
+ runUnlockAttemptTest(enableAndVerifyTrustAgent = true, managingTrust = true) {
+ val oldSuccessfulCount = agent.successfulUnlockCallCount
+ val oldFailedCount = agent.failedUnlockCallCount
+
+ triggerFailedUnlock()
+
+ assertThat(agent.successfulUnlockCallCount).isEqualTo(oldSuccessfulCount)
+ assertThat(agent.failedUnlockCallCount).isEqualTo(oldFailedCount + 1)
+ }
+
+ @Test
+ fun failedUnlockAttempt_doesNotNotifyTrustListenerOfManagedTrust() =
+ runUnlockAttemptTest(enableAndVerifyTrustAgent = true, managingTrust = true) {
+ val oldTrustManagedChangedCount = trustListener.onTrustManagedChangedCount[userId] ?: 0
+
+ triggerFailedUnlock()
+
+ assertThat(trustListener.onTrustManagedChangedCount[userId] ?: 0).isEqualTo(
+ oldTrustManagedChangedCount
+ )
+ }
+
+ private fun runUnlockAttemptTest(
+ enableAndVerifyTrustAgent: Boolean,
+ managingTrust: Boolean,
+ testBlock: () -> Unit,
+ ) {
+ if (enableAndVerifyTrustAgent) {
+ Log.i(TAG, "Triggering successful unlock")
+ triggerSuccessfulUnlock()
+ Log.i(TAG, "Enabling and waiting for trust agent")
+ trustAgentRule.enableAndVerifyTrustAgentIsRunning(
+ MAX_WAIT_FOR_ENABLED_TRUST_AGENT_TO_START
+ )
+ Log.i(TAG, "Managing trust: $managingTrust")
+ agent.setManagingTrust(managingTrust)
+ await()
+ }
+ testBlock()
+ }
+
+ private fun triggerSuccessfulUnlock() {
+ screenLockRule.successfulScreenLockAttempt()
+ trustAgentRule.reportSuccessfulUnlock()
+ await()
+ }
+
+ private fun triggerFailedUnlock() {
+ screenLockRule.failedScreenLockAttempt()
+ trustAgentRule.reportFailedUnlock()
+ await()
+ }
+
+ companion object {
+ private const val TAG = "UnlockAttemptTest"
+ private fun await(millis: Long = 500) = Thread.sleep(millis)
+ private const val MAX_WAIT_FOR_ENABLED_TRUST_AGENT_TO_START = 10000L
+ }
+}
+
+class UnlockAttemptTrustAgent : BaseTrustAgentService() {
+ var successfulUnlockCallCount: Long = 0
+ private set
+ var failedUnlockCallCount: Long = 0
+ private set
+
+ override fun onUnlockAttempt(successful: Boolean) {
+ super.onUnlockAttempt(successful)
+ if (successful) {
+ successfulUnlockCallCount++
+ } else {
+ failedUnlockCallCount++
+ }
+ }
+}
+
+private class UnlockAttemptTrustListener : TestTrustListener() {
+ var enabledTrustAgentsChangedCount = mutableMapOf<Int, Int>()
+ var onTrustManagedChangedCount = mutableMapOf<Int, Int>()
+
+ override fun onEnabledTrustAgentsChanged(userId: Int) {
+ enabledTrustAgentsChangedCount.compute(userId) { _: Int, curr: Int? ->
+ if (curr == null) 0 else curr + 1
+ }
+ }
+
+ data class TrustChangedParams(
+ val enabled: Boolean,
+ val newlyUnlocked: Boolean,
+ val userId: Int,
+ val flags: Int,
+ val trustGrantedMessages: MutableList<String>?
+ )
+
+ val onTrustChangedCalls = mutableListOf<TrustChangedParams>()
+
+ override fun onTrustChanged(
+ enabled: Boolean,
+ newlyUnlocked: Boolean,
+ userId: Int,
+ flags: Int,
+ trustGrantedMessages: MutableList<String>
+ ) {
+ onTrustChangedCalls += TrustChangedParams(
+ enabled, newlyUnlocked, userId, flags, trustGrantedMessages
+ )
+ }
+
+ override fun onTrustManagedChanged(enabled: Boolean, userId: Int) {
+ onTrustManagedChangedCount.compute(userId) { _: Int, curr: Int? ->
+ if (curr == null) 0 else curr + 1
+ }
+ }
+}
diff --git a/tests/TrustTests/src/android/trust/test/lib/ScreenLockRule.kt b/tests/TrustTests/src/android/trust/test/lib/ScreenLockRule.kt
index f1edca3..1ccdcc6 100644
--- a/tests/TrustTests/src/android/trust/test/lib/ScreenLockRule.kt
+++ b/tests/TrustTests/src/android/trust/test/lib/ScreenLockRule.kt
@@ -24,6 +24,8 @@
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import androidx.test.uiautomator.UiDevice
import com.android.internal.widget.LockPatternUtils
+import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED
+import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN
import com.android.internal.widget.LockscreenCredential
import com.google.common.truth.Truth.assertWithMessage
import org.junit.rules.TestRule
@@ -32,13 +34,18 @@
/**
* Sets a screen lock on the device for the duration of the test.
+ *
+ * @param requireStrongAuth Whether a strong auth is required at the beginning.
+ * If true, trust agents will not be available until the user verifies their credentials.
*/
-class ScreenLockRule : TestRule {
+class ScreenLockRule(val requireStrongAuth: Boolean = false) : TestRule {
private val context: Context = getApplicationContext()
+ private val userId = context.userId
private val uiDevice = UiDevice.getInstance(getInstrumentation())
private val windowManager = checkNotNull(WindowManagerGlobal.getWindowManagerService())
private val lockPatternUtils = LockPatternUtils(context)
private var instantLockSavedValue = false
+ private var strongAuthSavedValue: Int = 0
override fun apply(base: Statement, description: Description) = object : Statement() {
override fun evaluate() {
@@ -46,10 +53,12 @@
dismissKeyguard()
setScreenLock()
setLockOnPowerButton()
+ configureStrongAuthState()
try {
base.evaluate()
} finally {
+ restoreStrongAuthState()
removeScreenLock()
revertLockOnPowerButton()
dismissKeyguard()
@@ -57,6 +66,22 @@
}
}
+ private fun configureStrongAuthState() {
+ strongAuthSavedValue = lockPatternUtils.getStrongAuthForUser(userId)
+ if (requireStrongAuth) {
+ Log.d(TAG, "Triggering strong auth due to simulated lockdown")
+ lockPatternUtils.requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN, userId)
+ wait("strong auth required after lockdown") {
+ lockPatternUtils.getStrongAuthForUser(userId) ==
+ STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN
+ }
+ }
+ }
+
+ private fun restoreStrongAuthState() {
+ lockPatternUtils.requireStrongAuth(strongAuthSavedValue, userId)
+ }
+
private fun verifyNoScreenLockAlreadySet() {
assertWithMessage("Screen Lock must not already be set on device")
.that(lockPatternUtils.isSecure(context.userId))
@@ -82,6 +107,22 @@
}
}
+ fun successfulScreenLockAttempt() {
+ lockPatternUtils.verifyCredential(LockscreenCredential.createPin(PIN), context.userId, 0)
+ lockPatternUtils.userPresent(context.userId)
+ wait("strong auth not required") {
+ lockPatternUtils.getStrongAuthForUser(context.userId) == STRONG_AUTH_NOT_REQUIRED
+ }
+ }
+
+ fun failedScreenLockAttempt() {
+ lockPatternUtils.verifyCredential(
+ LockscreenCredential.createPin(WRONG_PIN),
+ context.userId,
+ 0
+ )
+ }
+
private fun setScreenLock() {
lockPatternUtils.setLockCredential(
LockscreenCredential.createPin(PIN),
@@ -121,5 +162,6 @@
companion object {
private const val TAG = "ScreenLockRule"
private const val PIN = "0000"
+ private const val WRONG_PIN = "0001"
}
}
diff --git a/tests/TrustTests/src/android/trust/test/lib/TrustAgentRule.kt b/tests/TrustTests/src/android/trust/test/lib/TrustAgentRule.kt
index 18bc029..404c6d9 100644
--- a/tests/TrustTests/src/android/trust/test/lib/TrustAgentRule.kt
+++ b/tests/TrustTests/src/android/trust/test/lib/TrustAgentRule.kt
@@ -20,14 +20,15 @@
import android.content.ComponentName
import android.content.Context
import android.trust.BaseTrustAgentService
+import android.trust.test.lib.TrustAgentRule.Companion.invoke
import android.util.Log
import androidx.test.core.app.ApplicationProvider.getApplicationContext
import com.android.internal.widget.LockPatternUtils
import com.google.common.truth.Truth.assertWithMessage
+import kotlin.reflect.KClass
import org.junit.rules.TestRule
import org.junit.runner.Description
import org.junit.runners.model.Statement
-import kotlin.reflect.KClass
/**
* Enables a trust agent and causes the system service to bind to it.
@@ -37,7 +38,9 @@
* @constructor Creates the rule. Do not use; instead, use [invoke].
*/
class TrustAgentRule<T : BaseTrustAgentService>(
- private val serviceClass: KClass<T>
+ private val serviceClass: KClass<T>,
+ private val startUnlocked: Boolean,
+ private val startEnabled: Boolean,
) : TestRule {
private val context: Context = getApplicationContext()
private val trustManager = context.getSystemService(TrustManager::class.java) as TrustManager
@@ -48,11 +51,18 @@
override fun apply(base: Statement, description: Description) = object : Statement() {
override fun evaluate() {
verifyTrustServiceRunning()
- unlockDeviceWithCredential()
- enableTrustAgent()
+ if (startUnlocked) {
+ reportSuccessfulUnlock()
+ } else {
+ Log.i(TAG, "Trust manager not starting in unlocked state")
+ }
try {
- verifyAgentIsRunning()
+ if (startEnabled) {
+ enableAndVerifyTrustAgentIsRunning()
+ } else {
+ Log.i(TAG, "Trust agent ${serviceClass.simpleName} not enabled")
+ }
base.evaluate()
} finally {
disableTrustAgent()
@@ -64,12 +74,22 @@
assertWithMessage("Trust service is not running").that(trustManager).isNotNull()
}
- private fun unlockDeviceWithCredential() {
- Log.d(TAG, "Unlocking device with credential")
+ fun reportSuccessfulUnlock() {
+ Log.i(TAG, "Reporting successful unlock")
trustManager.reportUnlockAttempt(true, context.userId)
}
- private fun enableTrustAgent() {
+ fun reportFailedUnlock() {
+ Log.i(TAG, "Reporting failed unlock")
+ trustManager.reportUnlockAttempt(false, context.userId)
+ }
+
+ fun enableAndVerifyTrustAgentIsRunning(maxWait: Long = 30000L) {
+ enableTrustAgent()
+ verifyAgentIsRunning(maxWait)
+ }
+
+ fun enableTrustAgent() {
val componentName = ComponentName(context, serviceClass.java)
val userId = context.userId
Log.i(TAG, "Enabling trust agent ${componentName.flattenToString()} for user $userId")
@@ -79,12 +99,18 @@
lockPatternUtils.setEnabledTrustAgents(agents, userId)
}
- private fun verifyAgentIsRunning() {
- wait("${serviceClass.simpleName} to be running") {
+ fun verifyAgentIsRunning(maxWait: Long = 30000L) {
+ wait("${serviceClass.simpleName} to be running", maxWait) {
BaseTrustAgentService.instance(serviceClass) != null
}
}
+ fun ensureAgentIsNotRunning(window: Long = 30000L) {
+ ensure("${serviceClass.simpleName} is not running", window) {
+ BaseTrustAgentService.instance(serviceClass) == null
+ }
+ }
+
private fun disableTrustAgent() {
val componentName = ComponentName(context, serviceClass.java)
val userId = context.userId
@@ -97,13 +123,23 @@
companion object {
/**
- * Creates a new rule for the specified agent class. Example usage:
+ * Creates a new rule for the specified agent class. Starts with the device unlocked and
+ * the trust agent enabled. Example usage:
* ```
* @get:Rule val rule = TrustAgentRule<MyTestAgent>()
* ```
+ *
+ * Also supports setting different device lock and trust agent enablement states:
+ * ```
+ * @get:Rule val rule = TrustAgentRule<MyTestAgent>(startUnlocked = false, startEnabled = false)
+ * ```
*/
- inline operator fun <reified T : BaseTrustAgentService> invoke() =
- TrustAgentRule(T::class)
+ inline operator fun <reified T : BaseTrustAgentService> invoke(
+ startUnlocked: Boolean = true,
+ startEnabled: Boolean = true,
+ ) =
+ TrustAgentRule(T::class, startUnlocked, startEnabled)
+
private const val TAG = "TrustAgentRule"
}
diff --git a/tests/TrustTests/src/android/trust/test/lib/utils.kt b/tests/TrustTests/src/android/trust/test/lib/Utils.kt
similarity index 63%
rename from tests/TrustTests/src/android/trust/test/lib/utils.kt
rename to tests/TrustTests/src/android/trust/test/lib/Utils.kt
index e047202..3b32b47 100644
--- a/tests/TrustTests/src/android/trust/test/lib/utils.kt
+++ b/tests/TrustTests/src/android/trust/test/lib/Utils.kt
@@ -39,7 +39,7 @@
) {
var waited = 0L
var count = 0
- while (!conditionFunction.invoke(count)) {
+ while (!conditionFunction(count)) {
assertWithMessage("Condition exceeded maximum wait time of $maxWait ms: $description")
.that(waited <= maxWait)
.isTrue()
@@ -49,3 +49,34 @@
Thread.sleep(rate)
}
}
+
+/**
+ * Ensures that [conditionFunction] is true with a failed assertion if it is not within [window]
+ * ms.
+ *
+ * The condition function can perform additional logic (for example, logging or attempting to make
+ * the condition become true).
+ *
+ * @param conditionFunction function which takes the attempt count & returns whether the condition
+ * is met
+ */
+internal fun ensure(
+ description: String? = null,
+ window: Long = 30000L,
+ rate: Long = 50L,
+ conditionFunction: (count: Int) -> Boolean
+) {
+ var waited = 0L
+ var count = 0
+ while (waited <= window) {
+ assertWithMessage("Condition failed within $window ms: $description").that(
+ conditionFunction(
+ count
+ )
+ ).isTrue()
+ waited += rate
+ count++
+ Log.i(TAG, "Ensuring $description ($waited/$window) #$count")
+ Thread.sleep(rate)
+ }
+}