diff options
29 files changed, 455 insertions, 293 deletions
diff --git a/core/tests/coretests/src/android/app/KeyguardManagerTest.java b/core/tests/coretests/src/android/app/KeyguardManagerTest.java index 7231fbd3b7eb..958906c36d05 100644 --- a/core/tests/coretests/src/android/app/KeyguardManagerTest.java +++ b/core/tests/coretests/src/android/app/KeyguardManagerTest.java @@ -19,6 +19,7 @@ package android.app; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.doReturn; @@ -26,6 +27,7 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import android.app.admin.DevicePolicyManager; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -209,6 +211,42 @@ public class KeyguardManagerTest { verifyDeviceLockedAndRemoveLock(); } + @Test + public void createConfirmDeviceCredentialForRemoteValidationIntent() { + RemoteLockscreenValidationSession remoteLockscreenValidationSession = + new RemoteLockscreenValidationSession.Builder() + .setSourcePublicKey("sourcePublicKey".getBytes()) + .build(); + ComponentName componentName = new ComponentName("pkg", "cls"); + String title = "title"; + String description = "description"; + String checkboxLabel = "checkboxLabel"; + String alternateButtonLabel = "alternateButtonLabel"; + + Intent intent = mKeyguardManager.createConfirmDeviceCredentialForRemoteValidationIntent( + remoteLockscreenValidationSession, + componentName, + title, + description, + checkboxLabel, + alternateButtonLabel + ); + + assertNotNull(intent); + assertEquals(KeyguardManager.ACTION_CONFIRM_REMOTE_DEVICE_CREDENTIAL, intent.getAction()); + assertEquals(remoteLockscreenValidationSession, + intent.getParcelableExtra( + KeyguardManager.EXTRA_REMOTE_LOCKSCREEN_VALIDATION_SESSION, + RemoteLockscreenValidationSession.class)); + assertEquals(componentName, + intent.getParcelableExtra(Intent.EXTRA_COMPONENT_NAME, ComponentName.class)); + assertEquals(title, intent.getStringExtra(KeyguardManager.EXTRA_TITLE)); + assertEquals(description, intent.getStringExtra(KeyguardManager.EXTRA_DESCRIPTION)); + assertEquals(checkboxLabel, intent.getStringExtra(KeyguardManager.EXTRA_CHECKBOX_LABEL)); + assertEquals(alternateButtonLabel, + intent.getStringExtra(KeyguardManager.EXTRA_ALTERNATE_BUTTON_LABEL)); + } + private void verifyDeviceLockedAndRemoveLock() { assertTrue(mKeyguardManager.isDeviceSecure()); assertTrue("Failed to remove new password that was set in the test case.", diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java index f9aa1bd98e38..1e6e50359cf3 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java @@ -239,7 +239,7 @@ public class WindowAreaComponentImpl implements WindowAreaComponent, // display state, so we have to look through all displays to match the address final Display[] displays = mDisplayManager.getDisplays( DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED); - final Display defaultDisplay = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY); + for (int i = 0; i < displays.length; i++) { DisplayAddress.Physical address = @@ -255,6 +255,8 @@ public class WindowAreaComponentImpl implements WindowAreaComponent, // TODO(b/287170025): This should be something like if (!rearDisplay.isEnabled) // instead. Currently when the rear display is disabled, its state is STATE_OFF. if (rearDisplay.getDisplayId() != Display.DEFAULT_DISPLAY) { + final Display defaultDisplay = mDisplayManager + .getDisplay(Display.DEFAULT_DISPLAY); rotateRearDisplayMetricsIfNeeded(defaultDisplay.getRotation(), rearDisplay.getRotation(), rearDisplayMetrics); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java index acbdbf9d6769..cff317259f1e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java @@ -710,4 +710,19 @@ public abstract class WMShellModule { static DesktopModeTaskRepository provideDesktopModeTaskRepository() { return new DesktopModeTaskRepository(); } + + // + // Misc + // + + // TODO: Temporarily move dependencies to this instead of ShellInit since that is needed to add + // the callback. We will be moving to a different explicit startup mechanism in a follow- up CL. + @WMSingleton + @ShellCreateTriggerOverride + @Provides + static Object provideIndependentShellComponentsToCreate( + DefaultMixedHandler defaultMixedHandler, + Optional<DesktopModeController> desktopModeController) { + return new Object(); + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java index da14d03adb35..964ba9f9aa7c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java @@ -2365,6 +2365,11 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, out); } } + + // When split in the background, it should be only opening/dismissing transition and + // would keep out not empty. Prevent intercepting all transitions for split screen when + // it is in the background and not identify to handle it. + return (!out.isEmpty() || isSplitScreenVisible()) ? out : null; } else { if (isOpening && getStageOfTask(triggerTask) != null) { // One task is appearing into split, prepare to enter split screen. @@ -2373,8 +2378,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, mSplitTransitions.setEnterTransition(transition, request.getRemoteTransition(), TRANSIT_SPLIT_SCREEN_PAIR_OPEN, !mIsDropEntering); } + return out; } - return out; } /** @@ -2506,8 +2511,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, && getStageType(dismissStages.valueAt(0)) == STAGE_TYPE_MAIN) || mMainStage.getChildCount() == 0 ? STAGE_TYPE_SIDE : STAGE_TYPE_MAIN; // If there is a fullscreen opening change, we should not bring stage to top. - prepareExitSplitScreen(record.mContainShowFullscreenChange - ? STAGE_TYPE_UNDEFINED : dismissTop, wct); + prepareExitSplitScreen( + !record.mContainShowFullscreenChange && isSplitScreenVisible() + ? dismissTop : STAGE_TYPE_UNDEFINED, wct); mSplitTransitions.startDismissTransition(wct, this, dismissTop, EXIT_REASON_APP_FINISHED); // This can happen in some pathological cases. For example: diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt index 8cba2ab0b70b..702cc05f7f5f 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt @@ -56,7 +56,6 @@ private val KNOWN_PLUGINS = "com.android.systemui.falcon.four" to listOf(ClockMetadata("DIGITAL_CLOCK_GROWTH")), "com.android.systemui.falcon.five" to listOf(ClockMetadata("DIGITAL_CLOCK_HANDWRITTEN")), "com.android.systemui.falcon.six" to listOf(ClockMetadata("DIGITAL_CLOCK_INFLATE")), - "com.android.systemui.falcon.seven" to listOf(ClockMetadata("DIGITAL_CLOCK_METRO")), "com.android.systemui.falcon.eight" to listOf(ClockMetadata("DIGITAL_CLOCK_NUMBEROVERLAP")), "com.android.systemui.falcon.nine" to listOf(ClockMetadata("DIGITAL_CLOCK_WEATHER")), ) diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml index 28f5f3d9edd7..badad584824b 100644 --- a/packages/SystemUI/res-keyguard/values/strings.xml +++ b/packages/SystemUI/res-keyguard/values/strings.xml @@ -358,12 +358,12 @@ <!-- Message shown to prepare for an unattended update (OTA). Also known as an over-the-air (OTA) update. [CHAR LIMIT=70] --> <string name="kg_prompt_unattended_update_pattern">Draw pattern to install update later</string> - <!-- Message shown after an unattended update (OTA) asking the user to enter their PIN. Also known as an over-the-air (OTA) update. [CHAR LIMIT=70] --> + <!-- Message shown after an unattended mainline (major) update asking the user to enter their PIN. [CHAR LIMIT=70] --> <string name="kg_prompt_after_update_pin">Device updated. Enter PIN to continue.</string> - <!-- Message shown after an unattended update (OTA) asking the user to enter their password. Also known as an over-the-air (OTA) update. [CHAR LIMIT=70] --> + <!-- Message shown after an unattended mainline (major) update asking the user to enter their password. [CHAR LIMIT=70] --> <string name="kg_prompt_after_update_password">Device updated. Enter password to continue.</string> - <!-- Message shown after an unattended update (OTA) asking the user to enter their pattern. Also known as an over-the-air (OTA) update. [CHAR LIMIT=70] --> + <!-- Message shown after an unattended mainline (major) update asking the user to enter their pattern. [CHAR LIMIT=70] --> <string name="kg_prompt_after_update_pattern">Device updated. Draw pattern to continue.</string> </resources> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java index 7a0a24a85eaf..03d9eb3455fd 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java @@ -23,6 +23,7 @@ import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NONE; import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT; import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_PREPARE_FOR_UPDATE; import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_RESTART; +import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_RESTART_FOR_MAINLINE_UPDATE; import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TIMEOUT; import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TRUSTAGENT_EXPIRED; import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_USER_REQUEST; @@ -99,6 +100,8 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView { switch (reason) { case PROMPT_REASON_RESTART: return R.string.kg_prompt_reason_restart_password; + case PROMPT_REASON_RESTART_FOR_MAINLINE_UPDATE: + return R.string.kg_prompt_after_update_password; case PROMPT_REASON_TIMEOUT: return R.string.kg_prompt_reason_timeout_password; case PROMPT_REASON_DEVICE_ADMIN: @@ -106,7 +109,7 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView { case PROMPT_REASON_USER_REQUEST: return R.string.kg_prompt_after_user_lockdown_password; case PROMPT_REASON_PREPARE_FOR_UPDATE: - return R.string.kg_prompt_reason_timeout_password; + return R.string.kg_prompt_unattended_update_password; case PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT: return R.string.kg_prompt_reason_timeout_password; case PROMPT_REASON_TRUSTAGENT_EXPIRED: diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java index be423767e6d0..3d255a58cf8e 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java @@ -304,6 +304,9 @@ public class KeyguardPatternViewController case PROMPT_REASON_RESTART: resId = R.string.kg_prompt_reason_restart_pattern; break; + case PROMPT_REASON_RESTART_FOR_MAINLINE_UPDATE: + resId = R.string.kg_prompt_after_update_pattern; + break; case PROMPT_REASON_TIMEOUT: resId = R.string.kg_prompt_reason_timeout_pattern; break; @@ -314,7 +317,7 @@ public class KeyguardPatternViewController resId = R.string.kg_prompt_after_user_lockdown_pattern; break; case PROMPT_REASON_PREPARE_FOR_UPDATE: - resId = R.string.kg_prompt_reason_timeout_pattern; + resId = R.string.kg_prompt_unattended_update_pattern; break; case PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT: resId = R.string.kg_prompt_reason_timeout_pattern; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java index 687436c5d388..38e5dc57d316 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java @@ -21,6 +21,7 @@ import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NONE; import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT; import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_PREPARE_FOR_UPDATE; import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_RESTART; +import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_RESTART_FOR_MAINLINE_UPDATE; import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TIMEOUT; import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TRUSTAGENT_EXPIRED; import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_USER_REQUEST; @@ -113,6 +114,8 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView switch (reason) { case PROMPT_REASON_RESTART: return R.string.kg_prompt_reason_restart_pin; + case PROMPT_REASON_RESTART_FOR_MAINLINE_UPDATE: + return R.string.kg_prompt_after_update_pin; case PROMPT_REASON_TIMEOUT: return R.string.kg_prompt_reason_timeout_pin; case PROMPT_REASON_DEVICE_ADMIN: @@ -120,7 +123,7 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView case PROMPT_REASON_USER_REQUEST: return R.string.kg_prompt_after_user_lockdown_pin; case PROMPT_REASON_PREPARE_FOR_UPDATE: - return R.string.kg_prompt_reason_timeout_pin; + return R.string.kg_prompt_unattended_update_pin; case PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT: return R.string.kg_prompt_reason_timeout_pin; case PROMPT_REASON_TRUSTAGENT_EXPIRED: diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java index 419303d71f97..21960e219fc9 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java @@ -103,6 +103,12 @@ public interface KeyguardSecurityView { int PROMPT_REASON_PRIMARY_AUTH_LOCKED_OUT = 15; /** + * Strong auth is required because the device has just booted because of an automatic + * mainline update. + */ + int PROMPT_REASON_RESTART_FOR_MAINLINE_UPDATE = 16; + + /** * Reset the view and prepare to take input. This should do things like clearing the * password or pattern and clear error messages. */ diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt index 3f2054029459..10cacb201c29 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt @@ -740,6 +740,12 @@ object Flags { val ZJ_285570694_LOCKSCREEN_TRANSITION_FROM_AOD = releasedFlag(2900, "zj_285570694_lockscreen_transition_from_aod") + // 3000 - dream + // TODO(b/285059790) : Tracking Bug + @JvmField + val LOCKSCREEN_WALLPAPER_DREAM_ENABLED = + unreleasedFlag(3000, name = "enable_lockscreen_wallpaper_dream") + // TODO(b/283084712): Tracking Bug @JvmField val IMPROVED_HUN_ANIMATIONS = unreleasedFlag(283084712, "improved_hun_animations") diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java index a2c940bd298c..e6053fb3e352 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java @@ -80,6 +80,8 @@ import com.android.wm.shell.util.CounterRotator; import com.android.wm.shell.util.TransitionUtil; import java.util.ArrayList; +import java.util.Map; +import java.util.WeakHashMap; import javax.inject.Inject; @@ -192,7 +194,8 @@ public class KeyguardService extends Service { private final CounterRotator mCounterRotator = new CounterRotator(); @GuardedBy("mLeashMap") - private IRemoteTransitionFinishedCallback mFinishCallback = null; + private final Map<IBinder, IRemoteTransitionFinishedCallback> mFinishCallbacks = + new WeakHashMap<>(); @Override public void startAnimation(IBinder transition, TransitionInfo info, @@ -206,7 +209,7 @@ public class KeyguardService extends Service { synchronized (mLeashMap) { apps = wrap(info, false /* wallpapers */, t, mLeashMap, mCounterRotator); wallpapers = wrap(info, true /* wallpapers */, t, mLeashMap, mCounterRotator); - mFinishCallback = finishCallback; + mFinishCallbacks.put(transition, finishCallback); } // Set alpha back to 1 for the independent changes because we will be animating @@ -229,7 +232,7 @@ public class KeyguardService extends Service { @Override public void onAnimationFinished() throws RemoteException { Slog.d(TAG, "Finish IRemoteAnimationRunner."); - finish(); + finish(transition); } }); } @@ -246,7 +249,7 @@ public class KeyguardService extends Service { try { runner.onAnimationCancelled(); - finish(); + finish(currentTransition); } catch (RemoteException e) { // nothing, we'll just let it finish on its own I guess. } @@ -260,7 +263,7 @@ public class KeyguardService extends Service { } } - private void finish() throws RemoteException { + private void finish(IBinder transition) throws RemoteException { IRemoteTransitionFinishedCallback finishCallback = null; SurfaceControl.Transaction finishTransaction = null; @@ -271,8 +274,7 @@ public class KeyguardService extends Service { mCounterRotator.cleanUp(finishTransaction); } mLeashMap.clear(); - finishCallback = mFinishCallback; - mFinishCallback = null; + finishCallback = mFinishCallbacks.remove(transition); } if (finishCallback != null) { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 5bf56a1da32f..ff62aea10e5b 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -137,6 +137,7 @@ import com.android.systemui.dreams.DreamOverlayStateController; import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; +import com.android.systemui.flags.SystemPropertiesHelper; import com.android.systemui.keyguard.dagger.KeyguardModule; import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel; import com.android.systemui.log.SessionTracker; @@ -167,6 +168,7 @@ import dagger.Lazy; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; +import java.util.Objects; import java.util.concurrent.Executor; import java.util.function.Consumer; @@ -280,6 +282,8 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, * keyguard to show even if it is disabled for the current user. */ public static final String OPTION_FORCE_SHOW = "force_show"; + public static final String SYS_BOOT_REASON_PROP = "sys.boot.reason.last"; + public static final String REBOOT_MAINLINE_UPDATE = "reboot,mainline_update"; private final DreamOverlayStateController mDreamOverlayStateController; /** The stream type that the lock sounds are tied to. */ @@ -315,6 +319,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, /** UserSwitcherController for creating guest user on boot complete */ private final UserSwitcherController mUserSwitcherController; + private SystemPropertiesHelper mSystemPropertiesHelper; /** * Used to keep the device awake while to ensure the keyguard finishes opening before @@ -846,7 +851,12 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, strongAuthTracker.isNonStrongBiometricAllowedAfterIdleTimeout(currentUser); if (any && !strongAuthTracker.hasUserAuthenticatedSinceBoot()) { - return KeyguardSecurityView.PROMPT_REASON_RESTART; + String reasonForReboot = mSystemPropertiesHelper.get(SYS_BOOT_REASON_PROP); + if (Objects.equals(reasonForReboot, REBOOT_MAINLINE_UPDATE)) { + return KeyguardSecurityView.PROMPT_REASON_RESTART_FOR_MAINLINE_UPDATE; + } else { + return KeyguardSecurityView.PROMPT_REASON_RESTART; + } } else if (any && (strongAuth & STRONG_AUTH_REQUIRED_AFTER_TIMEOUT) != 0) { return KeyguardSecurityView.PROMPT_REASON_TIMEOUT; } else if (any && (strongAuth & STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN) != 0) { @@ -1304,7 +1314,8 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, Lazy<ScrimController> scrimControllerLazy, FeatureFlags featureFlags, @Main CoroutineDispatcher mainDispatcher, - Lazy<DreamingToLockscreenTransitionViewModel> dreamingToLockscreenTransitionViewModel) { + Lazy<DreamingToLockscreenTransitionViewModel> dreamingToLockscreenTransitionViewModel, + SystemPropertiesHelper systemPropertiesHelper) { mContext = context; mUserTracker = userTracker; mFalsingCollector = falsingCollector; @@ -1318,6 +1329,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, mPM = powerManager; mTrustManager = trustManager; mUserSwitcherController = userSwitcherController; + mSystemPropertiesHelper = systemPropertiesHelper; mStatusBarService = IStatusBarService.Stub.asInterface( ServiceManager.getService(Context.STATUS_BAR_SERVICE)); mKeyguardDisplayManager = keyguardDisplayManager; diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java index ab79c8067cd5..1f121e92d7d0 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java @@ -42,6 +42,7 @@ import com.android.systemui.dagger.qualifiers.UiBackground; import com.android.systemui.dreams.DreamOverlayStateController; import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.flags.SystemPropertiesHelper; import com.android.systemui.keyguard.DismissCallbackRegistry; import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.keyguard.KeyguardViewMediator; @@ -134,7 +135,8 @@ public class KeyguardModule { Lazy<ScrimController> scrimControllerLazy, FeatureFlags featureFlags, @Main CoroutineDispatcher mainDispatcher, - Lazy<DreamingToLockscreenTransitionViewModel> dreamingToLockscreenTransitionViewModel) { + Lazy<DreamingToLockscreenTransitionViewModel> dreamingToLockscreenTransitionViewModel, + SystemPropertiesHelper systemPropertiesHelper) { return new KeyguardViewMediator( context, uiEventLogger, @@ -170,7 +172,8 @@ public class KeyguardModule { scrimControllerLazy, featureFlags, mainDispatcher, - dreamingToLockscreenTransitionViewModel); + dreamingToLockscreenTransitionViewModel, + systemPropertiesHelper); } /** */ diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java index b96ca7ac2961..3b32313e76a0 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java @@ -224,7 +224,6 @@ public class TaskbarDelegate implements CommandQueue.Callbacks, return LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION; } }); - controller.overrideIconTintForNavMode(true); return controller; } diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java index d2e94d6a20a5..776a90d75a75 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java @@ -4813,7 +4813,9 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump if (!mHeadsUpTouchHelper.isTrackingHeadsUp() && mQsController.handleTouch( event, isFullyCollapsed(), isShadeOrQsHeightAnimationRunning())) { - mShadeLog.logMotionEvent(event, "onTouch: handleQsTouch handled event"); + if (event.getActionMasked() != MotionEvent.ACTION_MOVE) { + mShadeLog.logMotionEvent(event, "onTouch: handleQsTouch handled event"); + } return true; } if (event.getActionMasked() == MotionEvent.ACTION_DOWN && isFullyCollapsed()) { @@ -4827,7 +4829,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump } handled |= handleTouch(event); - mShadeLog.logOnTouchEventLastReturn(event, !mDozing, handled); return !mDozing || handled; } @@ -5010,7 +5011,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump } break; } - mShadeLog.logHandleTouchLastReturn(event, !mGestureWaitForTouchSlop, mTracking); return !mGestureWaitForTouchSlop || mTracking; } diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java index 6480164cdaf5..62e79112a1d1 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java @@ -1186,7 +1186,6 @@ public class QuickSettingsController implements Dumpable { mClippingAnimationEndBounds.left, fraction); int animTop = (int) MathUtils.lerp(startTop, mClippingAnimationEndBounds.top, fraction); - logClippingTopBound("interpolated top bound", top); int animRight = (int) MathUtils.lerp(startRight, mClippingAnimationEndBounds.right, fraction); int animBottom = (int) MathUtils.lerp(startBottom, @@ -1337,8 +1336,6 @@ public class QuickSettingsController implements Dumpable { // the screen without clipping. return -mAmbientState.getStackTopMargin(); } else { - logNotificationsClippingTopBound(qsTop, - mNotificationStackScrollLayoutController.getTop()); return qsTop - mNotificationStackScrollLayoutController.getTop(); } } @@ -1380,25 +1377,21 @@ public class QuickSettingsController implements Dumpable { keyguardNotificationStaticPadding, maxQsPadding) : maxQsPadding; topPadding = (int) MathUtils.lerp((float) getMinExpansionHeight(), (float) max, expandedFraction); - logNotificationsTopPadding("keyguard and expandImmediate", topPadding); return topPadding; } else if (isSizeChangeAnimationRunning()) { topPadding = Math.max((int) mSizeChangeAnimator.getAnimatedValue(), keyguardNotificationStaticPadding); - logNotificationsTopPadding("size change animation running", topPadding); return topPadding; } else if (keyguardShowing) { // We can only do the smoother transition on Keyguard when we also are not collapsing // from a scrolled quick settings. topPadding = MathUtils.lerp((float) keyguardNotificationStaticPadding, (float) (getMaxExpansionHeight()), computeExpansionFraction()); - logNotificationsTopPadding("keyguard", topPadding); return topPadding; } else { topPadding = Math.max(mQsFrameTranslateController.getNotificationsTopPadding( mExpansionHeight, mNotificationStackScrollLayoutController), mQuickQsHeaderHeight); - logNotificationsTopPadding("default case", topPadding); return topPadding; } } @@ -1446,38 +1439,6 @@ public class QuickSettingsController implements Dumpable { - mAmbientState.getScrollY()); } - /** TODO(b/273591201): remove after bug resolved */ - private void logNotificationsTopPadding(String message, float rawPadding) { - int padding = ((int) rawPadding / 10) * 10; - if (mBarState != KEYGUARD && padding != mLastNotificationsTopPadding && !mExpanded) { - mLastNotificationsTopPadding = padding; - mShadeLog.logNotificationsTopPadding(message, padding); - } - } - - /** TODO(b/273591201): remove after bug resolved */ - private void logClippingTopBound(String message, int top) { - top = (top / 10) * 10; - if (mBarState != KEYGUARD && mShadeExpandedFraction == 1 - && top != mLastClippingTopBound && !mExpanded) { - mLastClippingTopBound = top; - mShadeLog.logClippingTopBound(message, top); - } - } - - /** TODO(b/273591201): remove after bug resolved */ - private void logNotificationsClippingTopBound(int top, int nsslTop) { - top = (top / 10) * 10; - nsslTop = (nsslTop / 10) * 10; - if (mBarState == SHADE && mShadeExpandedFraction == 1 - && (top != mLastNotificationsClippingTopBound - || nsslTop != mLastNotificationsClippingTopBoundNssl) && !mExpanded) { - mLastNotificationsClippingTopBound = top; - mLastNotificationsClippingTopBoundNssl = nsslTop; - mShadeLog.logNotificationsClippingTopBound(top, nsslTop); - } - } - private int calculateTopClippingBound(int qsPanelBottomY) { int top; if (mSplitShadeEnabled) { @@ -1487,7 +1448,6 @@ public class QuickSettingsController implements Dumpable { // If we're transitioning, let's use the actual value. The else case // can be wrong during transitions when waiting for the keyguard to unlock top = mTransitionToFullShadePosition; - logClippingTopBound("set while transitioning to full shade", top); } else { final float notificationTop = getEdgePosition(); if (mBarState == KEYGUARD) { @@ -1496,10 +1456,8 @@ public class QuickSettingsController implements Dumpable { // this should go away once we unify the stackY position and don't have // to do this min anymore below. top = qsPanelBottomY; - logClippingTopBound("bypassing keyguard", top); } else { top = (int) Math.min(qsPanelBottomY, notificationTop); - logClippingTopBound("keyguard default case", top); } } else { top = (int) notificationTop; @@ -1507,14 +1465,12 @@ public class QuickSettingsController implements Dumpable { } // TODO (b/265193930): remove dependency on NPVC top += mPanelViewControllerLazy.get().getOverStretchAmount(); - logClippingTopBound("including overstretch", top); // Correction for instant expansion caused by HUN pull down/ float minFraction = mPanelViewControllerLazy.get().getMinFraction(); if (minFraction > 0f && minFraction < 1f) { float realFraction = (mShadeExpandedFraction - minFraction) / (1f - minFraction); top *= MathUtils.saturate(realFraction / minFraction); - logClippingTopBound("after adjusted fraction", top); } } return top; @@ -1654,15 +1610,11 @@ public class QuickSettingsController implements Dumpable { // as sometimes the qsExpansionFraction can be a tiny value instead of 0 when in QQS. if (!mSplitShadeEnabled && !mLastShadeFlingWasExpanding && computeExpansionFraction() <= 0.01 && mShadeExpandedFraction < 1.0) { - mShadeLog.logMotionEvent(event, - "handleQsTouch: shade touched while shade collapsing, QS tracking disabled"); mTracking = false; } if (!isExpandImmediate() && mTracking) { onTouch(event); if (!mConflictingExpansionGesture && !mSplitShadeEnabled) { - mShadeLog.logMotionEvent(event, - "handleQsTouch: not immediate expand or conflicting gesture"); return true; } } @@ -1756,7 +1708,6 @@ public class QuickSettingsController implements Dumpable { break; case MotionEvent.ACTION_MOVE: - mShadeLog.logMotionEvent(event, "onQsTouch: move action, setting QS expansion"); setExpansionHeight(h + mInitialHeightOnTouch); // TODO (b/265193930): remove dependency on NPVC if (h >= mPanelViewControllerLazy.get().getFalsingThreshold()) { @@ -1844,17 +1795,14 @@ public class QuickSettingsController implements Dumpable { final float h = y - mInitialTouchY; trackMovement(event); if (mTracking) { - // Already tracking because onOverscrolled was called. We need to update here // so we don't stop for a frame until the next touch event gets handled in // onTouchEvent. setExpansionHeight(h + mInitialHeightOnTouch); trackMovement(event); return true; - } else { - mShadeLog.logMotionEvent(event, - "onQsIntercept: move ignored because qs tracking disabled"); } + // TODO (b/265193930): remove dependency on NPVC float touchSlop = event.getClassification() == MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE @@ -1878,7 +1826,7 @@ public class QuickSettingsController implements Dumpable { } else { mShadeLog.logQsTrackingNotStarted(mInitialTouchY, y, h, touchSlop, getExpanded(), mPanelViewControllerLazy.get().isKeyguardShowing(), - isExpansionEnabled()); + isExpansionEnabled(), event.getDownTime()); } break; diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt index 2b772e372f77..2da8d5f4d921 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt @@ -54,7 +54,8 @@ class ShadeLogger @Inject constructor(@ShadeLog private val buffer: LogBuffer) { touchSlop: Float, qsExpanded: Boolean, keyguardShowing: Boolean, - qsExpansionEnabled: Boolean + qsExpansionEnabled: Boolean, + downTime: Long ) { buffer.log( TAG, @@ -67,10 +68,11 @@ class ShadeLogger @Inject constructor(@ShadeLog private val buffer: LogBuffer) { bool1 = qsExpanded bool2 = keyguardShowing bool3 = qsExpansionEnabled + str1 = downTime.toString() }, { - "QsTrackingNotStarted: initTouchY=$int1,y=$int2,h=$long1,slop=$double1,qsExpanded" + - "=$bool1,keyguardShowing=$bool2,qsExpansion=$bool3" + "QsTrackingNotStarted: downTime=$str1,initTouchY=$int1,y=$int2,h=$long1," + + "slop=$double1,qsExpanded=$bool1,keyguardShowing=$bool2,qsExpansion=$bool3" } ) } @@ -306,91 +308,6 @@ class ShadeLogger @Inject constructor(@ShadeLog private val buffer: LogBuffer) { ) } - fun logNotificationsTopPadding(message: String, padding: Int) { - buffer.log( - TAG, - LogLevel.VERBOSE, - { - str1 = message - int1 = padding - }, - { "QSC NotificationsTopPadding $str1: $int1"} - ) - } - - fun logClippingTopBound(message: String, top: Int) { - buffer.log( - TAG, - LogLevel.VERBOSE, - { - str1 = message - int1 = top - }, - { "QSC ClippingTopBound $str1: $int1" } - ) - } - - fun logNotificationsClippingTopBound(top: Int, nsslTop: Int) { - buffer.log( - TAG, - LogLevel.VERBOSE, - { - int1 = top - int2 = nsslTop - }, - { "QSC NotificationsClippingTopBound set to $int1 - $int2" } - ) - } - - fun logOnTouchEventLastReturn( - event: MotionEvent, - dozing: Boolean, - handled: Boolean, - ) { - buffer.log( - TAG, - LogLevel.VERBOSE, - { - bool1 = dozing - bool2 = handled - long1 = event.eventTime - long2 = event.downTime - int1 = event.action - int2 = event.classification - double1 = event.y.toDouble() - }, - { - "NPVC onTouchEvent last return: !mDozing: $bool1 || handled: $bool2 " + - "\neventTime=$long1,downTime=$long2,y=$double1,action=$int1,class=$int2" - } - ) - } - - fun logHandleTouchLastReturn( - event: MotionEvent, - gestureWaitForTouchSlop: Boolean, - tracking: Boolean, - ) { - buffer.log( - TAG, - LogLevel.VERBOSE, - { - bool1 = gestureWaitForTouchSlop - bool2 = tracking - long1 = event.eventTime - long2 = event.downTime - int1 = event.action - int2 = event.classification - double1 = event.y.toDouble() - }, - { - "NPVC handleTouch last return: !mGestureWaitForTouchSlop: $bool1 " + - "|| mTracking: $bool2 " + - "\neventTime=$long1,downTime=$long2,y=$double1,action=$int1,class=$int2" - } - ) - } - fun logUpdateNotificationPanelTouchState( disabled: Boolean, isGoingToSleep: Boolean, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java index 1cd0f081a744..648ece527bef 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -475,6 +475,13 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { */ private boolean mShouldDelayWakeUpAnimation = false; + /** + * Whether we should delay the AOD->Lockscreen animation. + * If false, the animation will start in onStartedWakingUp(). + * If true, the animation will start in onFinishedWakingUp(). + */ + private boolean mShouldDelayLockscreenTransitionFromAod = false; + private final Object mQueueLock = new Object(); private final PulseExpansionHandler mPulseExpansionHandler; @@ -3242,7 +3249,10 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { updateVisibleToUser(); updateIsKeyguard(); - if (!mFeatureFlags.isEnabled(Flags.ZJ_285570694_LOCKSCREEN_TRANSITION_FROM_AOD)) { + mShouldDelayLockscreenTransitionFromAod = mDozeParameters.getAlwaysOn() + && mFeatureFlags.isEnabled( + Flags.ZJ_285570694_LOCKSCREEN_TRANSITION_FROM_AOD); + if (!mShouldDelayLockscreenTransitionFromAod) { startLockscreenTransitionFromAod(); } }); @@ -3251,8 +3261,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { /** * Private helper for starting the LOCKSCREEN_TRANSITION_FROM_AOD animation - only necessary - * so we can start it from either onFinishedWakingUp() or onFinishedWakingUp() depending - * on a flag value. + * so we can start it from either onFinishedWakingUp() or onFinishedWakingUp(). */ private void startLockscreenTransitionFromAod() { // stopDozing() starts the LOCKSCREEN_TRANSITION_FROM_AOD animation. @@ -3273,7 +3282,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { @Override public void onFinishedWakingUp() { - if (mFeatureFlags.isEnabled(Flags.ZJ_285570694_LOCKSCREEN_TRANSITION_FROM_AOD)) { + if (mShouldDelayLockscreenTransitionFromAod) { mNotificationShadeWindowController.batchApplyWindowLayoutParams( this::startLockscreenTransitionFromAod); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java index 7bc4fc3c5e47..ae70384aa71a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java @@ -115,7 +115,6 @@ public class LightBarTransitionsController implements Dumpable { }; private final Context mContext; - private Boolean mOverrideIconTintForNavMode; @AssistedInject public LightBarTransitionsController( @@ -276,19 +275,11 @@ public class LightBarTransitionsController implements Dumpable { } /** - * Specify an override value to return for {@link #overrideIconTintForNavMode(boolean)}. - */ - public void overrideIconTintForNavMode(boolean overrideValue) { - mOverrideIconTintForNavMode = overrideValue; - } - /** * Return whether to use the tint calculated in this class for nav icons. */ public boolean supportsIconTintForNavMode(int navigationMode) { // In gesture mode, we already do region sampling to update tint based on content beneath. - return mOverrideIconTintForNavMode != null - ? mOverrideIconTintForNavMode - : !QuickStepContract.isGesturalMode(navigationMode); + return !QuickStepContract.isGesturalMode(navigationMode); } /** diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java index 8a422c895052..770765260446 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java @@ -22,6 +22,8 @@ import static android.view.WindowManagerPolicyConstants.OFF_BECAUSE_OF_USER; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN; +import static com.android.systemui.keyguard.KeyguardViewMediator.REBOOT_MAINLINE_UPDATE; +import static com.android.systemui.keyguard.KeyguardViewMediator.SYS_BOOT_REASON_PROP; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -72,6 +74,7 @@ import com.android.systemui.dreams.DreamOverlayStateController; import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FakeFeatureFlags; import com.android.systemui.flags.Flags; +import com.android.systemui.flags.SystemPropertiesHelper; import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel; import com.android.systemui.log.SessionTracker; import com.android.systemui.navigationbar.NavigationModeController; @@ -161,6 +164,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { private @Mock CentralSurfaces mCentralSurfaces; private @Mock UiEventLogger mUiEventLogger; private @Mock SessionTracker mSessionTracker; + private @Mock SystemPropertiesHelper mSystemPropertiesHelper; private @Mock CoroutineDispatcher mDispatcher; private @Mock DreamingToLockscreenTransitionViewModel mDreamingToLockscreenTransitionViewModel; @@ -357,6 +361,23 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { } @Test + public void testBouncerPrompt_deviceRestartedDueToMainlineUpdate() { + // GIVEN biometrics enrolled + when(mUpdateMonitor.isUnlockingWithBiometricsPossible(anyInt())).thenReturn(true); + + // WHEN reboot caused by ota update + KeyguardUpdateMonitor.StrongAuthTracker strongAuthTracker = + mock(KeyguardUpdateMonitor.StrongAuthTracker.class); + when(mUpdateMonitor.getStrongAuthTracker()).thenReturn(strongAuthTracker); + when(strongAuthTracker.hasUserAuthenticatedSinceBoot()).thenReturn(false); + when(mSystemPropertiesHelper.get(SYS_BOOT_REASON_PROP)).thenReturn(REBOOT_MAINLINE_UPDATE); + + // THEN the bouncer prompt reason should return PROMPT_REASON_RESTART_FOR_OTA + assertEquals(KeyguardSecurityView.PROMPT_REASON_RESTART_FOR_MAINLINE_UPDATE, + mViewMediator.mViewMediatorCallback.getBouncerPromptReason()); + } + + @Test public void testBouncerPrompt_afterUserLockDown() { // GIVEN biometrics enrolled when(mUpdateMonitor.isUnlockingWithBiometricsPossible(anyInt())).thenReturn(true); @@ -677,7 +698,8 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { () -> mScrimController, mFeatureFlags, mDispatcher, - () -> mDreamingToLockscreenTransitionViewModel); + () -> mDreamingToLockscreenTransitionViewModel, + mSystemPropertiesHelper); mViewMediator.start(); mViewMediator.registerCentralSurfaces(mCentralSurfaces, null, null, null, null, null); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java index 8062272a0042..77026308ad38 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java @@ -350,7 +350,9 @@ public class CentralSurfacesImplTest extends SysuiTestCase { // For the Shade to animate during the Back gesture, we must enable the animation flag. mFeatureFlags.set(Flags.WM_SHADE_ANIMATE_BACK_GESTURE, true); mFeatureFlags.set(Flags.LIGHT_REVEAL_MIGRATION, true); + // Turn AOD on and toggle feature flag for jank fixes mFeatureFlags.set(Flags.ZJ_285570694_LOCKSCREEN_TRANSITION_FROM_AOD, true); + when(mDozeParameters.getAlwaysOn()).thenReturn(true); IThermalService thermalService = mock(IThermalService.class); mPowerManager = new PowerManager(mContext, mPowerManagerService, thermalService, diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java index 1fa2bea6e5ea..eccff2a74eac 100644 --- a/services/core/java/com/android/server/am/CachedAppOptimizer.java +++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java @@ -123,7 +123,14 @@ public final class CachedAppOptimizer { "freeze_debounce_timeout"; @VisibleForTesting static final String KEY_FREEZER_EXEMPT_INST_PKG = "freeze_exempt_inst_pkg"; - + @VisibleForTesting static final String KEY_FREEZER_BINDER_ENABLED = + "freeze_binder_enabled"; + @VisibleForTesting static final String KEY_FREEZER_BINDER_DIVISOR = + "freeze_binder_divisor"; + @VisibleForTesting static final String KEY_FREEZER_BINDER_OFFSET = + "freeze_binder_offset"; + @VisibleForTesting static final String KEY_FREEZER_BINDER_THRESHOLD = + "freeze_binder_threshold"; static final int UNFREEZE_REASON_NONE = FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_NONE; @@ -237,8 +244,8 @@ public final class CachedAppOptimizer { @VisibleForTesting static final boolean ENABLE_FILE_COMPACT = false; // Defaults for phenotype flags. - @VisibleForTesting static final Boolean DEFAULT_USE_COMPACTION = true; - @VisibleForTesting static final Boolean DEFAULT_USE_FREEZER = true; + @VisibleForTesting static final boolean DEFAULT_USE_COMPACTION = true; + @VisibleForTesting static final boolean DEFAULT_USE_FREEZER = true; @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_1 = 5_000; @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_2 = 10_000; @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_3 = 500; @@ -257,7 +264,11 @@ public final class CachedAppOptimizer { @VisibleForTesting static final String DEFAULT_COMPACT_PROC_STATE_THROTTLE = String.valueOf(ActivityManager.PROCESS_STATE_RECEIVER); @VisibleForTesting static final long DEFAULT_FREEZER_DEBOUNCE_TIMEOUT = 10_000L; - @VisibleForTesting static final Boolean DEFAULT_FREEZER_EXEMPT_INST_PKG = true; + @VisibleForTesting static final boolean DEFAULT_FREEZER_EXEMPT_INST_PKG = true; + @VisibleForTesting static final boolean DEFAULT_FREEZER_BINDER_ENABLED = true; + @VisibleForTesting static final long DEFAULT_FREEZER_BINDER_DIVISOR = 4; + @VisibleForTesting static final int DEFAULT_FREEZER_BINDER_OFFSET = 500; + @VisibleForTesting static final long DEFAULT_FREEZER_BINDER_THRESHOLD = 1_000; @VisibleForTesting static final Uri CACHED_APP_FREEZER_ENABLED_URI = Settings.Global.getUriFor( Settings.Global.CACHED_APPS_FREEZER_ENABLED); @@ -393,6 +404,11 @@ public final class CachedAppOptimizer { updateFreezerDebounceTimeout(); } else if (KEY_FREEZER_EXEMPT_INST_PKG.equals(name)) { updateFreezerExemptInstPkg(); + } else if (KEY_FREEZER_BINDER_ENABLED.equals(name) + || KEY_FREEZER_BINDER_DIVISOR.equals(name) + || KEY_FREEZER_BINDER_THRESHOLD.equals(name) + || KEY_FREEZER_BINDER_OFFSET.equals(name)) { + updateFreezerBinderState(); } } } @@ -455,6 +471,16 @@ public final class CachedAppOptimizer { @GuardedBy("mPhenotypeFlagLock") @VisibleForTesting final Set<Integer> mProcStateThrottle; + @GuardedBy("mPhenotypeFlagLock") + @VisibleForTesting volatile boolean mFreezerBinderEnabled = DEFAULT_FREEZER_BINDER_ENABLED; + @GuardedBy("mPhenotypeFlagLock") + @VisibleForTesting volatile long mFreezerBinderDivisor = DEFAULT_FREEZER_BINDER_DIVISOR; + @GuardedBy("mPhenotypeFlagLock") + @VisibleForTesting volatile int mFreezerBinderOffset = DEFAULT_FREEZER_BINDER_OFFSET; + @GuardedBy("mPhenotypeFlagLock") + @VisibleForTesting volatile long mFreezerBinderThreshold = DEFAULT_FREEZER_BINDER_THRESHOLD; + + // Handler on which compaction runs. @VisibleForTesting Handler mCompactionHandler; @@ -759,6 +785,10 @@ public final class CachedAppOptimizer { pw.println(" " + KEY_FREEZER_STATSD_SAMPLE_RATE + "=" + mFreezerStatsdSampleRate); pw.println(" " + KEY_FREEZER_DEBOUNCE_TIMEOUT + "=" + mFreezerDebounceTimeout); pw.println(" " + KEY_FREEZER_EXEMPT_INST_PKG + "=" + mFreezerExemptInstPkg); + pw.println(" " + KEY_FREEZER_BINDER_ENABLED + "=" + mFreezerBinderEnabled); + pw.println(" " + KEY_FREEZER_BINDER_THRESHOLD + "=" + mFreezerBinderThreshold); + pw.println(" " + KEY_FREEZER_BINDER_DIVISOR + "=" + mFreezerBinderDivisor); + pw.println(" " + KEY_FREEZER_BINDER_OFFSET + "=" + mFreezerBinderOffset); synchronized (mProcLock) { int size = mFrozenProcesses.size(); pw.println(" Apps frozen: " + size); @@ -1264,6 +1294,26 @@ public final class CachedAppOptimizer { Slog.d(TAG_AM, "Freezer exemption set to " + mFreezerExemptInstPkg); } + @GuardedBy("mPhenotypeFlagLock") + private void updateFreezerBinderState() { + mFreezerBinderEnabled = DeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT, + KEY_FREEZER_BINDER_ENABLED, DEFAULT_FREEZER_BINDER_ENABLED); + mFreezerBinderDivisor = DeviceConfig.getLong( + DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT, + KEY_FREEZER_BINDER_DIVISOR, DEFAULT_FREEZER_BINDER_DIVISOR); + mFreezerBinderOffset = DeviceConfig.getInt( + DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT, + KEY_FREEZER_BINDER_OFFSET, DEFAULT_FREEZER_BINDER_OFFSET); + mFreezerBinderThreshold = DeviceConfig.getLong( + DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT, + KEY_FREEZER_BINDER_THRESHOLD, DEFAULT_FREEZER_BINDER_THRESHOLD); + Slog.d(TAG_AM, "Freezer binder state set to enabled=" + mFreezerBinderEnabled + + ", divisor=" + mFreezerBinderDivisor + + ", offset=" + mFreezerBinderOffset + + ", threshold=" + mFreezerBinderThreshold); + } + private boolean parseProcStateThrottle(String procStateThrottleString) { String[] procStates = TextUtils.split(procStateThrottleString, ","); mProcStateThrottle.clear(); @@ -1352,6 +1402,7 @@ public final class CachedAppOptimizer { } } } + app.mOptRecord.setLastUsedTimeout(delayMillis); mFreezeHandler.sendMessageDelayed( mFreezeHandler.obtainMessage(SET_FROZEN_PROCESS_MSG, DO_FREEZE, 0, app), delayMillis); @@ -2121,12 +2172,54 @@ public final class CachedAppOptimizer { } @GuardedBy({"mAm", "mProcLock"}) - private void rescheduleFreeze(final ProcessRecord proc, final String reason, - @UnfreezeReason int reasonCode) { + private void handleBinderFreezerFailure(final ProcessRecord proc, final String reason) { + if (!mFreezerBinderEnabled) { + // Just reschedule indefinitely. + unfreezeAppLSP(proc, UNFREEZE_REASON_BINDER_TXNS); + freezeAppAsyncLSP(proc); + return; + } + /* + * This handles the case where a process couldn't be frozen due to pending binder + * transactions. In order to prevent apps from avoiding the freezer by spamming binder + * transactions, there is an exponential decrease in freezer retry times plus a random + * offset per attempt to avoid phase issues. Once the last-attempted timeout is below a + * threshold, we assume that the app is spamming binder calls and can never be frozen, + * and we will then crash the app. + */ + if (proc.mOptRecord.getLastUsedTimeout() <= mFreezerBinderThreshold) { + // We've given the app plenty of chances, assume broken. Time to die. + Slog.d(TAG_AM, "Kill app due to repeated failure to freeze binder: " + + proc.getPid() + " " + proc.processName); + mAm.mHandler.post(() -> { + synchronized (mAm) { + // Crash regardless of procstate in case the app has found another way + // to abuse oom_adj + if (proc.getThread() == null) { + return; + } + proc.killLocked("excessive binder traffic during cached", + ApplicationExitInfo.REASON_EXCESSIVE_RESOURCE_USAGE, + ApplicationExitInfo.SUBREASON_EXCESSIVE_CPU, + true); + } + }); + return; + } + + long timeout = proc.mOptRecord.getLastUsedTimeout() / mFreezerBinderDivisor; + // range is [-mFreezerBinderOffset, +mFreezerBinderOffset] + int offset = mRandom.nextInt(mFreezerBinderOffset * 2) - mFreezerBinderOffset; + timeout = Math.max(timeout + offset, mFreezerBinderThreshold); + Slog.d(TAG_AM, "Reschedule freeze for process " + proc.getPid() - + " " + proc.processName + " (" + reason + ")"); - unfreezeAppLSP(proc, reasonCode); - freezeAppAsyncLSP(proc); + + " " + proc.processName + " (" + reason + "), timeout=" + timeout); + Trace.instantForTrack(Trace.TRACE_TAG_ACTIVITY_MANAGER, ATRACE_FREEZER_TRACK, + "Reschedule freeze " + proc.processName + ":" + proc.getPid() + + " timeout=" + timeout + ", reason=" + reason); + + unfreezeAppLSP(proc, UNFREEZE_REASON_BINDER_TXNS); + freezeAppAsyncLSP(proc, timeout); } /** @@ -2173,7 +2266,7 @@ public final class CachedAppOptimizer { // transactions that might be pending. try { if (freezeBinder(pid, true, FREEZE_BINDER_TIMEOUT_MS) != 0) { - rescheduleFreeze(proc, "outstanding txns", UNFREEZE_REASON_BINDER_TXNS); + handleBinderFreezerFailure(proc, "outstanding txns"); return; } } catch (RuntimeException e) { @@ -2234,7 +2327,7 @@ public final class CachedAppOptimizer { if ((freezeInfo & TXNS_PENDING_WHILE_FROZEN) != 0) { synchronized (mProcLock) { - rescheduleFreeze(proc, "new pending txns", UNFREEZE_REASON_BINDER_TXNS); + handleBinderFreezerFailure(proc, "new pending txns"); } return; } diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index 764bbe8bd191..f21ad2204d74 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -1009,7 +1009,6 @@ public class OomAdjuster { mCacheOomRanker.reRankLruCachedAppsLSP(mProcessList.getLruProcessesLSP(), mProcessList.getLruProcessServiceStartLOSP()); } - assignCachedAdjIfNecessary(mProcessList.getLruProcessesLOSP()); if (computeClients) { // There won't be cycles if we didn't compute clients above. // Cycle strategy: @@ -1034,7 +1033,7 @@ public class OomAdjuster { ProcessRecord app = activeProcesses.get(i); final ProcessStateRecord state = app.mState; if (!app.isKilledByAm() && app.getThread() != null && state.containsCycle()) { - if (computeOomAdjLSP(app, state.getCurRawAdj(), topApp, true, now, + if (computeOomAdjLSP(app, UNKNOWN_ADJ, topApp, true, now, true, true)) { retryCycles = true; } @@ -1044,6 +1043,8 @@ public class OomAdjuster { } mProcessesInCycle.clear(); + assignCachedAdjIfNecessary(mProcessList.getLruProcessesLOSP()); + mNumNonCachedProcs = 0; mNumCachedHiddenProcs = 0; diff --git a/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java b/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java index ffe5a6e6b958..f5c5ea8ae55a 100644 --- a/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java +++ b/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java @@ -127,6 +127,12 @@ final class ProcessCachedOptimizerRecord { @GuardedBy("mProcLock") private @UptimeMillisLong long mEarliestFreezableTimeMillis; + /** + * This is the most recently used timeout for freezing the app in millis + */ + @GuardedBy("mProcLock") + private long mLastUsedTimeout; + @GuardedBy("mProcLock") long getLastCompactTime() { return mLastCompactTime; @@ -282,6 +288,16 @@ final class ProcessCachedOptimizerRecord { } @GuardedBy("mProcLock") + long getLastUsedTimeout() { + return mLastUsedTimeout; + } + + @GuardedBy("mProcLock") + void setLastUsedTimeout(long lastUsedTimeout) { + mLastUsedTimeout = lastUsedTimeout; + } + + @GuardedBy("mProcLock") boolean isFreezeExempt() { return mFreezeExempt; } diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java index ec85d577a8e7..0c7f11f98809 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java +++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java @@ -1199,11 +1199,16 @@ public class AudioDeviceInventory { AudioDeviceInfo device = Stream.of(connectedDevices) .filter(d -> d.getInternalType() == ada.getInternalType()) .filter(d -> (!AudioSystem.isBluetoothDevice(d.getInternalType()) - || (d.getAddress() == ada.getAddress()))) + || (d.getAddress().equals(ada.getAddress())))) .findFirst() .orElse(null); if (device == null) { + if (AudioService.DEBUG_DEVICES) { + Slog.i(TAG, "purgeRoles() removing device: " + ada.toString() + + ", for strategy: " + keyRole.first + + " and role: " + keyRole.second); + } asi.deviceRoleAction(keyRole.first, keyRole.second, Arrays.asList(ada)); itDev.remove(); } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index c177c4efb5ef..53ed38edffe4 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -3666,25 +3666,29 @@ public class AudioService extends IAudioService.Stub * and aliases before mute change changed and after. */ private void muteAliasStreams(int streamAlias, boolean state) { - synchronized (VolumeStreamState.class) { - List<Integer> streamsToMute = new ArrayList<>(); - for (int stream = 0; stream < mStreamStates.length; stream++) { - VolumeStreamState vss = mStreamStates[stream]; - if (streamAlias == mStreamVolumeAlias[stream] && vss.isMutable()) { - if (!(mCameraSoundForced - && (vss.getStreamType() - == AudioSystem.STREAM_SYSTEM_ENFORCED))) { - boolean changed = vss.mute(state, /* apply= */ false, "muteAliasStreams"); - if (changed) { - streamsToMute.add(stream); + // Locking mSettingsLock to avoid inversion when calling doMute -> updateVolumeGroupIndex + synchronized (mSettingsLock) { + synchronized (VolumeStreamState.class) { + List<Integer> streamsToMute = new ArrayList<>(); + for (int stream = 0; stream < mStreamStates.length; stream++) { + VolumeStreamState vss = mStreamStates[stream]; + if (streamAlias == mStreamVolumeAlias[stream] && vss.isMutable()) { + if (!(mCameraSoundForced + && (vss.getStreamType() + == AudioSystem.STREAM_SYSTEM_ENFORCED))) { + boolean changed = vss.mute(state, /* apply= */ false, + "muteAliasStreams"); + if (changed) { + streamsToMute.add(stream); + } } } } + streamsToMute.forEach(streamToMute -> { + mStreamStates[streamToMute].doMute(); + broadcastMuteSetting(streamToMute, state); + }); } - streamsToMute.forEach(streamToMute -> { - mStreamStates[streamToMute].doMute(); - broadcastMuteSetting(streamToMute, state); - }); } } @@ -3699,18 +3703,22 @@ public class AudioService extends IAudioService.Stub // Called after a delay when volume down is pressed while muted private void onUnmuteStream(int stream, int flags) { boolean wasMuted; - synchronized (VolumeStreamState.class) { - final VolumeStreamState streamState = mStreamStates[stream]; - // if unmuting causes a change, it was muted - wasMuted = streamState.mute(false, "onUnmuteStream"); + // Locking mSettingsLock to avoid inversion when calling vss.mute -> vss.doMute -> + // vss.updateVolumeGroupIndex + synchronized (mSettingsLock) { + synchronized (VolumeStreamState.class) { + final VolumeStreamState streamState = mStreamStates[stream]; + // if unmuting causes a change, it was muted + wasMuted = streamState.mute(false, "onUnmuteStream"); - final int device = getDeviceForStream(stream); - final int index = streamState.getIndex(device); - sendVolumeUpdate(stream, index, index, flags, device); - } - if (stream == AudioSystem.STREAM_MUSIC && wasMuted) { - synchronized (mHdmiClientLock) { - maybeSendSystemAudioStatusCommand(true); + final int device = getDeviceForStream(stream); + final int index = streamState.getIndex(device); + sendVolumeUpdate(stream, index, index, flags, device); + } + if (stream == AudioSystem.STREAM_MUSIC && wasMuted) { + synchronized (mHdmiClientLock) { + maybeSendSystemAudioStatusCommand(true); + } } } } @@ -7611,7 +7619,11 @@ public class AudioService extends IAudioService.Stub Log.i(TAG, String.format("onAccessoryPlugMediaUnmute unmuting device=%d [%s]", newDevice, AudioSystem.getOutputDeviceName(newDevice))); } - mStreamStates[AudioSystem.STREAM_MUSIC].mute(false, "onAccessoryPlugMediaUnmute"); + // Locking mSettingsLock to avoid inversion when calling vss.mute -> vss.doMute -> + // vss.updateVolumeGroupIndex + synchronized (mSettingsLock) { + mStreamStates[AudioSystem.STREAM_MUSIC].mute(false, "onAccessoryPlugMediaUnmute"); + } } } @@ -7646,9 +7658,14 @@ public class AudioService extends IAudioService.Stub continue; } } - for (int i = 0; i < sVolumeGroupStates.size(); i++) { - final VolumeGroupState vgs = sVolumeGroupStates.valueAt(i); - vgs.applyAllVolumes(/* userSwitch= */ false); + + // need mSettingsLock for vgs.applyAllVolumes -> vss.setIndex which grabs this lock after + // VSS.class. Locking order needs to be preserved + synchronized (mSettingsLock) { + for (int i = 0; i < sVolumeGroupStates.size(); i++) { + final VolumeGroupState vgs = sVolumeGroupStates.valueAt(i); + vgs.applyAllVolumes(/* userSwitch= */ false); + } } } @@ -7685,9 +7702,14 @@ public class AudioService extends IAudioService.Stub if (DEBUG_VOL) { Log.v(TAG, "restoreVolumeGroups"); } - for (int i = 0; i < sVolumeGroupStates.size(); i++) { - final VolumeGroupState vgs = sVolumeGroupStates.valueAt(i); - vgs.applyAllVolumes(false/*userSwitch*/); + + // need mSettingsLock for vgs.applyAllVolumes -> vss.setIndex which grabs this lock after + // VSS.class. Locking order needs to be preserved + synchronized (mSettingsLock) { + for (int i = 0; i < sVolumeGroupStates.size(); i++) { + final VolumeGroupState vgs = sVolumeGroupStates.valueAt(i); + vgs.applyAllVolumes(false/*userSwitch*/); + } } } @@ -7824,49 +7846,51 @@ public class AudioService extends IAudioService.Stub } public void adjustVolume(int direction, int flags) { - synchronized (AudioService.VolumeStreamState.class) { - int device = getDeviceForVolume(); - int previousIndex = getIndex(device); - if (isMuteAdjust(direction) && !isMutable()) { - // Non mutable volume group - if (DEBUG_VOL) { - Log.d(TAG, "invalid mute on unmutable volume group " + name()); - } - return; - } - switch (direction) { - case AudioManager.ADJUST_TOGGLE_MUTE: { - // Note: If muted by volume 0, unmute will restore volume 0. - mute(!mIsMuted); - break; + synchronized (mSettingsLock) { + synchronized (AudioService.VolumeStreamState.class) { + int device = getDeviceForVolume(); + int previousIndex = getIndex(device); + if (isMuteAdjust(direction) && !isMutable()) { + // Non mutable volume group + if (DEBUG_VOL) { + Log.d(TAG, "invalid mute on unmutable volume group " + name()); + } + return; } - case AudioManager.ADJUST_UNMUTE: - // Note: If muted by volume 0, unmute will restore volume 0. - mute(false); - break; - case AudioManager.ADJUST_MUTE: - // May be already muted by setvolume 0, prevent from setting same value - if (previousIndex != 0) { - // bypass persist - mute(true); + switch (direction) { + case AudioManager.ADJUST_TOGGLE_MUTE: { + // Note: If muted by volume 0, unmute will restore volume 0. + mute(!mIsMuted); + break; } - mIsMuted = true; - break; - case AudioManager.ADJUST_RAISE: - // As for stream, RAISE during mute will increment the index - setVolumeIndex(Math.min(previousIndex + 1, mIndexMax), device, flags); - break; - case AudioManager.ADJUST_LOWER: - // For stream, ADJUST_LOWER on a muted VSS is a no-op - // If we decide to unmute on ADJUST_LOWER, cannot fallback on - // adjustStreamVolume for group associated to legacy stream type - if (isMuted() && previousIndex != 0) { + case AudioManager.ADJUST_UNMUTE: + // Note: If muted by volume 0, unmute will restore volume 0. mute(false); - } else { - int newIndex = Math.max(previousIndex - 1, mIndexMin); - setVolumeIndex(newIndex, device, flags); - } - break; + break; + case AudioManager.ADJUST_MUTE: + // May be already muted by setvolume 0, prevent from setting same value + if (previousIndex != 0) { + // bypass persist + mute(true); + } + mIsMuted = true; + break; + case AudioManager.ADJUST_RAISE: + // As for stream, RAISE during mute will increment the index + setVolumeIndex(Math.min(previousIndex + 1, mIndexMax), device, flags); + break; + case AudioManager.ADJUST_LOWER: + // For stream, ADJUST_LOWER on a muted VSS is a no-op + // If we decide to unmute on ADJUST_LOWER, cannot fallback on + // adjustStreamVolume for group associated to legacy stream type + if (isMuted() && previousIndex != 0) { + mute(false); + } else { + int newIndex = Math.max(previousIndex - 1, mIndexMin); + setVolumeIndex(newIndex, device, flags); + } + break; + } } } } @@ -7878,11 +7902,13 @@ public class AudioService extends IAudioService.Stub } public void setVolumeIndex(int index, int flags) { - synchronized (AudioService.VolumeStreamState.class) { - if (mUseFixedVolume) { - return; + synchronized (mSettingsLock) { + synchronized (AudioService.VolumeStreamState.class) { + if (mUseFixedVolume) { + return; + } + setVolumeIndex(index, getDeviceForVolume(), flags); } - setVolumeIndex(index, getDeviceForVolume(), flags); } } @@ -8689,24 +8715,30 @@ public class AudioService extends IAudioService.Stub // If associated to volume group, update group cache private void updateVolumeGroupIndex(int device, boolean forceMuteState) { - synchronized (VolumeStreamState.class) { - if (mVolumeGroupState != null) { - int groupIndex = (getIndex(device) + 5) / 10; - if (DEBUG_VOL) { - Log.d(TAG, "updateVolumeGroupIndex for stream " + mStreamType - + ", muted=" + mIsMuted + ", device=" + device + ", index=" - + getIndex(device) + ", group " + mVolumeGroupState.name() - + " Muted=" + mVolumeGroupState.isMuted() + ", Index=" + groupIndex - + ", forceMuteState=" + forceMuteState); - } - mVolumeGroupState.updateVolumeIndex(groupIndex, device); - // Only propage mute of stream when applicable - if (isMutable()) { - // For call stream, align mute only when muted, not when index is set to 0 - mVolumeGroupState.mute( - forceMuteState ? mIsMuted : - (groupIndex == 0 && !isCallStream(mStreamType)) - || mIsMuted); + // need mSettingsLock when called from setIndex for vgs.mute -> vgs.applyAllVolumes -> + // vss.setIndex which grabs this lock after VSS.class. Locking order needs to be + // preserved + synchronized (mSettingsLock) { + synchronized (VolumeStreamState.class) { + if (mVolumeGroupState != null) { + int groupIndex = (getIndex(device) + 5) / 10; + if (DEBUG_VOL) { + Log.d(TAG, "updateVolumeGroupIndex for stream " + mStreamType + + ", muted=" + mIsMuted + ", device=" + device + ", index=" + + getIndex(device) + ", group " + mVolumeGroupState.name() + + " Muted=" + mVolumeGroupState.isMuted() + ", Index=" + + groupIndex + ", forceMuteState=" + forceMuteState); + } + mVolumeGroupState.updateVolumeIndex(groupIndex, device); + // Only propage mute of stream when applicable + if (isMutable()) { + // For call stream, align mute only when muted, not when index is set to + // 0 + mVolumeGroupState.mute( + forceMuteState ? mIsMuted : + (groupIndex == 0 && !isCallStream(mStreamType)) + || mIsMuted); + } } } } diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java index c8a17e5eea5a..3560797ce2cf 100644 --- a/services/core/java/com/android/server/audio/BtHelper.java +++ b/services/core/java/com/android/server/audio/BtHelper.java @@ -218,8 +218,8 @@ public class BtHelper { if (AudioService.DEBUG_VOL) { AudioService.sVolumeLogger.enqueue(new EventLogger.StringEvent( "setAvrcpAbsoluteVolumeIndex: bailing due to null mA2dp").printLog(TAG)); - return; } + return; } if (!mAvrcpAbsVolSupported) { AudioService.sVolumeLogger.enqueue(new EventLogger.StringEvent( diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java index 770f04a2db5e..60e2af5f283c 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java @@ -2512,6 +2512,35 @@ public class MockingOomAdjusterTests { assertEquals(FOREGROUND_APP_ADJ, app.mState.getSetAdj()); } + @SuppressWarnings("GuardedBy") + @Test + public void testUpdateOomAdj_DoAll_Side_Cycle() { + final ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, + MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false)); + final ProcessRecord app2 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID, + MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false)); + final ProcessRecord app3 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID, + MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false)); + long now = SystemClock.uptimeMillis(); + ServiceRecord s = bindService(app, app2, null, 0, mock(IBinder.class)); + s.startRequested = true; + s.lastActivity = now; + s = bindService(app2, app3, null, 0, mock(IBinder.class)); + s.lastActivity = now; + s = bindService(app3, app2, null, 0, mock(IBinder.class)); + s.lastActivity = now; + + sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); + sService.mOomAdjuster.mNumServiceProcs = 3; + updateOomAdj(app, app2, app3); + + assertEquals(SERVICE_ADJ, app.mState.getSetAdj()); + assertTrue(sFirstCachedAdj <= app2.mState.getSetAdj()); + assertTrue(sFirstCachedAdj <= app3.mState.getSetAdj()); + assertTrue(CACHED_APP_MAX_ADJ >= app2.mState.getSetAdj()); + assertTrue(CACHED_APP_MAX_ADJ >= app3.mState.getSetAdj()); + } + private ProcessRecord makeDefaultProcessRecord(int pid, int uid, String processName, String packageName, boolean hasShownUi) { long now = SystemClock.uptimeMillis(); |