diff options
24 files changed, 722 insertions, 425 deletions
diff --git a/api/coverage/tools/ExtractFlaggedApis.kt b/api/coverage/tools/ExtractFlaggedApis.kt index 5efda98a1518..bf67187f4bad 100644 --- a/api/coverage/tools/ExtractFlaggedApis.kt +++ b/api/coverage/tools/ExtractFlaggedApis.kt @@ -75,10 +75,10 @@ fun addFlaggedApi(builder: FlagApiMap.Builder, api: JavaMethod.Builder, flag: St 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/api/gen_combined_removed_dex.sh b/api/gen_combined_removed_dex.sh index e0153f7c1091..2860e2ed17c2 100755 --- a/api/gen_combined_removed_dex.sh +++ b/api/gen_combined_removed_dex.sh @@ -6,6 +6,6 @@ shift 2 # Convert each removed.txt to the "dex format" equivalent, and print all output. for f in "$@"; do - "$metalava_path" signature-to-dex "$f" "${tmp_dir}/tmp" + "$metalava_path" signature-to-dex "$f" --out "${tmp_dir}/tmp" cat "${tmp_dir}/tmp" done diff --git a/core/java/android/os/DeadObjectException.java b/core/java/android/os/DeadObjectException.java index fc3870e812a2..0a50778dce72 100644 --- a/core/java/android/os/DeadObjectException.java +++ b/core/java/android/os/DeadObjectException.java @@ -26,7 +26,7 @@ import android.os.RemoteException; * receive this error from an app, at a minimum, you should * recover by resetting the connection. For instance, you should * drop the binder, clean up associated state, and reset your - * connection to the service which through this error. In order + * connection to the service which threw this error. In order * to simplify your error recovery paths, you may also want to * "simply" restart your process. However, this may not be an * option if the service you are talking to is unreliable or diff --git a/core/java/android/view/autofill/OWNERS b/core/java/android/view/autofill/OWNERS index 898947adcd1b..7f3b4e5a21b3 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 82367834f93d..511c6802677e 100644 --- a/core/java/com/android/internal/widget/ILockSettings.aidl +++ b/core/java/com/android/internal/widget/ILockSettings.aidl @@ -109,4 +109,5 @@ interface ILockSettings { 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 e46b8d7c5fae..f4ad487f48ac 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -449,6 +449,21 @@ public class LockPatternUtils { } /** + * 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 0734e6827d4d..11c220b14bcc 100644 --- a/core/java/com/android/internal/widget/LockPatternView.java +++ b/core/java/com/android/internal/widget/LockPatternView.java @@ -261,6 +261,8 @@ public class LockPatternView extends View { public float lineEndY = Float.MIN_VALUE; @Nullable Animator activationAnimator; + @Nullable + Animator deactivationAnimator; } /** @@ -667,7 +669,7 @@ public class LockPatternView extends View { */ private void resetPattern() { if (mKeepDotActivated && !mPattern.isEmpty()) { - resetLastActivatedCellProgress(); + resetPatternCellSize(); } mPattern.clear(); mPatternPath.reset(); @@ -676,14 +678,20 @@ public class LockPatternView extends View { 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 @@ public class LockPatternView extends View { !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 @@ public class LockPatternView extends View { } 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 @@ public class LockPatternView extends View { .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 @@ public class LockPatternView extends View { 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 @@ public class LockPatternView extends View { 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 @@ public class LockPatternView extends View { 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 @@ public class LockPatternView extends View { // 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 @@ public class LockPatternView extends View { 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 e2672f5b03ba..cf2f202a03ac 100644 --- a/core/java/com/android/internal/widget/OWNERS +++ b/core/java/com/android/internal/widget/OWNERS @@ -9,18 +9,18 @@ per-file *Lockscreen* = file:/services/core/java/com/android/server/locksettings 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/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml index 67cceb5d5343..581dee571a69 100644 --- a/core/res/res/xml/sms_short_codes.xml +++ b/core/res/res/xml/sms_short_codes.xml @@ -185,6 +185,9 @@ https://www.itu.int/dms_pub/itu-t/oth/02/02/T020200006B0001PDFE.pdf --> <shortcode country="it" pattern="\\d{5}" premium="44[0-4]\\d{2}|47[0-4]\\d{2}|48[0-4]\\d{2}|44[5-9]\\d{4}|47[5-9]\\d{4}|48[5-9]\\d{4}|455\\d{2}|499\\d{2}" free="116\\d{3}|4112503|40\\d{0,12}" standard="430\\d{2}|431\\d{2}|434\\d{4}|435\\d{4}|439\\d{7}" /> + <!-- Jordan: 1-5 digits (standard system default, not country specific) --> + <shortcode country="jo" pattern="\\d{1,5}" free="99066" /> + <!-- Japan: 8083 used by SOFTBANK_DCB_2 --> <shortcode country="jp" pattern="\\d{1,5}" free="8083" /> 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 b90480a1e794..92a7d8ef890d 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 org.mockito.ArgumentCaptor; import java.nio.charset.StandardCharsets; import java.util.List; +import java.util.concurrent.CompletableFuture; @RunWith(AndroidJUnit4.class) @SmallTest @@ -316,6 +317,40 @@ public class LockPatternUtilsTest { 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/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 000000000000..482aaab6bc74 --- /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/media/jni/Android.bp b/media/jni/Android.bp index 21415166d4ed..1ed6476fb7d0 100644 --- a/media/jni/Android.bp +++ b/media/jni/Android.bp @@ -79,7 +79,6 @@ cc_library_shared { "libcamera_client", "libmtp", "libpiex", - "libprocessgroup", "libandroidfw", "libhidlallocatorutils", "libhidlbase", diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS index 2545620a2630..a627a3967802 100644 --- a/services/core/java/com/android/server/OWNERS +++ b/services/core/java/com/android/server/OWNERS @@ -48,3 +48,6 @@ per-file VcnManagementService.java = file:/services/core/java/com/android/server # 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 dfd148dfc0ec..c2cb5e90ca58 100644 --- a/services/core/java/com/android/server/RescueParty.java +++ b/services/core/java/com/android/server/RescueParty.java @@ -241,12 +241,14 @@ public class RescueParty { * 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 @@ public class RescueParty { * 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 class RescueParty { } 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 @@ public class RescueParty { } } + 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 @@ public class RescueParty { * @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 @@ public class RescueParty { 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 @@ public class RescueParty { } } + /** + * 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 @@ public class RescueParty { 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 @@ public class RescueParty { 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 @@ public class RescueParty { 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 @@ public class RescueParty { 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()) { + if (!Flags.deprecateFlagsAndSettingsResets()) { + // 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.Secure.resetToDefaultsAsUser(resolver, null, mode, userId); + Settings.Global.resetToDefaultsAsUser(resolver, null, mode, + UserHandle.SYSTEM.getIdentifier()); } catch (Exception e) { - res = new RuntimeException("Failed to reset secure settings for " + userId, 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; } - } - if (res != null) { - throw res; } } @@ -728,18 +803,28 @@ public class RescueParty { @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 @@ public class RescueParty { 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 @@ public class RescueParty { 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 @@ public class RescueParty { 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 @@ public class RescueParty { 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 @@ public class RescueParty { 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); - } - namespaceSet.add(namespace); - // Record it in namespace to calling packages map - Set<String> callingPackageSet = mNamespaceCallingPackageSetMap.get(namespace); - if (callingPackageSet == null) { - callingPackageSet = new ArraySet<>(); + 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); } - callingPackageSet.add(callingPackage); - mNamespaceCallingPackageSetMap.put(namespace, callingPackageSet); } private synchronized Set<String> getAffectedNamespaceSet(String failedPackage) { @@ -881,6 +980,18 @@ public class RescueParty { } } + /** + * 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 @@ public class RescueParty { } } + 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 598f086db94d..4faadcbe0cca 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 @@ public class LmkdConnection { @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 @@ public class LmkdConnection { 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 @@ public class LmkdConnection { 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 @@ public class LmkdConnection { } 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 64e3e8ed29c1..97678aa922a4 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 @@ public final class ProcessList { 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/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index 71576465e035..7aae91b98348 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 @@ public class LockSettingsService extends ILockSettings.Stub { } } + @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 89c4f0f276af..91990048e356 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 @@ final class InstallPackageHelper { 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 d1f91c89a04e..c4e3fa4213a9 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 @@ class Rollback { 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 c85ceac9ea55..4f28e023da92 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 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve } } + 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 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve @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/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java index 977a8a05d6f3..c76bcf804ee4 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 @@ public final class ProfcollectForwardingService extends SystemService { 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 @@ public final class ProfcollectForwardingService extends SystemService { // 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 @@ public final class ProfcollectForwardingService extends SystemService { 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_system(traceTag); } 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 337789950a32..f2acbc31b008 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.verify; 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.eq; 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.crashrecovery.flags.Flags; 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.After; 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.List; 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 @@ public class RescuePartyTest { 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 @@ public class RescuePartyTest { @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 @@ public class RescuePartyTest { } @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 @@ public class RescuePartyTest { 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 @@ public class RescuePartyTest { 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 @@ public class RescuePartyTest { } @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 @@ public class RescuePartyTest { } @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 @@ public class RescuePartyTest { } @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 @@ public class RescuePartyTest { } @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 @@ public class RescuePartyTest { } @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 @@ public class RescuePartyTest { } @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 @@ public class RescuePartyTest { } @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 @@ public class RescuePartyTest { } @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 @@ public class RescuePartyTest { } @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 @@ public class RescuePartyTest { } @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 @@ public class RescuePartyTest { } @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 @@ public class RescuePartyTest { @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 @@ public class RescuePartyTest { @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 @@ public class RescuePartyTest { } @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 @@ public class RescuePartyTest { } @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 @@ public class RescuePartyTest { 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 @@ public class RescuePartyTest { } @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 @@ public class RescuePartyTest { } @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 @@ public class RescuePartyTest { } @Test + @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS) public void testResetDeviceConfigForPackagesOnlyPresetMap() { RescueParty.onSettingsProviderPublished(mMockContext); verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver), @@ -835,7 +755,7 @@ public class RescuePartyTest { 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 @@ public class RescuePartyTest { } @Test + @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS) public void testResetDeviceConfigForPackagesBothMaps() { RescueParty.onSettingsProviderPublished(mMockContext); verify(() -> DeviceConfig.setMonitorCallback(eq(mMockContentResolver), @@ -884,6 +805,7 @@ public class RescuePartyTest { } @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/servicestests/src/com/android/server/locksettings/LockscreenRepairModeTest.java b/services/tests/servicestests/src/com/android/server/locksettings/LockscreenRepairModeTest.java index 70150c507460..4396c679ec24 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 @@ package com.android.server.locksettings; 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 @@ public class LockscreenRepairModeTest extends BaseLockSettingsServiceTests { .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/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java b/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java index 489ef4444e1d..3722fefb12ad 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.net.ConnectivityModuleConnector.ConnectivityModuleHealthListener; 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 @@ public class CrashRecoveryTest { } @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 @@ public class CrashRecoveryTest { 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)); |