Merge "Marking failing tests as flaky until they can be fixed." into main
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 77168e3..0185080 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -647,6 +647,7 @@
field public static final String OPSTR_RECEIVE_AMBIENT_TRIGGER_AUDIO = "android:receive_ambient_trigger_audio";
field public static final String OPSTR_RECEIVE_EMERGENCY_BROADCAST = "android:receive_emergency_broadcast";
field public static final String OPSTR_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO = "android:receive_explicit_user_interaction_audio";
+ field public static final String OPSTR_RECEIVE_SANDBOX_TRIGGER_AUDIO = "android:receive_sandbox_trigger_audio";
field public static final String OPSTR_REQUEST_DELETE_PACKAGES = "android:request_delete_packages";
field public static final String OPSTR_REQUEST_INSTALL_PACKAGES = "android:request_install_packages";
field public static final String OPSTR_RUN_ANY_IN_BACKGROUND = "android:run_any_in_background";
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index bcd43ea..096ad55 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -2256,6 +2256,7 @@
*
* @hide
*/
+ @SystemApi
public static final String OPSTR_RECEIVE_SANDBOX_TRIGGER_AUDIO =
"android:receive_sandbox_trigger_audio";
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index d189bab..2c428ef 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -236,6 +236,7 @@
* {@link android.view.WindowManagerPolicyConstants#KEYGUARD_GOING_AWAY_FLAG_TO_SHADE}
* etc.
*/
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.CONTROL_KEYGUARD)")
void keyguardGoingAway(int flags);
void suppressResizeConfigChanges(boolean suppress);
diff --git a/core/java/android/content/res/Element.java b/core/java/android/content/res/Element.java
index eb928fd..a86c0c9 100644
--- a/core/java/android/content/res/Element.java
+++ b/core/java/android/content/res/Element.java
@@ -775,8 +775,6 @@
return index == R.styleable.AndroidManifestReceiver_name;
case TAG_SERVICE:
return index == R.styleable.AndroidManifestService_name;
- case TAG_USES_LIBRARY:
- return index == R.styleable.AndroidManifestUsesLibrary_name;
default:
return false;
}
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 64be87b..7300772 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -5565,10 +5565,6 @@
<!-- pdp data reject retry delay in ms -->
<integer name="config_pdp_reject_retry_delay_ms">-1</integer>
- <!-- Duration in milliseconds for device to vibrate on mash press on power
- button. -->
- <integer name="config_mashPressVibrateTimeOnPowerButton">0</integer>
-
<!-- Whether or not to enable the binder heavy hitter watcher by default -->
<bool name="config_defaultBinderHeavyHitterWatcherEnabled">false</bool>
diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml
index b7a5bc8..18abe70 100644
--- a/core/res/res/values/config_telephony.xml
+++ b/core/res/res/values/config_telephony.xml
@@ -199,4 +199,8 @@
<bool name="allow_clear_initial_attach_data_profile">false</bool>
<java-symbol type="bool" name="allow_clear_initial_attach_data_profile" />
+ <!-- Boolean indicating whether TelephonyAnalytics module is active or not. -->
+ <bool name="telephony_analytics_switch">true</bool>
+ <java-symbol type="bool" name="telephony_analytics_switch" />
+
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 3aae3ca..391d7bd 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4949,8 +4949,6 @@
<java-symbol type="array" name="config_builtInDisplayIsRoundArray" />
<java-symbol type="array" name="config_gnssParameters" />
- <java-symbol type="integer" name="config_mashPressVibrateTimeOnPowerButton" />
-
<java-symbol type="string" name="config_systemGameService" />
<java-symbol type="string" name="config_supervisedUserCreationPackage"/>
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt
index 5efa51b..421ad75 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt
@@ -63,12 +63,8 @@
}
/** Checks that the visible region of [pipApp] window always moves down during the animation. */
- @Presubmit
- @Test
- fun pipWindowMovesDown() = pipWindowMoves(Direction.DOWN)
+ @Presubmit @Test fun pipWindowMovesDown() = pipWindowMoves(Direction.DOWN)
/** Checks that the visible region of [pipApp] layer always moves down during the animation. */
- @Presubmit
- @Test
- fun pipLayerMovesDown() = pipLayerMoves(Direction.DOWN)
+ @Presubmit @Test fun pipLayerMovesDown() = pipLayerMoves(Direction.DOWN)
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavLandscape.kt
index 2494054..e37d806 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavLandscape.kt
@@ -22,7 +22,7 @@
import com.android.wm.shell.flicker.service.splitscreen.scenarios.CopyContentInSplit
import org.junit.Test
-class CopyContentInSplitGesturalNavLandscape : CopyContentInSplit(Rotation.ROTATION_90) {
+open class CopyContentInSplitGesturalNavLandscape : CopyContentInSplit(Rotation.ROTATION_90) {
@PlatinumTest(focusArea = "sysui")
@Presubmit
@Test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavPortrait.kt
index 57943ec..2a50912 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavPortrait.kt
@@ -22,7 +22,7 @@
import com.android.wm.shell.flicker.service.splitscreen.scenarios.CopyContentInSplit
import org.junit.Test
-class CopyContentInSplitGesturalNavPortrait : CopyContentInSplit(Rotation.ROTATION_0) {
+open class CopyContentInSplitGesturalNavPortrait : CopyContentInSplit(Rotation.ROTATION_0) {
@PlatinumTest(focusArea = "sysui")
@Presubmit
@Test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavLandscape.kt
index 6f0e202..d5da1a8 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavLandscape.kt
@@ -22,7 +22,7 @@
import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByDivider
import org.junit.Test
-class DismissSplitScreenByDividerGesturalNavLandscape :
+open class DismissSplitScreenByDividerGesturalNavLandscape :
DismissSplitScreenByDivider(Rotation.ROTATION_90) {
@PlatinumTest(focusArea = "sysui")
@Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavPortrait.kt
index dac8fa2..7fdcb9b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavPortrait.kt
@@ -22,7 +22,7 @@
import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByDivider
import org.junit.Test
-class DismissSplitScreenByDividerGesturalNavPortrait :
+open class DismissSplitScreenByDividerGesturalNavPortrait :
DismissSplitScreenByDivider(Rotation.ROTATION_0) {
@PlatinumTest(focusArea = "sysui")
@Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavLandscape.kt
index baecc16..308e954 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavLandscape.kt
@@ -22,7 +22,7 @@
import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByGoHome
import org.junit.Test
-class DismissSplitScreenByGoHomeGesturalNavLandscape :
+open class DismissSplitScreenByGoHomeGesturalNavLandscape :
DismissSplitScreenByGoHome(Rotation.ROTATION_90) {
@PlatinumTest(focusArea = "sysui")
@Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavPortrait.kt
index 3063ea5..39e75bd 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavPortrait.kt
@@ -22,7 +22,7 @@
import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByGoHome
import org.junit.Test
-class DismissSplitScreenByGoHomeGesturalNavPortrait :
+open class DismissSplitScreenByGoHomeGesturalNavPortrait :
DismissSplitScreenByGoHome(Rotation.ROTATION_0) {
@PlatinumTest(focusArea = "sysui")
@Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavLandscape.kt
index 41660ba..e18da17 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavLandscape.kt
@@ -22,7 +22,7 @@
import com.android.wm.shell.flicker.service.splitscreen.scenarios.DragDividerToResize
import org.junit.Test
-class DragDividerToResizeGesturalNavLandscape : DragDividerToResize(Rotation.ROTATION_90) {
+open class DragDividerToResizeGesturalNavLandscape : DragDividerToResize(Rotation.ROTATION_90) {
@PlatinumTest(focusArea = "sysui")
@Presubmit
@Test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavPortrait.kt
index c41ffb7..00d60e7 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavPortrait.kt
@@ -22,7 +22,7 @@
import com.android.wm.shell.flicker.service.splitscreen.scenarios.DragDividerToResize
import org.junit.Test
-class DragDividerToResizeGesturalNavPortrait : DragDividerToResize(Rotation.ROTATION_0) {
+open class DragDividerToResizeGesturalNavPortrait : DragDividerToResize(Rotation.ROTATION_0) {
@PlatinumTest(focusArea = "sysui")
@Presubmit
@Test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt
index afde55b..d7efbc8 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt
@@ -22,7 +22,7 @@
import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromAllApps
import org.junit.Test
-class EnterSplitScreenByDragFromAllAppsGesturalNavLandscape :
+open class EnterSplitScreenByDragFromAllAppsGesturalNavLandscape :
EnterSplitScreenByDragFromAllApps(Rotation.ROTATION_90) {
@PlatinumTest(focusArea = "sysui")
@Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt
index 3765fc4..4eece3f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt
@@ -22,7 +22,7 @@
import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromAllApps
import org.junit.Test
-class EnterSplitScreenByDragFromAllAppsGesturalNavPortrait :
+open class EnterSplitScreenByDragFromAllAppsGesturalNavPortrait :
EnterSplitScreenByDragFromAllApps(Rotation.ROTATION_0) {
@PlatinumTest(focusArea = "sysui")
@Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt
index 1e128fd..d96b056 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt
@@ -22,7 +22,7 @@
import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromNotification
import org.junit.Test
-class EnterSplitScreenByDragFromNotificationGesturalNavLandscape :
+open class EnterSplitScreenByDragFromNotificationGesturalNavLandscape :
EnterSplitScreenByDragFromNotification(Rotation.ROTATION_90) {
@PlatinumTest(focusArea = "sysui")
@Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt
index 7767872..809b690 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt
@@ -22,7 +22,7 @@
import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromNotification
import org.junit.Test
-class EnterSplitScreenByDragFromNotificationGesturalNavPortrait :
+open class EnterSplitScreenByDragFromNotificationGesturalNavPortrait :
EnterSplitScreenByDragFromNotification(Rotation.ROTATION_0) {
@PlatinumTest(focusArea = "sysui")
@Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt
index 4ca4bd1..bbdf2d7 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt
@@ -22,7 +22,7 @@
import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromShortcut
import org.junit.Test
-class EnterSplitScreenByDragFromShortcutGesturalNavLandscape :
+open class EnterSplitScreenByDragFromShortcutGesturalNavLandscape :
EnterSplitScreenByDragFromShortcut(Rotation.ROTATION_90) {
@PlatinumTest(focusArea = "sysui")
@Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt
index 2d9d258..5c29fd8 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt
@@ -22,7 +22,7 @@
import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromShortcut
import org.junit.Test
-class EnterSplitScreenByDragFromShortcutGesturalNavPortrait :
+open class EnterSplitScreenByDragFromShortcutGesturalNavPortrait :
EnterSplitScreenByDragFromShortcut(Rotation.ROTATION_0) {
@PlatinumTest(focusArea = "sysui")
@Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt
index c9282ac..a7398eb 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt
@@ -22,7 +22,7 @@
import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromTaskbar
import org.junit.Test
-class EnterSplitScreenByDragFromTaskbarGesturalNavLandscape :
+open class EnterSplitScreenByDragFromTaskbarGesturalNavLandscape :
EnterSplitScreenByDragFromTaskbar(Rotation.ROTATION_90) {
@PlatinumTest(focusArea = "sysui")
@Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt
index 68c6d6c..eae88ad 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt
@@ -22,7 +22,7 @@
import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromTaskbar
import org.junit.Test
-class EnterSplitScreenByDragFromTaskbarGesturalNavPortrait :
+open class EnterSplitScreenByDragFromTaskbarGesturalNavPortrait :
EnterSplitScreenByDragFromTaskbar(Rotation.ROTATION_0) {
@PlatinumTest(focusArea = "sysui")
@Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavLandscape.kt
index 304529e..7e8ee04 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavLandscape.kt
@@ -22,7 +22,7 @@
import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenFromOverview
import org.junit.Test
-class EnterSplitScreenFromOverviewGesturalNavLandscape :
+open class EnterSplitScreenFromOverviewGesturalNavLandscape :
EnterSplitScreenFromOverview(Rotation.ROTATION_90) {
@PlatinumTest(focusArea = "sysui")
@Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavPortrait.kt
index 53a6b44..9295c33 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavPortrait.kt
@@ -22,7 +22,7 @@
import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenFromOverview
import org.junit.Test
-class EnterSplitScreenFromOverviewGesturalNavPortrait :
+open class EnterSplitScreenFromOverviewGesturalNavPortrait :
EnterSplitScreenFromOverview(Rotation.ROTATION_0) {
@PlatinumTest(focusArea = "sysui")
@Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt
index a467830..4b59e9f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt
@@ -22,7 +22,7 @@
import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchAppByDoubleTapDivider
import org.junit.Test
-class SwitchAppByDoubleTapDividerGesturalNavLandscape :
+open class SwitchAppByDoubleTapDividerGesturalNavLandscape :
SwitchAppByDoubleTapDivider(Rotation.ROTATION_90) {
@PlatinumTest(focusArea = "sysui")
@Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt
index 1524233..5ff36d4 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt
@@ -22,7 +22,7 @@
import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchAppByDoubleTapDivider
import org.junit.Test
-class SwitchAppByDoubleTapDividerGesturalNavPortrait :
+open class SwitchAppByDoubleTapDividerGesturalNavPortrait :
SwitchAppByDoubleTapDivider(Rotation.ROTATION_0) {
@PlatinumTest(focusArea = "sysui")
@Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt
index 0389659..c0cb721 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt
@@ -22,7 +22,7 @@
import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromAnotherApp
import org.junit.Test
-class SwitchBackToSplitFromAnotherAppGesturalNavLandscape :
+open class SwitchBackToSplitFromAnotherAppGesturalNavLandscape :
SwitchBackToSplitFromAnotherApp(Rotation.ROTATION_90) {
@PlatinumTest(focusArea = "sysui")
@Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt
index 7fadf18..8c14088 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt
@@ -22,7 +22,7 @@
import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromAnotherApp
import org.junit.Test
-class SwitchBackToSplitFromAnotherAppGesturalNavPortrait :
+open class SwitchBackToSplitFromAnotherAppGesturalNavPortrait :
SwitchBackToSplitFromAnotherApp(Rotation.ROTATION_0) {
@PlatinumTest(focusArea = "sysui")
@Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavLandscape.kt
index 148cc52..7b6614b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavLandscape.kt
@@ -22,7 +22,7 @@
import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromHome
import org.junit.Test
-class SwitchBackToSplitFromHomeGesturalNavLandscape :
+open class SwitchBackToSplitFromHomeGesturalNavLandscape :
SwitchBackToSplitFromHome(Rotation.ROTATION_90) {
@PlatinumTest(focusArea = "sysui")
@Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavPortrait.kt
index 0641fb0..5df5be9 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavPortrait.kt
@@ -22,7 +22,7 @@
import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromHome
import org.junit.Test
-class SwitchBackToSplitFromHomeGesturalNavPortrait :
+open class SwitchBackToSplitFromHomeGesturalNavPortrait :
SwitchBackToSplitFromHome(Rotation.ROTATION_0) {
@PlatinumTest(focusArea = "sysui")
@Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavLandscape.kt
index 741f871..9d63003 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavLandscape.kt
@@ -22,7 +22,7 @@
import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromRecent
import org.junit.Test
-class SwitchBackToSplitFromRecentGesturalNavLandscape :
+open class SwitchBackToSplitFromRecentGesturalNavLandscape :
SwitchBackToSplitFromRecent(Rotation.ROTATION_90) {
@PlatinumTest(focusArea = "sysui")
@Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavPortrait.kt
index 778e2d6..9fa04b2 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavPortrait.kt
@@ -22,7 +22,7 @@
import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromRecent
import org.junit.Test
-class SwitchBackToSplitFromRecentGesturalNavPortrait :
+open class SwitchBackToSplitFromRecentGesturalNavPortrait :
SwitchBackToSplitFromRecent(Rotation.ROTATION_0) {
@PlatinumTest(focusArea = "sysui")
@Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavLandscape.kt
index dcdca70..9386aa2 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavLandscape.kt
@@ -22,7 +22,8 @@
import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBetweenSplitPairs
import org.junit.Test
-class SwitchBetweenSplitPairsGesturalNavLandscape : SwitchBetweenSplitPairs(Rotation.ROTATION_90) {
+open class SwitchBetweenSplitPairsGesturalNavLandscape :
+ SwitchBetweenSplitPairs(Rotation.ROTATION_90) {
@PlatinumTest(focusArea = "sysui")
@Presubmit
@Test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavPortrait.kt
index 3c69311..5ef2167 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavPortrait.kt
@@ -22,7 +22,8 @@
import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBetweenSplitPairs
import org.junit.Test
-class SwitchBetweenSplitPairsGesturalNavPortrait : SwitchBetweenSplitPairs(Rotation.ROTATION_0) {
+open class SwitchBetweenSplitPairsGesturalNavPortrait :
+ SwitchBetweenSplitPairs(Rotation.ROTATION_0) {
@PlatinumTest(focusArea = "sysui")
@Presubmit
@Test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt
index c6566f5..9caab9b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt
@@ -24,7 +24,7 @@
import org.junit.runners.BlockJUnit4ClassRunner
@RunWith(BlockJUnit4ClassRunner::class)
-class UnlockKeyguardToSplitScreenGesturalNavLandscape : UnlockKeyguardToSplitScreen() {
+open class UnlockKeyguardToSplitScreenGesturalNavLandscape : UnlockKeyguardToSplitScreen() {
@PlatinumTest(focusArea = "sysui")
@Presubmit
@Test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt
index bb1a502..bf484e5 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt
@@ -24,7 +24,7 @@
import org.junit.runners.BlockJUnit4ClassRunner
@RunWith(BlockJUnit4ClassRunner::class)
-class UnlockKeyguardToSplitScreenGesturalNavPortrait : UnlockKeyguardToSplitScreen() {
+open class UnlockKeyguardToSplitScreenGesturalNavPortrait : UnlockKeyguardToSplitScreen() {
@PlatinumTest(focusArea = "sysui")
@Presubmit
@Test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairsNoPip.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairsNoPip.kt
index 91e7d47..e59ed64 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairsNoPip.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairsNoPip.kt
@@ -25,8 +25,8 @@
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.PipAppHelper
-import com.android.wm.shell.flicker.utils.SplitScreenUtils
import com.android.wm.shell.flicker.splitscreen.benchmark.SplitScreenBase
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
import com.android.wm.shell.flicker.utils.layerBecomesInvisible
import com.android.wm.shell.flicker.utils.splitAppLayerBoundsIsVisibleAtEnd
import com.android.wm.shell.flicker.utils.splitAppLayerBoundsSnapToDivider
@@ -45,8 +45,8 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class SwitchBetweenSplitPairsNoPip (override val flicker: LegacyFlickerTest) :
- SplitScreenBase(flicker) {
+class SwitchBetweenSplitPairsNoPip(override val flicker: LegacyFlickerTest) :
+ SplitScreenBase(flicker) {
val thirdApp = SplitScreenUtils.getSendNotification(instrumentation)
val pipApp = PipAppHelper(instrumentation)
@@ -77,74 +77,69 @@
}
}
- /**
- * Checks that [pipApp] window won't enter pip
- */
+ /** Checks that [pipApp] window won't enter pip */
@Presubmit
@Test
fun notEnterPip() {
flicker.assertWm { isNotPinned(pipApp) }
}
- /**
- * Checks the [pipApp] task did not reshow during transition.
- */
+ /** Checks the [pipApp] task did not reshow during transition. */
@Presubmit
@Test
fun app1WindowIsVisibleOnceApp2WindowIsInvisible() {
flicker.assertLayers {
this.isVisible(pipApp)
- .then().isVisible(ComponentNameMatcher.LAUNCHER, isOptional = true)
- .then().isVisible(ComponentNameMatcher.SNAPSHOT, isOptional = true)
- .then().isInvisible(pipApp).isVisible(secondaryApp)
+ .then()
+ .isVisible(ComponentNameMatcher.LAUNCHER, isOptional = true)
+ .then()
+ .isVisible(ComponentNameMatcher.SNAPSHOT, isOptional = true)
+ .then()
+ .isInvisible(pipApp)
+ .isVisible(secondaryApp)
}
}
@Presubmit
@Test
fun primaryAppBoundsIsVisibleAtEnd() =
- flicker.splitAppLayerBoundsIsVisibleAtEnd(
- primaryApp,
- landscapePosLeft = tapl.isTablet,
- portraitPosTop = false
- )
+ flicker.splitAppLayerBoundsIsVisibleAtEnd(
+ primaryApp,
+ landscapePosLeft = tapl.isTablet,
+ portraitPosTop = false
+ )
@Presubmit
@Test
fun secondaryAppBoundsIsVisibleAtEnd() =
- flicker.splitAppLayerBoundsIsVisibleAtEnd(
- secondaryApp,
- landscapePosLeft = !tapl.isTablet,
- portraitPosTop = true
- )
+ flicker.splitAppLayerBoundsIsVisibleAtEnd(
+ secondaryApp,
+ landscapePosLeft = !tapl.isTablet,
+ portraitPosTop = true
+ )
- /**
- * Checks the [pipApp] task become invisible after transition finish.
- */
- @Presubmit
- @Test
- fun pipAppLayerBecomesInvisible() = flicker.layerBecomesInvisible(pipApp)
+ /** Checks the [pipApp] task become invisible after transition finish. */
+ @Presubmit @Test fun pipAppLayerBecomesInvisible() = flicker.layerBecomesInvisible(pipApp)
- /**
- * Checks the [pipApp] task is in split screen bounds when transition start.
- */
+ /** Checks the [pipApp] task is in split screen bounds when transition start. */
@Presubmit
@Test
fun pipAppBoundsIsVisibleAtBegin() =
- flicker.assertLayersStart {
- this.splitAppLayerBoundsSnapToDivider(
- pipApp,
- landscapePosLeft = !tapl.isTablet,
- portraitPosTop = true,
- flicker.scenario.startRotation
- )
- }
+ flicker.assertLayersStart {
+ this.splitAppLayerBoundsSnapToDivider(
+ pipApp,
+ landscapePosLeft = !tapl.isTablet,
+ portraitPosTop = true,
+ flicker.scenario.startRotation
+ )
+ }
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams() = LegacyFlickerTestFactory.nonRotationTests(
+ fun getParams() =
+ LegacyFlickerTestFactory.nonRotationTests(
supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
- )
+ )
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt
index 10dceba..4c44028 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt
@@ -69,11 +69,12 @@
@Test
@Presubmit
fun visibleLayersShownMoreThanOneConsecutiveEntry_withoutWallpaper() =
- flicker.assertLayers { this.visibleLayersShownMoreThanOneConsecutiveEntry(
- LayersTraceSubject.VISIBLE_FOR_MORE_THAN_ONE_ENTRY_IGNORE_LAYERS + listOf(
- WALLPAPER_BBQ_WRAPPER
+ flicker.assertLayers {
+ this.visibleLayersShownMoreThanOneConsecutiveEntry(
+ LayersTraceSubject.VISIBLE_FOR_MORE_THAN_ONE_ENTRY_IGNORE_LAYERS +
+ listOf(WALLPAPER_BBQ_WRAPPER)
)
- ) }
+ }
@Test
fun splitScreenDividerIsVisibleAtEnd() {
diff --git a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
index 864a8bb..c8df760 100644
--- a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
+++ b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
@@ -123,8 +123,7 @@
@Override
public boolean performClick() {
- mSwitch.performClick();
- return super.performClick();
+ return mSwitch.performClick();
}
/**
diff --git a/packages/SettingsLib/Spa/spa/Android.bp b/packages/SettingsLib/Spa/spa/Android.bp
index 79f8c46..7f5948c 100644
--- a/packages/SettingsLib/Spa/spa/Android.bp
+++ b/packages/SettingsLib/Spa/spa/Android.bp
@@ -22,7 +22,7 @@
name: "SpaLib",
srcs: ["src/**/*.kt"],
-
+ use_resource_processor: true,
static_libs: [
"androidx.slice_slice-builders",
"androidx.slice_slice-core",
@@ -50,5 +50,6 @@
// Expose the srcs to tests, so the tests can access the internal classes.
filegroup {
name: "SpaLib_srcs",
+ visibility: ["//frameworks/base/packages/SettingsLib/Spa/tests"],
srcs: ["src/**/*.kt"],
}
diff --git a/packages/SettingsLib/Spa/testutils/Android.bp b/packages/SettingsLib/Spa/testutils/Android.bp
index e4d56cc..65f5d34 100644
--- a/packages/SettingsLib/Spa/testutils/Android.bp
+++ b/packages/SettingsLib/Spa/testutils/Android.bp
@@ -22,7 +22,7 @@
name: "SpaLibTestUtils",
srcs: ["src/**/*.kt"],
-
+ use_resource_processor: true,
static_libs: [
"SpaLib",
"androidx.arch.core_core-testing",
diff --git a/packages/SettingsLib/SpaPrivileged/Android.bp b/packages/SettingsLib/SpaPrivileged/Android.bp
index 4a7418f..eaeda3c 100644
--- a/packages/SettingsLib/SpaPrivileged/Android.bp
+++ b/packages/SettingsLib/SpaPrivileged/Android.bp
@@ -22,7 +22,7 @@
name: "SpaPrivilegedLib",
srcs: ["src/**/*.kt"],
-
+ use_resource_processor: true,
static_libs: [
"SpaLib",
"SettingsLib",
@@ -45,5 +45,6 @@
// Expose the srcs to tests, so the tests can access the internal classes.
filegroup {
name: "SpaPrivilegedLib_srcs",
+ visibility: [":__subpackages__"],
srcs: ["src/**/*.kt"],
}
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/compose/StringResources.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/compose/StringResources.kt
new file mode 100644
index 0000000..05cb1b1
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/compose/StringResources.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spaprivileged.framework.compose
+
+import android.content.Context
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.res.stringResource
+import com.android.settingslib.R
+
+/** An empty placer holder string. */
+@Composable
+fun placeholder() = stringResource(R.string.summary_placeholder)
+
+/** Gets an empty placer holder string. */
+fun Context.getPlaceholder(): String = getString(R.string.summary_placeholder)
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppRepository.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppRepository.kt
index 1a7d896..de2cf1f 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppRepository.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppRepository.kt
@@ -23,11 +23,11 @@
import androidx.compose.runtime.State
import androidx.compose.runtime.produceState
import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.res.stringResource
import com.android.settingslib.Utils
import com.android.settingslib.spa.framework.compose.rememberContext
import com.android.settingslib.spaprivileged.R
import com.android.settingslib.spaprivileged.framework.common.userManager
+import com.android.settingslib.spaprivileged.framework.compose.placeholder
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@@ -40,7 +40,7 @@
@Composable
fun produceLabel(app: ApplicationInfo, isClonedAppPage: Boolean = false): State<String> {
val context = LocalContext.current
- return produceState(initialValue = stringResource(R.string.summary_placeholder), app) {
+ return produceState(initialValue = placeholder(), app) {
withContext(Dispatchers.IO) {
value = if (isClonedAppPage || isCloneApp(context, app)) {
context.getString(R.string.cloned_app_info_label, loadLabel(app))
@@ -82,7 +82,7 @@
withContext(Dispatchers.IO) {
value = when {
context.userManager.isManagedProfile(app.userId) -> {
- context.getString(R.string.category_work)
+ context.getString(com.android.settingslib.R.string.category_work)
}
else -> null
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/EnterpriseRepository.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/EnterpriseRepository.kt
index fab3ae8..cc3584b 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/EnterpriseRepository.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/EnterpriseRepository.kt
@@ -20,7 +20,7 @@
import android.app.admin.DevicePolicyResources.Strings.Settings.PERSONAL_CATEGORY_HEADER
import android.app.admin.DevicePolicyResources.Strings.Settings.WORK_CATEGORY_HEADER
import android.content.Context
-import com.android.settingslib.spaprivileged.R
+import com.android.settingslib.R
class EnterpriseRepository(private val context: Context) {
private val resources by lazy {
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictionsProvider.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictionsProvider.kt
index ae362c8..e2ff7b0 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictionsProvider.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictionsProvider.kt
@@ -27,7 +27,7 @@
import com.android.settingslib.RestrictedLockUtils
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin
import com.android.settingslib.RestrictedLockUtilsInternal
-import com.android.settingslib.spaprivileged.R
+import com.android.settingslib.widget.R
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
@@ -56,11 +56,15 @@
override fun getSummary(checked: Boolean?) = when (checked) {
true -> enterpriseRepository.getEnterpriseString(
- Settings.ENABLED_BY_ADMIN_SWITCH_SUMMARY, R.string.enabled_by_admin
+ updatableStringId = Settings.ENABLED_BY_ADMIN_SWITCH_SUMMARY,
+ resId = R.string.enabled_by_admin,
)
+
false -> enterpriseRepository.getEnterpriseString(
- Settings.DISABLED_BY_ADMIN_SWITCH_SUMMARY, R.string.disabled_by_admin
+ updatableStringId = Settings.DISABLED_BY_ADMIN_SWITCH_SUMMARY,
+ resId = R.string.disabled_by_admin,
)
+
else -> ""
}
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt
index b43210f..cee750e 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt
@@ -72,7 +72,7 @@
private fun InstallType(app: ApplicationInfo) {
if (!app.isInstantApp) return
Spacer(modifier = Modifier.height(4.dp))
- SettingsBody(stringResource(R.string.install_type_instant))
+ SettingsBody(stringResource(com.android.settingslib.widget.R.string.install_type_instant))
}
@Composable
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppStorageSize.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppStorageSize.kt
index 3e96994..5fc1972 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppStorageSize.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppStorageSize.kt
@@ -24,9 +24,8 @@
import androidx.compose.runtime.State
import androidx.compose.runtime.produceState
import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.res.stringResource
-import com.android.settingslib.spaprivileged.R
import com.android.settingslib.spaprivileged.framework.common.storageStatsManager
+import com.android.settingslib.spaprivileged.framework.compose.placeholder
import com.android.settingslib.spaprivileged.model.app.userHandle
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@@ -36,7 +35,7 @@
@Composable
fun ApplicationInfo.getStorageSize(): State<String> {
val context = LocalContext.current
- return produceState(initialValue = stringResource(R.string.summary_placeholder)) {
+ return produceState(initialValue = placeholder()) {
withContext(Dispatchers.IO) {
val sizeBytes = calculateSizeBytes(context)
value = if (sizeBytes != null) Formatter.formatFileSize(context, sizeBytes) else ""
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPage.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPage.kt
index cbc4822..1fa854a 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPage.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPage.kt
@@ -38,6 +38,7 @@
import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.preference.PreferenceModel
import com.android.settingslib.spaprivileged.R
+import com.android.settingslib.spaprivileged.framework.compose.getPlaceholder
import com.android.settingslib.spaprivileged.model.app.AppListModel
import com.android.settingslib.spaprivileged.model.app.AppRecord
import com.android.settingslib.spaprivileged.model.app.userId
@@ -173,7 +174,7 @@
when (allowed.value) {
true -> context.getString(R.string.app_permission_summary_allowed)
false -> context.getString(R.string.app_permission_summary_not_allowed)
- null -> context.getString(R.string.summary_placeholder)
+ null -> context.getPlaceholder()
}
}
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreference.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreference.kt
index b08b6df..e77dcd4 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreference.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreference.kt
@@ -32,7 +32,7 @@
import com.android.settingslib.spa.framework.compose.stateOf
import com.android.settingslib.spa.widget.preference.SwitchPreference
import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
-import com.android.settingslib.spaprivileged.R
+import com.android.settingslib.spaprivileged.framework.compose.getPlaceholder
import com.android.settingslib.spaprivileged.model.enterprise.BaseUserRestricted
import com.android.settingslib.spaprivileged.model.enterprise.BlockedByAdmin
import com.android.settingslib.spaprivileged.model.enterprise.NoRestricted
@@ -72,9 +72,12 @@
checked: State<Boolean?>,
): State<String> = when (restrictedMode) {
is NoRestricted -> summaryIfNoRestricted
- is BaseUserRestricted -> stateOf(context.getString(R.string.disabled))
+ is BaseUserRestricted -> stateOf(
+ context.getString(com.android.settingslib.R.string.disabled)
+ )
+
is BlockedByAdmin -> derivedStateOf { restrictedMode.getSummary(checked.value) }
- null -> stateOf(context.getString(R.string.summary_placeholder))
+ null -> stateOf(context.getPlaceholder())
}
}
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppRepositoryTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppRepositoryTest.kt
index 26caa01..d11e63a 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppRepositoryTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppRepositoryTest.kt
@@ -25,7 +25,6 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settingslib.spa.framework.compose.stateOf
import com.android.settingslib.spa.testutils.delay
-import com.android.settingslib.spaprivileged.R
import com.android.settingslib.spaprivileged.framework.common.userManager
import com.google.common.truth.Truth.assertThat
import org.junit.Before
@@ -66,7 +65,8 @@
val contentDescription = produceIconContentDescription()
- assertThat(contentDescription.value).isEqualTo(context.getString(R.string.category_work))
+ assertThat(contentDescription.value)
+ .isEqualTo(context.getString(com.android.settingslib.R.string.category_work))
}
@Test
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListPageTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListPageTest.kt
index f6f4889..82fbee9 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListPageTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListPageTest.kt
@@ -116,7 +116,7 @@
private fun onMoreOptions() =
composeTestRule.onNodeWithContentDescription(
- context.getString(R.string.abc_action_menu_overflow_description)
+ context.getString(androidx.appcompat.R.string.abc_action_menu_overflow_description)
)
private companion object {
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPageTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPageTest.kt
index 961ec10..457b810 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPageTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPageTest.kt
@@ -30,6 +30,7 @@
import com.android.settingslib.spa.framework.compose.stateOf
import com.android.settingslib.spa.testutils.FakeNavControllerWrapper
import com.android.settingslib.spaprivileged.R
+import com.android.settingslib.spaprivileged.framework.compose.getPlaceholder
import com.android.settingslib.spaprivileged.model.enterprise.NoRestricted
import com.android.settingslib.spaprivileged.tests.testutils.FakeRestrictionsProvider
import com.android.settingslib.spaprivileged.tests.testutils.TestAppRecord
@@ -95,9 +96,7 @@
val summaryState = getSummary(listModel)
- assertThat(summaryState.value).isEqualTo(
- context.getString(R.string.summary_placeholder)
- )
+ assertThat(summaryState.value).isEqualTo(context.getPlaceholder())
}
@Test
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index de8287e..68fcdea 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1196,7 +1196,6 @@
<dimen name="magnification_window_drag_corner_stroke">3dp</dimen>
<!-- The extra padding to show the whole outer border -->
<dimen name="magnifier_drag_handle_padding">3dp</dimen>
- <dimen name="magnification_max_frame_size">300dp</dimen>
<!-- Magnification settings panel -->
<dimen name="magnification_setting_view_margin">24dp</dimen>
<dimen name="magnification_setting_text_size">18sp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index 6c8f8f3..4a31f3d 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -124,7 +124,7 @@
private float mScale;
/**
- * MagnificationFrame represents the bound of {@link #mMirrorSurface} and is constrained
+ * MagnificationFrame represents the bound of {@link #mMirrorSurfaceView} and is constrained
* by the {@link #mMagnificationFrameBoundary}.
* We use MagnificationFrame to calculate the position of {@link #mMirrorView}.
* We combine MagnificationFrame with {@link #mMagnificationFrameOffsetX} and
@@ -225,6 +225,8 @@
private boolean mAllowDiagonalScrolling = false;
private boolean mEditSizeEnable = false;
private boolean mSettingsPanelVisibility = false;
+ @VisibleForTesting
+ WindowMagnificationSizePrefs mWindowMagnificationSizePrefs;
@Nullable
private final MirrorWindowControl mMirrorWindowControl;
@@ -249,6 +251,7 @@
mWindowMagnifierCallback = callback;
mSysUiState = sysUiState;
mConfiguration = new Configuration(context.getResources().getConfiguration());
+ mWindowMagnificationSizePrefs = new WindowMagnificationSizePrefs(mContext);
final Display display = mContext.getDisplay();
mDisplayId = mContext.getDisplayId();
@@ -272,8 +275,8 @@
com.android.internal.R.integer.config_shortAnimTime);
updateDimensions();
- final Size windowSize = getDefaultWindowSizeWithWindowBounds(mWindowBounds);
- setMagnificationFrame(windowSize.getWidth(), windowSize.getHeight(),
+ final Size windowFrameSize = restoreMagnificationWindowFrameSizeIfPossible();
+ setMagnificationFrame(windowFrameSize.getWidth(), windowFrameSize.getHeight(),
mWindowBounds.width() / 2, mWindowBounds.height() / 2);
computeBounceAnimationScale();
@@ -381,12 +384,16 @@
if (!mMagnificationSizeScaleOptions.contains(index)) {
return;
}
- final float scale = mMagnificationSizeScaleOptions.get(index, 1.0f);
- final int initSize = Math.min(mWindowBounds.width(), mWindowBounds.height()) / 3;
- int size = (int) (initSize * scale);
+ int size = getMagnificationWindowSizeFromIndex(index);
setWindowSize(size, size);
}
+ int getMagnificationWindowSizeFromIndex(@MagnificationSize int index) {
+ final float scale = mMagnificationSizeScaleOptions.get(index, 1.0f);
+ int initSize = Math.min(mWindowBounds.width(), mWindowBounds.height()) / 3;
+ return (int) (initSize * scale) - (int) (initSize * scale) % 2;
+ }
+
void setEditMagnifierSizeMode(boolean enable) {
mEditSizeEnable = enable;
applyResourcesValues();
@@ -395,6 +402,12 @@
updateDimensions();
applyTapExcludeRegion();
}
+
+ if (!enable) {
+ // Keep the magnifier size when exiting edit mode
+ mWindowMagnificationSizePrefs.saveSizeForCurrentDensity(
+ new Size(mMagnificationFrame.width(), mMagnificationFrame.height()));
+ }
}
void setDiagonalScrolling(boolean enable) {
@@ -519,12 +532,12 @@
return false;
}
mWindowBounds.set(currentWindowBounds);
- final Size windowSize = getDefaultWindowSizeWithWindowBounds(mWindowBounds);
+ final Size windowFrameSize = restoreMagnificationWindowFrameSizeIfPossible();
final float newCenterX = (getCenterX()) * mWindowBounds.width() / oldWindowBounds.width();
final float newCenterY = (getCenterY()) * mWindowBounds.height() / oldWindowBounds.height();
- setMagnificationFrame(windowSize.getWidth(), windowSize.getHeight(), (int) newCenterX,
- (int) newCenterY);
+ setMagnificationFrame(windowFrameSize.getWidth(), windowFrameSize.getHeight(),
+ (int) newCenterX, (int) newCenterY);
calculateMagnificationFrameBoundary();
return true;
}
@@ -738,6 +751,8 @@
}
private void setMagnificationFrame(int width, int height, int centerX, int centerY) {
+ mWindowMagnificationSizePrefs.saveSizeForCurrentDensity(new Size(width, height));
+
// Sets the initial frame area for the mirror and place it to the given center on the
// display.
final int initX = centerX - width / 2;
@@ -745,12 +760,18 @@
mMagnificationFrame.set(initX, initY, initX + width, initY + height);
}
- private Size getDefaultWindowSizeWithWindowBounds(Rect windowBounds) {
- int initSize = Math.min(windowBounds.width(), windowBounds.height()) / 2;
- initSize = Math.min(mResources.getDimensionPixelSize(R.dimen.magnification_max_frame_size),
- initSize);
- initSize += 2 * mMirrorSurfaceMargin;
- return new Size(initSize, initSize);
+ private Size restoreMagnificationWindowFrameSizeIfPossible() {
+ if (!mWindowMagnificationSizePrefs.isPreferenceSavedForCurrentDensity()) {
+ return getDefaultMagnificationWindowFrameSize();
+ }
+
+ return mWindowMagnificationSizePrefs.getSizeForCurrentDensity();
+ }
+
+ private Size getDefaultMagnificationWindowFrameSize() {
+ final int defaultSize = getMagnificationWindowSizeFromIndex(MagnificationSize.MEDIUM)
+ - 2 * mMirrorSurfaceMargin;
+ return new Size(defaultSize, defaultSize);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSizePrefs.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSizePrefs.java
new file mode 100644
index 0000000..4d7ad264
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSizePrefs.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.util.Size;
+
+/**
+ * Class to handle SharedPreference for window magnification size.
+ */
+public final class WindowMagnificationSizePrefs {
+
+ private static final String WINDOW_MAGNIFICATION_PREFERENCES =
+ "window_magnification_preferences";
+ Context mContext;
+ SharedPreferences mWindowMagnificationSizePreferences;
+
+ public WindowMagnificationSizePrefs(Context context) {
+ mContext = context;
+ mWindowMagnificationSizePreferences = mContext
+ .getSharedPreferences(WINDOW_MAGNIFICATION_PREFERENCES, Context.MODE_PRIVATE);
+ }
+
+ /**
+ * Uses smallest screen width DP as the key for preference.
+ */
+ private String getKey() {
+ return String.valueOf(
+ mContext.getResources().getConfiguration().smallestScreenWidthDp);
+ }
+
+ /**
+ * Saves the window frame size for current screen density.
+ */
+ public void saveSizeForCurrentDensity(Size size) {
+ mWindowMagnificationSizePreferences.edit()
+ .putString(getKey(), size.toString()).apply();
+ }
+
+ /**
+ * Check if there is a preference saved for current screen density.
+ *
+ * @return true if there is a preference saved for current screen density, false if it is unset.
+ */
+ public boolean isPreferenceSavedForCurrentDensity() {
+ return mWindowMagnificationSizePreferences.contains(getKey());
+ }
+
+ /**
+ * Gets the size preference for current screen density.
+ */
+ public Size getSizeForCurrentDensity() {
+ return Size.parseSize(mWindowMagnificationSizePreferences.getString(getKey(), null));
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 2686233..66de371 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -3291,7 +3291,8 @@
flags |= StatusBarManager.DISABLE_RECENT;
}
- if (mPowerGestureIntercepted && mOccluded && isSecure()) {
+ if (mPowerGestureIntercepted && mOccluded && isSecure()
+ && mUpdateMonitor.isFaceEnrolled()) {
flags |= StatusBarManager.DISABLE_RECENT;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index 11ad206..a48fa5d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -71,6 +71,7 @@
import android.testing.TestableLooper;
import android.testing.TestableResources;
import android.text.TextUtils;
+import android.util.Size;
import android.view.Display;
import android.view.IWindowSession;
import android.view.MotionEvent;
@@ -100,6 +101,7 @@
import org.junit.After;
import org.junit.Assume;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
@@ -313,10 +315,10 @@
assertFalse(rects.isEmpty());
}
+ @Ignore("The default window size should be constrained after fixing b/288056772")
@Test
public void enableWindowMagnification_LargeScreen_windowSizeIsConstrained() {
- final int screenSize = mContext.getResources().getDimensionPixelSize(
- R.dimen.magnification_max_frame_size) * 10;
+ final int screenSize = mWindowManager.getCurrentWindowMetrics().getBounds().width() * 10;
mWindowManager.setWindowBounds(new Rect(0, 0, screenSize, screenSize));
mInstrumentation.runOnMainSync(() -> {
@@ -543,17 +545,22 @@
}
@Test
- public void onScreenSizeChanged_enabledAtTheCenterOfScreen_keepSameWindowSizeRatio() {
+ public void onScreenSizeAndDensityChanged_enabledAtTheCenterOfScreen_keepSameWindowSizeRatio() {
// The default position is at the center of the screen.
final float expectedRatio = 0.5f;
- final Rect testWindowBounds = new Rect(
- mWindowManager.getCurrentWindowMetrics().getBounds());
- testWindowBounds.set(testWindowBounds.left, testWindowBounds.top,
- testWindowBounds.right + 100, testWindowBounds.bottom + 100);
+
mInstrumentation.runOnMainSync(() -> {
mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
Float.NaN);
});
+
+ // Screen size and density change
+ mContext.getResources().getConfiguration().smallestScreenWidthDp =
+ mContext.getResources().getConfiguration().smallestScreenWidthDp * 2;
+ final Rect testWindowBounds = new Rect(
+ mWindowManager.getCurrentWindowMetrics().getBounds());
+ testWindowBounds.set(testWindowBounds.left, testWindowBounds.top,
+ testWindowBounds.right + 100, testWindowBounds.bottom + 100);
mWindowManager.setWindowBounds(testWindowBounds);
mInstrumentation.runOnMainSync(() -> {
@@ -568,26 +575,49 @@
mWindowMagnificationController.getCenterY() / testWindowBounds.height(),
0);
}
+
@Test
- public void screenSizeIsChangedToLarge_enabled_windowSizeIsConstrained() {
+ public void onScreenChangedToSavedDensity_enabled_restoreSavedMagnifierWindow() {
+ mContext.getResources().getConfiguration().smallestScreenWidthDp =
+ mContext.getResources().getConfiguration().smallestScreenWidthDp * 2;
+ int windowFrameSize = mResources.getDimensionPixelSize(
+ com.android.internal.R.dimen.accessibility_window_magnifier_min_size);
+ mWindowMagnificationController.mWindowMagnificationSizePrefs.saveSizeForCurrentDensity(
+ new Size(windowFrameSize, windowFrameSize));
+
mInstrumentation.runOnMainSync(() -> {
mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
Float.NaN);
});
- final int screenSize = mContext.getResources().getDimensionPixelSize(
- R.dimen.magnification_max_frame_size) * 10;
+
+ WindowManager.LayoutParams params = mWindowManager.getLayoutParamsFromAttachedView();
+ assertTrue(params.width == windowFrameSize);
+ assertTrue(params.height == windowFrameSize);
+ }
+
+ @Test
+ public void screenSizeIsChangedToLarge_enabled_defaultWindowSize() {
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
+ Float.NaN);
+ });
+ final int screenSize = mWindowManager.getCurrentWindowMetrics().getBounds().width() * 10;
+ // Screen size and density change
+ mContext.getResources().getConfiguration().smallestScreenWidthDp =
+ mContext.getResources().getConfiguration().smallestScreenWidthDp * 2;
mWindowManager.setWindowBounds(new Rect(0, 0, screenSize, screenSize));
mInstrumentation.runOnMainSync(() -> {
mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_SCREEN_SIZE);
});
- final int halfScreenSize = screenSize / 2;
+ final int defaultWindowSize =
+ mWindowMagnificationController.getMagnificationWindowSizeFromIndex(
+ WindowMagnificationSettings.MagnificationSize.MEDIUM);
WindowManager.LayoutParams params = mWindowManager.getLayoutParamsFromAttachedView();
- // The frame size should be the half of smaller value of window height/width unless it
- //exceed the max frame size.
- assertTrue(params.width < halfScreenSize);
- assertTrue(params.height < halfScreenSize);
+
+ assertTrue(params.width == defaultWindowSize);
+ assertTrue(params.height == defaultWindowSize);
}
@Test
@@ -1136,6 +1166,11 @@
mWindowManager.setWindowInsets(testInsets);
}
+ private int updateMirrorSurfaceMarginDimension() {
+ return mContext.getResources().getDimensionPixelSize(
+ R.dimen.magnification_mirror_surface_margin);
+ }
+
@Surface.Rotation
private int simulateRotateTheDevice() {
final Display display = Mockito.spy(mContext.getDisplay());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSizePrefsTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSizePrefsTest.java
new file mode 100644
index 0000000..04b0d70
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSizePrefsTest.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.util.Size;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class WindowMagnificationSizePrefsTest extends SysuiTestCase {
+
+ WindowMagnificationSizePrefs mWindowMagnificationSizePrefs =
+ new WindowMagnificationSizePrefs(mContext);
+
+ @Test
+ public void saveSizeForCurrentDensity_getExpectedSize() {
+ Size testSize = new Size(500, 500);
+ mWindowMagnificationSizePrefs.saveSizeForCurrentDensity(testSize);
+
+ assertThat(mWindowMagnificationSizePrefs.getSizeForCurrentDensity())
+ .isEqualTo(testSize);
+ }
+
+ @Test
+ public void saveSizeForCurrentDensity_containsPreferenceForCurrentDensity() {
+ Size testSize = new Size(500, 500);
+ mWindowMagnificationSizePrefs.saveSizeForCurrentDensity(testSize);
+
+ assertThat(mWindowMagnificationSizePrefs.isPreferenceSavedForCurrentDensity())
+ .isTrue();
+ }
+}
diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java
index f19f7f2..1741593 100644
--- a/services/core/java/com/android/server/GestureLauncherService.java
+++ b/services/core/java/com/android/server/GestureLauncherService.java
@@ -19,12 +19,10 @@
import android.app.ActivityManager;
import android.app.StatusBarManager;
import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.hardware.Sensor;
@@ -40,8 +38,6 @@
import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
-import android.os.VibrationEffect;
-import android.os.Vibrator;
import android.provider.Settings;
import android.util.MutableBoolean;
import android.util.Slog;
@@ -113,19 +109,6 @@
*/
private static final int CAMERA_POWER_TAP_COUNT_THRESHOLD = 2;
- /** Action for starting emergency alerts on Wear OS. */
- private static final String WEAR_LAUNCH_EMERGENCY_ACTION =
- "com.android.systemui.action.LAUNCH_EMERGENCY";
-
- /** Action for starting emergency alerts in retail mode on Wear OS. */
- private static final String WEAR_LAUNCH_EMERGENCY_RETAIL_ACTION =
- "com.android.systemui.action.LAUNCH_EMERGENCY_RETAIL";
-
- /**
- * Boolean extra for distinguishing intents coming from power button gesture.
- */
- private static final String EXTRA_LAUNCH_EMERGENCY_VIA_GESTURE = "launch_emergency_via_gesture";
-
/** The listener that receives the gesture event. */
private final GestureEventListener mGestureListener = new GestureEventListener();
private final CameraLiftTriggerEventListener mCameraLiftTriggerListener =
@@ -198,7 +181,6 @@
private final UiEventLogger mUiEventLogger;
private boolean mHasFeatureWatch;
- private long mVibrateMilliSecondsForPanicGesture;
@VisibleForTesting
public enum GestureLauncherEvent implements UiEventLogger.UiEventEnum {
@@ -268,13 +250,6 @@
mHasFeatureWatch =
mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
- mVibrateMilliSecondsForPanicGesture =
- resources.getInteger(
- com.android
- .internal
- .R
- .integer
- .config_mashPressVibrateTimeOnPowerButton);
}
}
@@ -714,11 +689,6 @@
userSetupComplete));
}
- if (mHasFeatureWatch) {
- onEmergencyGestureDetectedOnWatch();
- return true;
- }
-
StatusBarManagerInternal service = LocalServices.getService(
StatusBarManagerInternal.class);
service.onEmergencyActionLaunchGestureDetected();
@@ -728,37 +698,6 @@
}
}
- private void onEmergencyGestureDetectedOnWatch() {
- Intent emergencyIntent =
- new Intent(
- isInRetailMode()
- ? WEAR_LAUNCH_EMERGENCY_RETAIL_ACTION
- : WEAR_LAUNCH_EMERGENCY_ACTION);
- PackageManager pm = mContext.getPackageManager();
- ResolveInfo resolveInfo = pm.resolveActivity(emergencyIntent, /*flags=*/0);
- if (resolveInfo == null) {
- Slog.w(TAG, "Couldn't find an app to process the emergency intent "
- + emergencyIntent.getAction());
- return;
- }
-
- Vibrator vibrator = mContext.getSystemService(Vibrator.class);
- vibrator.vibrate(VibrationEffect.createOneShot(mVibrateMilliSecondsForPanicGesture,
- VibrationEffect.DEFAULT_AMPLITUDE));
-
- emergencyIntent.setComponent(
- new ComponentName(
- resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name));
- emergencyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- emergencyIntent.putExtra(EXTRA_LAUNCH_EMERGENCY_VIA_GESTURE, true);
- mContext.startActivityAsUser(emergencyIntent, new UserHandle(mUserId));
- }
-
- private boolean isInRetailMode() {
- return Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.DEVICE_DEMO_MODE, 0) == 1;
- }
-
private boolean isUserSetupComplete() {
return Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index dc83125..383bb25 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -6434,6 +6434,7 @@
}
updateServiceConnectionActivitiesLocked(psr);
psr.removeAllConnections();
+ psr.removeAllSdkSandboxConnections();
psr.mAllowlistManager = false;
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index bef53c7..faf1900a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -22,6 +22,7 @@
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER_QUICK;
import static com.android.server.am.BroadcastConstants.DEFER_BOOT_COMPLETED_BROADCAST_BACKGROUND_RESTRICTED_ONLY;
import static com.android.server.am.BroadcastConstants.DEFER_BOOT_COMPLETED_BROADCAST_TARGET_T_ONLY;
+import static com.android.server.am.BroadcastConstants.getDeviceConfigBoolean;
import android.annotation.NonNull;
import android.app.ActivityThread;
@@ -153,6 +154,11 @@
static final String KEY_TIERED_CACHED_ADJ_DECAY_TIME = "tiered_cached_adj_decay_time";
static final String KEY_USE_MODERN_TRIM = "use_modern_trim";
+ /**
+ * Whether or not to enable the new oom adjuster implementation.
+ */
+ static final String KEY_ENABLE_NEW_OOMADJ = "enable_new_oom_adj";
+
private static final int DEFAULT_MAX_CACHED_PROCESSES = 1024;
private static final boolean DEFAULT_PRIORITIZE_ALARM_BROADCASTS = true;
private static final long DEFAULT_FGSERVICE_MIN_SHOWN_TIME = 2*1000;
@@ -216,6 +222,11 @@
private static final boolean DEFAULT_USE_MODERN_TRIM = true;
/**
+ * The default value to {@link #KEY_ENABLE_NEW_OOMADJ}.
+ */
+ private static final boolean DEFAULT_ENABLE_NEW_OOM_ADJ = false;
+
+ /**
* Same as {@link TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED}
*/
private static final int
@@ -1051,6 +1062,9 @@
/** @see #KEY_USE_MODERN_TRIM */
public boolean USE_MODERN_TRIM = DEFAULT_USE_MODERN_TRIM;
+ /** @see #KEY_ENABLE_NEW_OOMADJ */
+ public boolean ENABLE_NEW_OOMADJ = DEFAULT_ENABLE_NEW_OOM_ADJ;
+
private final OnPropertiesChangedListener mOnDeviceConfigChangedListener =
new OnPropertiesChangedListener() {
@Override
@@ -1308,6 +1322,7 @@
CUR_TRIM_CACHED_PROCESSES = (Integer.min(CUR_MAX_CACHED_PROCESSES, MAX_CACHED_PROCESSES)
- rawMaxEmptyProcesses) / 3;
+ loadNativeBootDeviceConfigConstants();
}
public void start(ContentResolver resolver) {
@@ -1347,6 +1362,11 @@
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_COMPONENT_ALIAS));
}
+ private void loadNativeBootDeviceConfigConstants() {
+ ENABLE_NEW_OOMADJ = getDeviceConfigBoolean(KEY_ENABLE_NEW_OOMADJ,
+ DEFAULT_ENABLE_NEW_OOM_ADJ);
+ }
+
public void setOverrideMaxCachedProcesses(int value) {
mOverrideMaxCachedProcesses = value;
updateMaxCachedProcesses();
@@ -1997,6 +2017,13 @@
DEFAULT_USE_MODERN_TRIM);
}
+ private void updateEnableNewOomAdj() {
+ ENABLE_NEW_OOMADJ = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
+ KEY_ENABLE_NEW_OOMADJ,
+ DEFAULT_ENABLE_NEW_OOM_ADJ);
+ }
+
private void updateFGSPermissionEnforcementFlagsIfNecessary(@NonNull String name) {
ForegroundServiceTypePolicy.getDefaultPolicy()
.updatePermissionEnforcementFlagIfNecessary(name);
@@ -2187,6 +2214,9 @@
pw.print(" "); pw.print(KEY_TIERED_CACHED_ADJ_DECAY_TIME);
pw.print("="); pw.println(TIERED_CACHED_ADJ_DECAY_TIME);
+ pw.print(" "); pw.print(KEY_ENABLE_NEW_OOMADJ);
+ pw.print("="); pw.println(ENABLE_NEW_OOMADJ);
+
pw.println();
if (mOverrideMaxCachedProcesses >= 0) {
pw.print(" mOverrideMaxCachedProcesses="); pw.println(mOverrideMaxCachedProcesses);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index a0fae26..c1f2f67 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2029,6 +2029,7 @@
app.makeActive(mSystemThread.getApplicationThread(), mProcessStats);
app.mProfile.addHostingComponentType(HOSTING_COMPONENT_TYPE_SYSTEM);
addPidLocked(app);
+ mOomAdjuster.onProcessBeginLocked(app);
updateLruProcessLocked(app, false, null);
updateOomAdjLocked(OOM_ADJ_REASON_SYSTEM_INIT);
}
@@ -2422,7 +2423,9 @@
mProcessList.init(this, activeUids, mPlatformCompat);
mAppProfiler = new AppProfiler(this, BackgroundThread.getHandler().getLooper(), null);
mPhantomProcessList = new PhantomProcessList(this);
- mOomAdjuster = new OomAdjuster(this, mProcessList, activeUids, handlerThread);
+ mOomAdjuster = mConstants.ENABLE_NEW_OOMADJ
+ ? new OomAdjusterModernImpl(this, mProcessList, activeUids, handlerThread)
+ : new OomAdjuster(this, mProcessList, activeUids, handlerThread);
mIntentFirewall = null;
mProcessStats = new ProcessStatsService(this, mContext.getCacheDir());
@@ -2483,7 +2486,9 @@
mAppProfiler = new AppProfiler(this, BackgroundThread.getHandler().getLooper(),
new LowMemDetector(this));
mPhantomProcessList = new PhantomProcessList(this);
- mOomAdjuster = new OomAdjuster(this, mProcessList, activeUids);
+ mOomAdjuster = mConstants.ENABLE_NEW_OOMADJ
+ ? new OomAdjusterModernImpl(this, mProcessList, activeUids)
+ : new OomAdjuster(this, mProcessList, activeUids);
// Broadcast policy parameters
final BroadcastConstants foreConstants = new BroadcastConstants(
@@ -4595,6 +4600,7 @@
EventLogTags.writeAmProcBound(app.userId, pid, app.processName);
synchronized (mProcLock) {
+ mOomAdjuster.onProcessBeginLocked(app);
mOomAdjuster.setAttachingProcessStatesLSP(app);
clearProcessForegroundLocked(app);
app.setDebugging(false);
@@ -6980,6 +6986,7 @@
sdkSandboxClientAppPackage,
new HostingRecord(HostingRecord.HOSTING_TYPE_ADDED_APPLICATION,
customProcess != null ? customProcess : info.processName));
+ mOomAdjuster.onProcessBeginLocked(app);
updateLruProcessLocked(app, false, null);
updateOomAdjLocked(app, OOM_ADJ_REASON_PROCESS_BEGIN);
}
diff --git a/services/core/java/com/android/server/am/BroadcastConstants.java b/services/core/java/com/android/server/am/BroadcastConstants.java
index 8c1fd51..2fff79b 100644
--- a/services/core/java/com/android/server/am/BroadcastConstants.java
+++ b/services/core/java/com/android/server/am/BroadcastConstants.java
@@ -373,7 +373,7 @@
* Return the {@link SystemProperty} name for the given key in our
* {@link DeviceConfig} namespace.
*/
- private @NonNull String propertyFor(@NonNull String key) {
+ private static @NonNull String propertyFor(@NonNull String key) {
return "persist.device_config." + NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT + "." + key;
}
@@ -382,11 +382,11 @@
* {@link DeviceConfig} namespace, but with a different prefix that can be
* used to locally override the {@link DeviceConfig} value.
*/
- private @NonNull String propertyOverrideFor(@NonNull String key) {
+ private static @NonNull String propertyOverrideFor(@NonNull String key) {
return "persist.sys." + NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT + "." + key;
}
- private boolean getDeviceConfigBoolean(@NonNull String key, boolean def) {
+ static boolean getDeviceConfigBoolean(@NonNull String key, boolean def) {
return SystemProperties.getBoolean(propertyOverrideFor(key),
SystemProperties.getBoolean(propertyFor(key), def));
}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 459c6ff..1f9e89e 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -41,6 +41,7 @@
import static android.app.ActivityManager.PROCESS_STATE_SERVICE;
import static android.app.ActivityManager.PROCESS_STATE_TOP;
import static android.app.ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
+import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN;
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_ACTIVITY;
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_ALLOWLIST;
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_BACKUP;
@@ -124,6 +125,7 @@
import static com.android.server.am.ProcessList.VISIBLE_APP_ADJ;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal.OomAdjReason;
@@ -369,20 +371,21 @@
*/
private final Handler mProcessGroupHandler;
- private final int[] mTmpSchedGroup = new int[1];
+ protected final int[] mTmpSchedGroup = new int[1];
- private final ActivityManagerService mService;
- private final ProcessList mProcessList;
- private final ActivityManagerGlobalLock mProcLock;
+ final ActivityManagerService mService;
+ final ProcessList mProcessList;
+ final ActivityManagerGlobalLock mProcLock;
private final int mNumSlots;
- private final ArrayList<ProcessRecord> mTmpProcessList = new ArrayList<ProcessRecord>();
- private final ArrayList<UidRecord> mTmpBecameIdle = new ArrayList<UidRecord>();
- private final ActiveUids mTmpUidRecords;
- private final ArrayDeque<ProcessRecord> mTmpQueue;
- private final ArraySet<ProcessRecord> mTmpProcessSet = new ArraySet<>();
- private final ArraySet<ProcessRecord> mPendingProcessSet = new ArraySet<>();
- private final ArraySet<ProcessRecord> mProcessesInCycle = new ArraySet<>();
+ protected final ArrayList<ProcessRecord> mTmpProcessList = new ArrayList<ProcessRecord>();
+ protected final ArrayList<ProcessRecord> mTmpProcessList2 = new ArrayList<ProcessRecord>();
+ protected final ArrayList<UidRecord> mTmpBecameIdle = new ArrayList<UidRecord>();
+ protected final ActiveUids mTmpUidRecords;
+ protected final ArrayDeque<ProcessRecord> mTmpQueue;
+ protected final ArraySet<ProcessRecord> mTmpProcessSet = new ArraySet<>();
+ protected final ArraySet<ProcessRecord> mPendingProcessSet = new ArraySet<>();
+ protected final ArraySet<ProcessRecord> mProcessesInCycle = new ArraySet<>();
/**
* Flag to mark if there is an ongoing oomAdjUpdate: potentially the oomAdjUpdate
@@ -412,7 +415,7 @@
this(service, processList, activeUids, createAdjusterThread());
}
- private static ServiceThread createAdjusterThread() {
+ static ServiceThread createAdjusterThread() {
// The process group is usually critical to the response time of foreground app, so the
// setter should apply it as soon as possible.
final ServiceThread adjusterThread =
@@ -532,7 +535,7 @@
mPendingProcessSet.remove(app);
mProcessesInCycle.clear();
- computeOomAdjLSP(app, cachedAdj, topApp, false, now, false, true);
+ computeOomAdjLSP(app, cachedAdj, topApp, false, now, false, true, oomAdjReason, true);
if (!mProcessesInCycle.isEmpty()) {
// We can't use the score here if there is a cycle, abort.
for (int i = mProcessesInCycle.size() - 1; i >= 0; i--) {
@@ -550,7 +553,7 @@
&& (uidRec.getSetProcState() != uidRec.getCurProcState()
|| uidRec.getSetCapability() != uidRec.getCurCapability()
|| uidRec.isSetAllowListed() != uidRec.isCurAllowListed())) {
- ActiveUids uids = mTmpUidRecords;
+ final ActiveUids uids = mTmpUidRecords;
uids.clear();
uids.put(uidRec.getUid(), uidRec);
updateUidsLSP(uids, SystemClock.elapsedRealtime());
@@ -633,19 +636,20 @@
}
@GuardedBy({"mService", "mProcLock"})
- private boolean performUpdateOomAdjLSP(ProcessRecord app, @OomAdjReason int oomAdjReason) {
+ protected boolean performUpdateOomAdjLSP(ProcessRecord app, @OomAdjReason int oomAdjReason) {
final ProcessRecord topApp = mService.getTopApp();
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, oomAdjReasonToString(oomAdjReason));
mService.mOomAdjProfiler.oomAdjStarted();
mAdjSeq++;
- // Firstly, try to see if the importance of itself gets changed
final ProcessStateRecord state = app.mState;
final boolean wasCached = state.isCached();
final int oldAdj = state.getCurRawAdj();
final int cachedAdj = oldAdj >= CACHED_APP_MIN_ADJ
? oldAdj : UNKNOWN_ADJ;
+
+ // Firstly, try to see if the importance of itself gets changed
final boolean wasBackground = ActivityManager.isProcStateBackground(
state.getSetProcState());
final int oldCap = state.getSetCapability();
@@ -693,8 +697,6 @@
mPendingProcessSet.clear();
if (!containsCycle) {
- // Reset the flag
- state.setReachable(false);
// Remove this app from the return list because we've done the computation on it.
processes.remove(app);
}
@@ -718,8 +720,13 @@
return true;
}
+ /**
+ * Collect the reachable processes from the given {@code apps}, the result will be
+ * returned in the given {@code processes}, which will include the processes from
+ * the given {@code apps}.
+ */
@GuardedBy("mService")
- private boolean collectReachableProcessesLocked(ArraySet<ProcessRecord> apps,
+ protected boolean collectReachableProcessesLocked(ArraySet<ProcessRecord> apps,
ArrayList<ProcessRecord> processes, ActiveUids uids) {
final ArrayDeque<ProcessRecord> queue = mTmpQueue;
queue.clear();
@@ -824,11 +831,15 @@
if (size > 0) {
// Reverse the process list, since the updateOomAdjInnerLSP scans from the end of it.
for (int l = 0, r = size - 1; l < r; l++, r--) {
- ProcessRecord t = processes.get(l);
- processes.set(l, processes.get(r));
+ final ProcessRecord t = processes.get(l);
+ final ProcessRecord u = processes.get(r);
+ t.mState.setReachable(false);
+ u.mState.setReachable(false);
+ processes.set(l, u);
processes.set(r, t);
}
}
+
return containsCycle;
}
@@ -928,24 +939,18 @@
* Update OomAdj for all processes within the given list (could be partial), or the whole LRU
* list if the given list is null; when it's partial update, each process's client proc won't
* get evaluated recursively here.
+ *
+ * <p>Note: If the given {@code processes} is not null, the expectation to it is, the caller
+ * must have called {@link collectReachableProcessesLocked} on it.
*/
@GuardedBy({"mService", "mProcLock"})
- private void updateOomAdjInnerLSP(@OomAdjReason int oomAdjReason, final ProcessRecord topApp,
+ protected void updateOomAdjInnerLSP(@OomAdjReason int oomAdjReason, final ProcessRecord topApp,
ArrayList<ProcessRecord> processes, ActiveUids uids, boolean potentialCycles,
boolean startProfiling) {
- if (startProfiling) {
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, oomAdjReasonToString(oomAdjReason));
- mService.mOomAdjProfiler.oomAdjStarted();
- }
- final long now = SystemClock.uptimeMillis();
- final long nowElapsed = SystemClock.elapsedRealtime();
- final long oldTime = now - mConstants.mMaxEmptyTimeMillis;
final boolean fullUpdate = processes == null;
+ final ArrayList<ProcessRecord> activeProcesses = fullUpdate
+ ? mProcessList.getLruProcessesLOSP() : processes;
ActiveUids activeUids = uids;
- ArrayList<ProcessRecord> activeProcesses = fullUpdate ? mProcessList.getLruProcessesLOSP()
- : processes;
- final int numProc = activeProcesses.size();
-
if (activeUids == null) {
final int numUids = mActiveUids.size();
activeUids = mTmpUidRecords;
@@ -956,14 +961,14 @@
}
}
- // Reset state in all uid records.
- for (int i = activeUids.size() - 1; i >= 0; i--) {
- final UidRecord uidRec = activeUids.valueAt(i);
- if (DEBUG_UID_OBSERVERS) {
- Slog.i(TAG_UID_OBSERVERS, "Starting update of " + uidRec);
- }
- uidRec.reset();
+ if (startProfiling) {
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, oomAdjReasonToString(oomAdjReason));
+ mService.mOomAdjProfiler.oomAdjStarted();
}
+ final long now = SystemClock.uptimeMillis();
+ final long nowElapsed = SystemClock.elapsedRealtime();
+ final long oldTime = now - mConstants.mMaxEmptyTimeMillis;
+ final int numProc = activeProcesses.size();
mAdjSeq++;
if (fullUpdate) {
@@ -971,6 +976,9 @@
mNewNumAServiceProcs = 0;
}
+ // Reset state in all uid records.
+ resetUidRecordsLsp(activeUids);
+
boolean retryCycles = false;
boolean computeClients = fullUpdate || potentialCycles;
@@ -996,8 +1004,9 @@
if (!app.isKilledByAm() && app.getThread() != null) {
state.setProcStateChanged(false);
app.mOptRecord.setLastOomAdjChangeReason(oomAdjReason);
+ // It won't enter cycle if not computing clients.
computeOomAdjLSP(app, UNKNOWN_ADJ, topApp, fullUpdate, now, false,
- computeClients); // It won't enter cycle if not computing clients.
+ computeClients, oomAdjReason, true);
// if any app encountered a cycle, we need to perform an additional loop later
retryCycles |= state.containsCycle();
// Keep the completedAdjSeq to up to date.
@@ -1034,7 +1043,7 @@
final ProcessStateRecord state = app.mState;
if (!app.isKilledByAm() && app.getThread() != null && state.containsCycle()) {
if (computeOomAdjLSP(app, UNKNOWN_ADJ, topApp, true, now,
- true, true)) {
+ true, true, oomAdjReason, true)) {
retryCycles = true;
}
}
@@ -1045,10 +1054,33 @@
assignCachedAdjIfNecessary(mProcessList.getLruProcessesLOSP());
+ postUpdateOomAdjInnerLSP(oomAdjReason, activeUids, now, nowElapsed, oldTime);
+
+ if (startProfiling) {
+ mService.mOomAdjProfiler.oomAdjEnded();
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+ }
+ }
+
+ @GuardedBy({"mService", "mProcLock"})
+ private void resetUidRecordsLsp(@NonNull ActiveUids activeUids) {
+ // Reset state in all uid records.
+ for (int i = activeUids.size() - 1; i >= 0; i--) {
+ final UidRecord uidRec = activeUids.valueAt(i);
+ if (DEBUG_UID_OBSERVERS) {
+ Slog.i(TAG_UID_OBSERVERS, "Starting update of " + uidRec);
+ }
+ uidRec.reset();
+ }
+ }
+
+ @GuardedBy({"mService", "mProcLock"})
+ protected void postUpdateOomAdjInnerLSP(@OomAdjReason int oomAdjReason, ActiveUids activeUids,
+ long now, long nowElapsed, long oldTime) {
mNumNonCachedProcs = 0;
mNumCachedHiddenProcs = 0;
- boolean allChanged = updateAndTrimProcessLSP(now, nowElapsed, oldTime, activeUids,
+ final boolean allChanged = updateAndTrimProcessLSP(now, nowElapsed, oldTime, activeUids,
oomAdjReason);
mNumServiceProcs = mNewNumServiceProcs;
@@ -1085,14 +1117,10 @@
Slog.d(TAG_OOM_ADJ, "Did OOM ADJ in " + duration + "ms");
}
}
- if (startProfiling) {
- mService.mOomAdjProfiler.oomAdjEnded();
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- }
}
@GuardedBy({"mService", "mProcLock"})
- private void assignCachedAdjIfNecessary(ArrayList<ProcessRecord> lruList) {
+ protected void assignCachedAdjIfNecessary(ArrayList<ProcessRecord> lruList) {
final int numLru = lruList.size();
if (mConstants.USE_TIERED_CACHED_ADJ) {
final long now = SystemClock.uptimeMillis();
@@ -1413,7 +1441,7 @@
}
@GuardedBy({"mService", "mProcLock"})
- private void updateAppUidRecIfNecessaryLSP(final ProcessRecord app) {
+ protected void updateAppUidRecIfNecessaryLSP(final ProcessRecord app) {
if (!app.isKilledByAm() && app.getThread() != null) {
if (app.isolated && app.mServices.numberOfRunningServices() <= 0
&& app.getIsolatedEntryPoint() == null) {
@@ -1442,7 +1470,7 @@
}
@GuardedBy({"mService", "mProcLock"})
- private void updateUidsLSP(ActiveUids activeUids, final long nowElapsed) {
+ protected void updateUidsLSP(ActiveUids activeUids, final long nowElapsed) {
// This compares previously set procstate to the current procstate in regards to whether
// or not the app's network access will be blocked. So, this needs to be called before
// we update the UidRecord's procstate by calling {@link UidRecord#setSetProcState}.
@@ -1580,7 +1608,7 @@
return true;
}
- private final ComputeOomAdjWindowCallback mTmpComputeOomAdjWindowCallback =
+ protected final ComputeOomAdjWindowCallback mTmpComputeOomAdjWindowCallback =
new ComputeOomAdjWindowCallback();
/** These methods are called inline during computeOomAdjLSP(), on the same thread */
@@ -1719,24 +1747,30 @@
}
@GuardedBy({"mService", "mProcLock"})
- private boolean computeOomAdjLSP(ProcessRecord app, int cachedAdj,
+ protected boolean computeOomAdjLSP(ProcessRecord app, int cachedAdj,
ProcessRecord topApp, boolean doingAll, long now, boolean cycleReEval,
- boolean computeClients) {
+ boolean computeClients, int oomAdjReason, boolean couldRecurse) {
final ProcessStateRecord state = app.mState;
- if (mAdjSeq == state.getAdjSeq()) {
- if (state.getAdjSeq() == state.getCompletedAdjSeq()) {
- // This adjustment has already been computed successfully.
- return false;
- } else {
- // The process is being computed, so there is a cycle. We cannot
- // rely on this process's state.
- state.setContainsCycle(true);
- mProcessesInCycle.add(app);
+ if (couldRecurse) {
+ if (mAdjSeq == state.getAdjSeq()) {
+ if (state.getAdjSeq() == state.getCompletedAdjSeq()) {
+ // This adjustment has already been computed successfully.
+ return false;
+ } else {
+ // The process is being computed, so there is a cycle. We cannot
+ // rely on this process's state.
+ state.setContainsCycle(true);
+ mProcessesInCycle.add(app);
- return false;
+ return false;
+ }
}
}
+ int prevAppAdj = getInitialAdj(app);
+ int prevProcState = getInitialProcState(app);
+ int prevCapability = getInitialCapability(app);
+
if (app.getThread() == null) {
state.setAdjSeq(mAdjSeq);
state.setCurrentSchedulingGroup(SCHED_GROUP_BACKGROUND);
@@ -1745,6 +1779,8 @@
state.setCurRawAdj(CACHED_APP_MAX_ADJ);
state.setCompletedAdjSeq(state.getAdjSeq());
state.setCurCapability(PROCESS_CAPABILITY_NONE);
+ onProcessStateChanged(app, prevProcState);
+ onProcessOomAdjChanged(app, prevAppAdj);
return false;
}
@@ -1753,7 +1789,7 @@
state.setAdjTarget(null);
state.setEmpty(false);
state.setCached(false);
- if (!cycleReEval) {
+ if (!couldRecurse || !cycleReEval) {
// Don't reset this flag when doing cycles re-evaluation.
state.setNoKillOnBgRestrictedAndIdle(false);
// If this UID is currently allowlisted, it should not be frozen.
@@ -1764,9 +1800,6 @@
final int appUid = app.info.uid;
final int logUid = mService.mCurOomAdjUid;
- int prevAppAdj = state.getCurAdj();
- int prevProcState = state.getCurProcState();
- int prevCapability = state.getCurCapability();
final ProcessServiceRecord psr = app.mServices;
if (state.getMaxAdj() <= FOREGROUND_APP_ADJ) {
@@ -1812,6 +1845,8 @@
state.setCurRawProcState(state.getCurProcState());
state.setCurAdj(state.getMaxAdj());
state.setCompletedAdjSeq(state.getAdjSeq());
+ onProcessStateChanged(app, prevProcState);
+ onProcessOomAdjChanged(app, prevAppAdj);
// if curAdj is less than prevAppAdj, then this process was promoted
return state.getCurAdj() < prevAppAdj || state.getCurProcState() < prevProcState;
}
@@ -1825,7 +1860,7 @@
int adj;
int schedGroup;
int procState;
- int capability = cycleReEval ? app.mState.getCurCapability() : 0;
+ int capability = cycleReEval ? getInitialCapability(app) : 0;
boolean foregroundActivities = false;
boolean hasVisibleActivities = false;
@@ -1904,7 +1939,7 @@
// value that the caller wants us to.
adj = cachedAdj;
procState = PROCESS_STATE_CACHED_EMPTY;
- if (!state.containsCycle()) {
+ if (!couldRecurse || !state.containsCycle()) {
state.setCached(true);
state.setEmpty(true);
state.setAdjType("cch-empty");
@@ -2169,8 +2204,10 @@
}
}
- boolean boundByNonBgRestricted = state.isCurBoundByNonBgRestrictedApp();
- boolean scheduleLikeTopApp = false;
+ state.setCurBoundByNonBgRestrictedApp(getInitialIsCurBoundByNonBgRestrictedApp(app));
+
+ state.setScheduleLikeTopApp(false);
+
for (int is = psr.numberOfRunningServices() - 1;
is >= 0 && (adj > FOREGROUND_APP_ADJ
|| schedGroup == SCHED_GROUP_BACKGROUND
@@ -2243,6 +2280,18 @@
}
}
+ if (!couldRecurse) {
+ // We're entering recursive functions below, if we're told it's not a recursive
+ // loop, abort here.
+ continue;
+ }
+
+
+ state.setCurRawAdj(adj);
+ state.setCurRawProcState(procState);
+ state.setCurrentSchedulingGroup(schedGroup);
+ state.setCurCapability(capability);
+
ArrayMap<IBinder, ArrayList<ConnectionRecord>> serviceConnections = s.getConnections();
for (int conni = serviceConnections.size() - 1;
conni >= 0 && (adj > FOREGROUND_APP_ADJ
@@ -2263,335 +2312,13 @@
continue;
}
- boolean trackedProcState = false;
+ computeServiceHostOomAdjLSP(cr, app, cr.binding.client, now, topApp, doingAll,
+ cycleReEval, computeClients, oomAdjReason, cachedAdj, true);
- ProcessRecord client = cr.binding.client;
- if (app.isSdkSandbox && cr.binding.attributedClient != null) {
- // For SDK sandboxes, use the attributed client (eg the app that
- // requested the sandbox)
- client = cr.binding.attributedClient;
- }
- final ProcessStateRecord cstate = client.mState;
- if (computeClients) {
- computeOomAdjLSP(client, cachedAdj, topApp, doingAll, now,
- cycleReEval, true);
- } else {
- cstate.setCurRawAdj(cstate.getCurAdj());
- cstate.setCurRawProcState(cstate.getCurProcState());
- }
-
- int clientAdj = cstate.getCurRawAdj();
- int clientProcState = cstate.getCurRawProcState();
-
- final boolean clientIsSystem = clientProcState < PROCESS_STATE_TOP;
-
- boundByNonBgRestricted |= cstate.isCurBoundByNonBgRestrictedApp()
- || clientProcState <= PROCESS_STATE_BOUND_TOP
- || (clientProcState == PROCESS_STATE_FOREGROUND_SERVICE
- && !cstate.isBackgroundRestricted());
-
- if (client.mOptRecord.shouldNotFreeze()) {
- // Propagate the shouldNotFreeze flag down the bindings.
- app.mOptRecord.setShouldNotFreeze(true);
- }
-
- // We always propagate PROCESS_CAPABILITY_BFSL over bindings here,
- // but, right before actually setting it to the process,
- // we check the final procstate, and remove it if the procsate is below BFGS.
- capability |= getBfslCapabilityFromClient(client);
-
- if (cr.notHasFlag(Context.BIND_WAIVE_PRIORITY)) {
- if (cr.hasFlag(Context.BIND_INCLUDE_CAPABILITIES)) {
- capability |= cstate.getCurCapability();
- }
-
- // If an app has network capability by default
- // (by having procstate <= BFGS), then the apps it binds to will get
- // elevated to a high enough procstate anyway to get network unless they
- // request otherwise, so don't propagate the network capability by default
- // in this case unless they explicitly request it.
- if ((cstate.getCurCapability()
- & PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK) != 0) {
- if (clientProcState <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
- // This is used to grant network access to Expedited Jobs.
- if (cr.hasFlag(Context.BIND_BYPASS_POWER_NETWORK_RESTRICTIONS)) {
- capability |= PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK;
- }
- } else {
- capability |= PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK;
- }
- }
- if ((cstate.getCurCapability()
- & PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK) != 0) {
- if (clientProcState <= PROCESS_STATE_IMPORTANT_FOREGROUND) {
- // This is used to grant network access to User Initiated Jobs.
- if (cr.hasFlag(Context.BIND_BYPASS_USER_NETWORK_RESTRICTIONS)) {
- capability |= PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK;
- }
- }
- }
-
- if (shouldSkipDueToCycle(app, cstate, procState, adj, cycleReEval)) {
- continue;
- }
-
- if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) {
- // If the other app is cached for any reason, for purposes here
- // we are going to consider it empty. The specific cached state
- // doesn't propagate except under certain conditions.
- clientProcState = PROCESS_STATE_CACHED_EMPTY;
- }
- String adjType = null;
- if (cr.hasFlag(Context.BIND_ALLOW_OOM_MANAGEMENT)) {
- // Similar to BIND_WAIVE_PRIORITY, keep it unfrozen.
- if (clientAdj < CACHED_APP_MIN_ADJ) {
- app.mOptRecord.setShouldNotFreeze(true);
- }
- // Not doing bind OOM management, so treat
- // this guy more like a started service.
- if (state.hasShownUi() && !state.getCachedIsHomeProcess()) {
- // If this process has shown some UI, let it immediately
- // go to the LRU list because it may be pretty heavy with
- // UI stuff. We'll tag it with a label just to help
- // debug and understand what is going on.
- if (adj > clientAdj) {
- adjType = "cch-bound-ui-services";
- }
- state.setCached(false);
- clientAdj = adj;
- clientProcState = procState;
- } else {
- if (now >= (s.lastActivity
- + mConstants.MAX_SERVICE_INACTIVITY)) {
- // This service has not seen activity within
- // recent memory, so allow it to drop to the
- // LRU list if there is no other reason to keep
- // it around. We'll also tag it with a label just
- // to help debug and undertand what is going on.
- if (adj > clientAdj) {
- adjType = "cch-bound-services";
- }
- clientAdj = adj;
- }
- }
- }
- if (adj > clientAdj) {
- // If this process has recently shown UI, and
- // the process that is binding to it is less
- // important than being visible, then we don't
- // care about the binding as much as we care
- // about letting this process get into the LRU
- // list to be killed and restarted if needed for
- // memory.
- if (state.hasShownUi() && !state.getCachedIsHomeProcess()
- && clientAdj > PERCEPTIBLE_APP_ADJ) {
- if (adj >= CACHED_APP_MIN_ADJ) {
- adjType = "cch-bound-ui-services";
- }
- } else {
- int newAdj;
- int lbAdj = VISIBLE_APP_ADJ; // lower bound of adj.
- if (cr.hasFlag(Context.BIND_ABOVE_CLIENT
- | Context.BIND_IMPORTANT)) {
- if (clientAdj >= PERSISTENT_SERVICE_ADJ) {
- newAdj = clientAdj;
- } else {
- // make this service persistent
- newAdj = PERSISTENT_SERVICE_ADJ;
- schedGroup = SCHED_GROUP_DEFAULT;
- procState = ActivityManager.PROCESS_STATE_PERSISTENT;
- cr.trackProcState(procState, mAdjSeq);
- trackedProcState = true;
- }
- } else if (cr.hasFlag(Context.BIND_NOT_PERCEPTIBLE)
- && clientAdj <= PERCEPTIBLE_APP_ADJ
- && adj >= (lbAdj = PERCEPTIBLE_LOW_APP_ADJ)) {
- newAdj = PERCEPTIBLE_LOW_APP_ADJ;
- } else if (cr.hasFlag(Context.BIND_ALMOST_PERCEPTIBLE)
- && cr.notHasFlag(Context.BIND_NOT_FOREGROUND)
- && clientAdj < PERCEPTIBLE_APP_ADJ
- && adj >= (lbAdj = PERCEPTIBLE_APP_ADJ)) {
- // This is for user-initiated jobs.
- // We use APP_ADJ + 1 here, so we can tell them apart from FGS.
- newAdj = PERCEPTIBLE_APP_ADJ + 1;
- } else if (cr.hasFlag(Context.BIND_ALMOST_PERCEPTIBLE)
- && cr.hasFlag(Context.BIND_NOT_FOREGROUND)
- && clientAdj < PERCEPTIBLE_APP_ADJ
- && adj >= (lbAdj = (PERCEPTIBLE_MEDIUM_APP_ADJ + 2))) {
- // This is for expedited jobs.
- // We use MEDIUM_APP_ADJ + 2 here, so we can tell apart
- // EJ and short-FGS.
- newAdj = PERCEPTIBLE_MEDIUM_APP_ADJ + 2;
- } else if (cr.hasFlag(Context.BIND_NOT_VISIBLE)
- && clientAdj < PERCEPTIBLE_APP_ADJ
- && adj >= (lbAdj = PERCEPTIBLE_APP_ADJ)) {
- newAdj = PERCEPTIBLE_APP_ADJ;
- } else if (clientAdj >= PERCEPTIBLE_APP_ADJ) {
- newAdj = clientAdj;
- } else if (cr.hasFlag(BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE)
- && clientAdj <= VISIBLE_APP_ADJ
- && adj > VISIBLE_APP_ADJ) {
- newAdj = VISIBLE_APP_ADJ;
- } else {
- if (adj > VISIBLE_APP_ADJ) {
- // TODO: Is this too limiting for apps bound from TOP?
- newAdj = Math.max(clientAdj, lbAdj);
- } else {
- newAdj = adj;
- }
- }
- if (!cstate.isCached()) {
- state.setCached(false);
- }
- if (adj > newAdj) {
- adj = newAdj;
- state.setCurRawAdj(adj);
- adjType = "service";
- }
- }
- }
- if (cr.notHasFlag(Context.BIND_NOT_FOREGROUND
- | Context.BIND_IMPORTANT_BACKGROUND)) {
- // This will treat important bound services identically to
- // the top app, which may behave differently than generic
- // foreground work.
- final int curSchedGroup = cstate.getCurrentSchedulingGroup();
- if (curSchedGroup > schedGroup) {
- if (cr.hasFlag(Context.BIND_IMPORTANT)) {
- schedGroup = curSchedGroup;
- } else {
- schedGroup = SCHED_GROUP_DEFAULT;
- }
- }
- if (clientProcState < PROCESS_STATE_TOP) {
- // Special handling for above-top states (persistent
- // processes). These should not bring the current process
- // into the top state, since they are not on top. Instead
- // give them the best bound state after that.
- if (cr.hasFlag(BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE)) {
- clientProcState = PROCESS_STATE_FOREGROUND_SERVICE;
- } else if (cr.hasFlag(Context.BIND_FOREGROUND_SERVICE)) {
- clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
- } else if (mService.mWakefulness.get()
- == PowerManagerInternal.WAKEFULNESS_AWAKE
- && cr.hasFlag(Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE))
- {
- clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
- } else {
- clientProcState =
- PROCESS_STATE_IMPORTANT_FOREGROUND;
- }
- } else if (clientProcState == PROCESS_STATE_TOP) {
- // Go at most to BOUND_TOP, unless requested to elevate
- // to client's state.
- clientProcState = PROCESS_STATE_BOUND_TOP;
- final boolean enabled = cstate.getCachedCompatChange(
- CACHED_COMPAT_CHANGE_PROCESS_CAPABILITY);
- if (enabled) {
- if (cr.hasFlag(Context.BIND_INCLUDE_CAPABILITIES)) {
- // TOP process passes all capabilities to the service.
- capability |= cstate.getCurCapability();
- } else {
- // TOP process passes no capability to the service.
- }
- } else {
- // TOP process passes all capabilities to the service.
- capability |= cstate.getCurCapability();
- }
- }
- } else if (cr.notHasFlag(Context.BIND_IMPORTANT_BACKGROUND)) {
- if (clientProcState <
- PROCESS_STATE_TRANSIENT_BACKGROUND) {
- clientProcState =
- PROCESS_STATE_TRANSIENT_BACKGROUND;
- }
- } else {
- if (clientProcState <
- PROCESS_STATE_IMPORTANT_BACKGROUND) {
- clientProcState =
- PROCESS_STATE_IMPORTANT_BACKGROUND;
- }
- }
-
- if (schedGroup < SCHED_GROUP_TOP_APP
- && cr.hasFlag(Context.BIND_SCHEDULE_LIKE_TOP_APP)
- && clientIsSystem) {
- schedGroup = SCHED_GROUP_TOP_APP;
- scheduleLikeTopApp = true;
- }
-
- if (!trackedProcState) {
- cr.trackProcState(clientProcState, mAdjSeq);
- }
-
- if (procState > clientProcState) {
- procState = clientProcState;
- state.setCurRawProcState(procState);
- if (adjType == null) {
- adjType = "service";
- }
- }
- if (procState < PROCESS_STATE_IMPORTANT_BACKGROUND
- && cr.hasFlag(Context.BIND_SHOWING_UI)) {
- app.setPendingUiClean(true);
- }
- if (adjType != null) {
- state.setAdjType(adjType);
- state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo
- .REASON_SERVICE_IN_USE);
- state.setAdjSource(client);
- state.setAdjSourceProcState(clientProcState);
- state.setAdjTarget(s.instanceName);
- if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
- reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to " + adjType
- + ": " + app + ", due to " + client
- + " adj=" + adj + " procState="
- + ProcessList.makeProcStateString(procState));
- }
- }
- } else { // BIND_WAIVE_PRIORITY == true
- // BIND_WAIVE_PRIORITY bindings are special when it comes to the
- // freezer. Processes bound via WPRI are expected to be running,
- // but they are not promoted in the LRU list to keep them out of
- // cached. As a result, they can freeze based on oom_adj alone.
- // Normally, bindToDeath would fire when a cached app would die
- // in the background, but nothing will fire when a running process
- // pings a frozen process. Accordingly, any cached app that is
- // bound by an unfrozen app via a WPRI binding has to remain
- // unfrozen.
- if (clientAdj < CACHED_APP_MIN_ADJ) {
- app.mOptRecord.setShouldNotFreeze(true);
- }
- }
- if (cr.hasFlag(Context.BIND_TREAT_LIKE_ACTIVITY)) {
- psr.setTreatLikeActivity(true);
- }
- final ActivityServiceConnectionsHolder a = cr.activity;
- if (cr.hasFlag(Context.BIND_ADJUST_WITH_ACTIVITY)) {
- if (a != null && adj > FOREGROUND_APP_ADJ
- && a.isActivityVisible()) {
- adj = FOREGROUND_APP_ADJ;
- state.setCurRawAdj(adj);
- if (cr.notHasFlag(Context.BIND_NOT_FOREGROUND)) {
- if (cr.hasFlag(Context.BIND_IMPORTANT)) {
- schedGroup = SCHED_GROUP_TOP_APP_BOUND;
- } else {
- schedGroup = SCHED_GROUP_DEFAULT;
- }
- }
- state.setCached(false);
- state.setAdjType("service");
- state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo
- .REASON_SERVICE_IN_USE);
- state.setAdjSource(a);
- state.setAdjSourceProcState(procState);
- state.setAdjTarget(s.instanceName);
- if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
- reportOomAdjMessageLocked(TAG_OOM_ADJ,
- "Raise to service w/activity: " + app);
- }
- }
- }
+ adj = state.getCurRawAdj();
+ procState = state.getCurRawProcState();
+ schedGroup = state.getCurrentSchedulingGroup();
+ capability = state.getCurCapability();
}
}
}
@@ -2603,97 +2330,27 @@
|| procState > PROCESS_STATE_TOP);
provi--) {
ContentProviderRecord cpr = ppr.getProviderAt(provi);
- for (int i = cpr.connections.size() - 1;
- i >= 0 && (adj > FOREGROUND_APP_ADJ
- || schedGroup == SCHED_GROUP_BACKGROUND
- || procState > PROCESS_STATE_TOP);
- i--) {
- ContentProviderConnection conn = cpr.connections.get(i);
- ProcessRecord client = conn.client;
- final ProcessStateRecord cstate = client.mState;
- if (client == app) {
- // Being our own client is not interesting.
- continue;
- }
- if (computeClients) {
- computeOomAdjLSP(client, cachedAdj, topApp, doingAll, now, cycleReEval, true);
- } else {
- cstate.setCurRawAdj(cstate.getCurAdj());
- cstate.setCurRawProcState(cstate.getCurProcState());
- }
+ if (couldRecurse) {
+ // We're entering recursive functions below.
+ state.setCurRawAdj(adj);
+ state.setCurRawProcState(procState);
+ state.setCurrentSchedulingGroup(schedGroup);
+ state.setCurCapability(capability);
- if (shouldSkipDueToCycle(app, cstate, procState, adj, cycleReEval)) {
- continue;
- }
+ for (int i = cpr.connections.size() - 1;
+ i >= 0 && (adj > FOREGROUND_APP_ADJ
+ || schedGroup == SCHED_GROUP_BACKGROUND
+ || procState > PROCESS_STATE_TOP);
+ i--) {
+ ContentProviderConnection conn = cpr.connections.get(i);
+ ProcessRecord client = conn.client;
+ computeProviderHostOomAdjLSP(conn, app, client, now, topApp, doingAll,
+ cycleReEval, computeClients, oomAdjReason, cachedAdj, true);
- int clientAdj = cstate.getCurRawAdj();
- int clientProcState = cstate.getCurRawProcState();
-
- // We always propagate PROCESS_CAPABILITY_BFSL to providers here,
- // but, right before actually setting it to the process,
- // we check the final procstate, and remove it if the procsate is below BFGS.
- capability |= getBfslCapabilityFromClient(client);
-
- if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) {
- // If the other app is cached for any reason, for purposes here
- // we are going to consider it empty.
- clientProcState = PROCESS_STATE_CACHED_EMPTY;
- }
- if (client.mOptRecord.shouldNotFreeze()) {
- // Propagate the shouldNotFreeze flag down the bindings.
- app.mOptRecord.setShouldNotFreeze(true);
- }
-
- boundByNonBgRestricted |= cstate.isCurBoundByNonBgRestrictedApp()
- || clientProcState <= PROCESS_STATE_BOUND_TOP
- || (clientProcState == PROCESS_STATE_FOREGROUND_SERVICE
- && !cstate.isBackgroundRestricted());
-
- String adjType = null;
- if (adj > clientAdj) {
- if (state.hasShownUi() && !state.getCachedIsHomeProcess()
- && clientAdj > PERCEPTIBLE_APP_ADJ) {
- adjType = "cch-ui-provider";
- } else {
- adj = Math.max(clientAdj, FOREGROUND_APP_ADJ);
- state.setCurRawAdj(adj);
- adjType = "provider";
- }
- state.setCached(state.isCached() & cstate.isCached());
- }
-
- if (clientProcState <= PROCESS_STATE_FOREGROUND_SERVICE) {
- if (adjType == null) {
- adjType = "provider";
- }
- if (clientProcState == PROCESS_STATE_TOP) {
- clientProcState = PROCESS_STATE_BOUND_TOP;
- } else {
- clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
- }
- }
-
- conn.trackProcState(clientProcState, mAdjSeq);
- if (procState > clientProcState) {
- procState = clientProcState;
- state.setCurRawProcState(procState);
- }
- if (cstate.getCurrentSchedulingGroup() > schedGroup) {
- schedGroup = SCHED_GROUP_DEFAULT;
- }
- if (adjType != null) {
- state.setAdjType(adjType);
- state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo
- .REASON_PROVIDER_IN_USE);
- state.setAdjSource(client);
- state.setAdjSourceProcState(clientProcState);
- state.setAdjTarget(cpr.name);
- if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
- reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to " + adjType
- + ": " + app + ", due to " + client
- + " adj=" + adj + " procState="
- + ProcessList.makeProcStateString(procState));
- }
+ adj = state.getCurRawAdj();
+ procState = state.getCurRawProcState();
+ schedGroup = state.getCurrentSchedulingGroup();
+ capability = state.getCurCapability();
}
}
// If the provider has external (non-framework) process
@@ -2799,7 +2456,7 @@
// restrictions on screen off
if (procState >= PROCESS_STATE_BOUND_FOREGROUND_SERVICE
&& mService.mWakefulness.get() != PowerManagerInternal.WAKEFULNESS_AWAKE
- && !scheduleLikeTopApp) {
+ && !state.shouldScheduleLikeTopApp()) {
if (schedGroup > SCHED_GROUP_RESTRICTED) {
schedGroup = SCHED_GROUP_RESTRICTED;
}
@@ -2817,6 +2474,7 @@
capability &= ~PROCESS_CAPABILITY_BFSL;
}
+ state.setHasForegroundActivities(foregroundActivities);
if (app.isPendingFinishAttach()) {
// If the app is still starting up. We reset the computations to the
@@ -2834,22 +2492,580 @@
// it when computing the final cached adj later. Note that we don't need to
// worry about this for max adj above, since max adj will always be used to
// keep it out of the cached vaues.
- state.setCurAdj(adj);
state.setCurCapability(capability);
- state.setCurrentSchedulingGroup(schedGroup);
- state.setCurProcState(procState);
- state.setCurRawProcState(procState);
state.updateLastInvisibleTime(hasVisibleActivities);
- state.setHasForegroundActivities(foregroundActivities);
state.setCompletedAdjSeq(mAdjSeq);
- state.setCurBoundByNonBgRestrictedApp(boundByNonBgRestricted);
+
+ schedGroup = setIntermediateAdjLSP(app, adj, prevAppAdj, schedGroup);
+ setIntermediateProcStateLSP(app, procState, prevProcState);
+ setIntermediateSchedGroupLSP(state, schedGroup);
// if curAdj or curProcState improved, then this process was promoted
return state.getCurAdj() < prevAppAdj || state.getCurProcState() < prevProcState
|| state.getCurCapability() != prevCapability;
}
- private int getDefaultCapability(ProcessRecord app, int procState) {
+ /**
+ * @return The proposed change to the schedGroup.
+ */
+ @GuardedBy({"mService", "mProcLock"})
+ protected int setIntermediateAdjLSP(ProcessRecord app, int adj, int prevRawAppAdj,
+ int schedGroup) {
+ final ProcessStateRecord state = app.mState;
+ state.setCurRawAdj(adj);
+
+ adj = app.mServices.modifyRawOomAdj(adj);
+ if (adj > state.getMaxAdj()) {
+ adj = state.getMaxAdj();
+ if (adj <= PERCEPTIBLE_LOW_APP_ADJ) {
+ schedGroup = SCHED_GROUP_DEFAULT;
+ }
+ }
+
+ state.setCurAdj(adj);
+
+ return schedGroup;
+ }
+
+ @GuardedBy({"mService", "mProcLock"})
+ protected void setIntermediateProcStateLSP(ProcessRecord app, int procState,
+ int prevProcState) {
+ final ProcessStateRecord state = app.mState;
+ state.setCurProcState(procState);
+ state.setCurRawProcState(procState);
+ }
+
+ @GuardedBy({"mService", "mProcLock"})
+ protected void setIntermediateSchedGroupLSP(ProcessStateRecord state, int schedGroup) {
+ // Put bound foreground services in a special sched group for additional
+ // restrictions on screen off
+ if (state.getCurProcState() >= PROCESS_STATE_BOUND_FOREGROUND_SERVICE
+ && mService.mWakefulness.get() != PowerManagerInternal.WAKEFULNESS_AWAKE
+ && !state.shouldScheduleLikeTopApp()) {
+ if (schedGroup > SCHED_GROUP_RESTRICTED) {
+ schedGroup = SCHED_GROUP_RESTRICTED;
+ }
+ }
+
+ state.setCurrentSchedulingGroup(schedGroup);
+ }
+
+ @GuardedBy({"mService", "mProcLock"})
+ protected void computeServiceHostOomAdjLSP(ConnectionRecord cr, ProcessRecord app,
+ ProcessRecord client, long now, ProcessRecord topApp, boolean doingAll,
+ boolean cycleReEval, boolean computeClients, int oomAdjReason, int cachedAdj,
+ boolean couldRecurse) {
+ if (app.isPendingFinishAttach()) {
+ // We've set the attaching process state in the computeInitialOomAdjLSP. Skip it here.
+ return;
+ }
+
+ final ProcessStateRecord state = app.mState;
+ ProcessStateRecord cstate = client.mState;
+
+ if (couldRecurse) {
+ if (app.isSdkSandbox && cr.binding.attributedClient != null) {
+ // For SDK sandboxes, use the attributed client (eg the app that
+ // requested the sandbox)
+ client = cr.binding.attributedClient;
+ cstate = client.mState;
+ }
+ if (computeClients) {
+ computeOomAdjLSP(client, cachedAdj, topApp, doingAll, now, cycleReEval, true,
+ oomAdjReason, true);
+ } else {
+ cstate.setCurRawAdj(cstate.getCurAdj());
+ cstate.setCurRawProcState(cstate.getCurProcState());
+ }
+ }
+
+ int clientAdj = cstate.getCurRawAdj();
+ int clientProcState = cstate.getCurRawProcState();
+
+ final boolean clientIsSystem = clientProcState < PROCESS_STATE_TOP;
+
+ int adj = state.getCurRawAdj();
+ int procState = state.getCurRawProcState();
+ int schedGroup = state.getCurrentSchedulingGroup();
+ int capability = state.getCurCapability();
+
+ final int prevRawAdj = adj;
+ final int prevProcState = procState;
+ final int prevSchedGroup = schedGroup;
+
+ final int appUid = app.info.uid;
+ final int logUid = mService.mCurOomAdjUid;
+
+ state.setCurBoundByNonBgRestrictedApp(state.isCurBoundByNonBgRestrictedApp()
+ || cstate.isCurBoundByNonBgRestrictedApp()
+ || clientProcState <= PROCESS_STATE_BOUND_TOP
+ || (clientProcState == PROCESS_STATE_FOREGROUND_SERVICE
+ && !cstate.isBackgroundRestricted()));
+
+ if (client.mOptRecord.shouldNotFreeze()) {
+ // Propagate the shouldNotFreeze flag down the bindings.
+ app.mOptRecord.setShouldNotFreeze(true);
+ }
+
+ boolean trackedProcState = false;
+
+ // We always propagate PROCESS_CAPABILITY_BFSL over bindings here,
+ // but, right before actually setting it to the process,
+ // we check the final procstate, and remove it if the procsate is below BFGS.
+ capability |= getBfslCapabilityFromClient(client);
+
+ if (cr.notHasFlag(Context.BIND_WAIVE_PRIORITY)) {
+ if (cr.hasFlag(Context.BIND_INCLUDE_CAPABILITIES)) {
+ capability |= cstate.getCurCapability();
+ }
+
+ // If an app has network capability by default
+ // (by having procstate <= BFGS), then the apps it binds to will get
+ // elevated to a high enough procstate anyway to get network unless they
+ // request otherwise, so don't propagate the network capability by default
+ // in this case unless they explicitly request it.
+ if ((cstate.getCurCapability()
+ & PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK) != 0) {
+ if (clientProcState <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
+ // This is used to grant network access to Expedited Jobs.
+ if (cr.hasFlag(Context.BIND_BYPASS_POWER_NETWORK_RESTRICTIONS)) {
+ capability |= PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK;
+ }
+ } else {
+ capability |= PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK;
+ }
+ }
+ if ((cstate.getCurCapability()
+ & PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK) != 0) {
+ if (clientProcState <= PROCESS_STATE_IMPORTANT_FOREGROUND) {
+ // This is used to grant network access to User Initiated Jobs.
+ if (cr.hasFlag(Context.BIND_BYPASS_USER_NETWORK_RESTRICTIONS)) {
+ capability |= PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK;
+ }
+ }
+ }
+
+ if (couldRecurse && shouldSkipDueToCycle(app, cstate, procState, adj, cycleReEval)) {
+ return;
+ }
+
+ if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) {
+ // If the other app is cached for any reason, for purposes here
+ // we are going to consider it empty. The specific cached state
+ // doesn't propagate except under certain conditions.
+ clientProcState = PROCESS_STATE_CACHED_EMPTY;
+ }
+ String adjType = null;
+ if (cr.hasFlag(Context.BIND_ALLOW_OOM_MANAGEMENT)) {
+ // Similar to BIND_WAIVE_PRIORITY, keep it unfrozen.
+ if (clientAdj < CACHED_APP_MIN_ADJ) {
+ app.mOptRecord.setShouldNotFreeze(true);
+ }
+ // Not doing bind OOM management, so treat
+ // this guy more like a started service.
+ if (state.hasShownUi() && !state.getCachedIsHomeProcess()) {
+ // If this process has shown some UI, let it immediately
+ // go to the LRU list because it may be pretty heavy with
+ // UI stuff. We'll tag it with a label just to help
+ // debug and understand what is going on.
+ if (adj > clientAdj) {
+ adjType = "cch-bound-ui-services";
+ }
+ state.setCached(false);
+ clientAdj = adj;
+ clientProcState = procState;
+ } else {
+ if (now >= (cr.binding.service.lastActivity
+ + mConstants.MAX_SERVICE_INACTIVITY)) {
+ // This service has not seen activity within
+ // recent memory, so allow it to drop to the
+ // LRU list if there is no other reason to keep
+ // it around. We'll also tag it with a label just
+ // to help debug and undertand what is going on.
+ if (adj > clientAdj) {
+ adjType = "cch-bound-services";
+ }
+ clientAdj = adj;
+ }
+ }
+ }
+ if (adj > clientAdj) {
+ // If this process has recently shown UI, and
+ // the process that is binding to it is less
+ // important than being visible, then we don't
+ // care about the binding as much as we care
+ // about letting this process get into the LRU
+ // list to be killed and restarted if needed for
+ // memory.
+ if (state.hasShownUi() && !state.getCachedIsHomeProcess()
+ && clientAdj > PERCEPTIBLE_APP_ADJ) {
+ if (adj >= CACHED_APP_MIN_ADJ) {
+ adjType = "cch-bound-ui-services";
+ }
+ } else {
+ int newAdj;
+ int lbAdj = VISIBLE_APP_ADJ; // lower bound of adj.
+ if (cr.hasFlag(Context.BIND_ABOVE_CLIENT
+ | Context.BIND_IMPORTANT)) {
+ if (clientAdj >= PERSISTENT_SERVICE_ADJ) {
+ newAdj = clientAdj;
+ } else {
+ // make this service persistent
+ newAdj = PERSISTENT_SERVICE_ADJ;
+ schedGroup = SCHED_GROUP_DEFAULT;
+ procState = ActivityManager.PROCESS_STATE_PERSISTENT;
+ cr.trackProcState(procState, mAdjSeq);
+ trackedProcState = true;
+ }
+ } else if (cr.hasFlag(Context.BIND_NOT_PERCEPTIBLE)
+ && clientAdj <= PERCEPTIBLE_APP_ADJ
+ && adj >= (lbAdj = PERCEPTIBLE_LOW_APP_ADJ)) {
+ newAdj = PERCEPTIBLE_LOW_APP_ADJ;
+ } else if (cr.hasFlag(Context.BIND_ALMOST_PERCEPTIBLE)
+ && cr.notHasFlag(Context.BIND_NOT_FOREGROUND)
+ && clientAdj < PERCEPTIBLE_APP_ADJ
+ && adj >= (lbAdj = PERCEPTIBLE_APP_ADJ)) {
+ // This is for user-initiated jobs.
+ // We use APP_ADJ + 1 here, so we can tell them apart from FGS.
+ newAdj = PERCEPTIBLE_APP_ADJ + 1;
+ } else if (cr.hasFlag(Context.BIND_ALMOST_PERCEPTIBLE)
+ && cr.hasFlag(Context.BIND_NOT_FOREGROUND)
+ && clientAdj < PERCEPTIBLE_APP_ADJ
+ && adj >= (lbAdj = (PERCEPTIBLE_MEDIUM_APP_ADJ + 2))) {
+ // This is for expedited jobs.
+ // We use MEDIUM_APP_ADJ + 2 here, so we can tell apart
+ // EJ and short-FGS.
+ newAdj = PERCEPTIBLE_MEDIUM_APP_ADJ + 2;
+ } else if (cr.hasFlag(Context.BIND_NOT_VISIBLE)
+ && clientAdj < PERCEPTIBLE_APP_ADJ
+ && adj >= (lbAdj = PERCEPTIBLE_APP_ADJ)) {
+ newAdj = PERCEPTIBLE_APP_ADJ;
+ } else if (clientAdj >= PERCEPTIBLE_APP_ADJ) {
+ newAdj = clientAdj;
+ } else if (cr.hasFlag(BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE)
+ && clientAdj <= VISIBLE_APP_ADJ
+ && adj > VISIBLE_APP_ADJ) {
+ newAdj = VISIBLE_APP_ADJ;
+ } else {
+ if (adj > VISIBLE_APP_ADJ) {
+ // TODO: Is this too limiting for apps bound from TOP?
+ newAdj = Math.max(clientAdj, lbAdj);
+ } else {
+ newAdj = adj;
+ }
+ }
+ if (!cstate.isCached()) {
+ state.setCached(false);
+ }
+ if (adj > newAdj) {
+ adj = newAdj;
+ state.setCurRawAdj(adj);
+ adjType = "service";
+ }
+ }
+ }
+ if (cr.notHasFlag(Context.BIND_NOT_FOREGROUND
+ | Context.BIND_IMPORTANT_BACKGROUND)) {
+ // This will treat important bound services identically to
+ // the top app, which may behave differently than generic
+ // foreground work.
+ final int curSchedGroup = cstate.getCurrentSchedulingGroup();
+ if (curSchedGroup > schedGroup) {
+ if (cr.hasFlag(Context.BIND_IMPORTANT)) {
+ schedGroup = curSchedGroup;
+ } else {
+ schedGroup = SCHED_GROUP_DEFAULT;
+ }
+ }
+ if (clientProcState < PROCESS_STATE_TOP) {
+ // Special handling for above-top states (persistent
+ // processes). These should not bring the current process
+ // into the top state, since they are not on top. Instead
+ // give them the best bound state after that.
+ if (cr.hasFlag(BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE)) {
+ clientProcState = PROCESS_STATE_FOREGROUND_SERVICE;
+ } else if (cr.hasFlag(Context.BIND_FOREGROUND_SERVICE)) {
+ clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+ } else if (mService.mWakefulness.get()
+ == PowerManagerInternal.WAKEFULNESS_AWAKE
+ && cr.hasFlag(Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE)) {
+ clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+ } else {
+ clientProcState =
+ PROCESS_STATE_IMPORTANT_FOREGROUND;
+ }
+ } else if (clientProcState == PROCESS_STATE_TOP) {
+ // Go at most to BOUND_TOP, unless requested to elevate
+ // to client's state.
+ clientProcState = PROCESS_STATE_BOUND_TOP;
+ final boolean enabled = cstate.getCachedCompatChange(
+ CACHED_COMPAT_CHANGE_PROCESS_CAPABILITY);
+ if (enabled) {
+ if (cr.hasFlag(Context.BIND_INCLUDE_CAPABILITIES)) {
+ // TOP process passes all capabilities to the service.
+ capability |= cstate.getCurCapability();
+ } else {
+ // TOP process passes no capability to the service.
+ }
+ } else {
+ // TOP process passes all capabilities to the service.
+ capability |= cstate.getCurCapability();
+ }
+ }
+ } else if (cr.notHasFlag(Context.BIND_IMPORTANT_BACKGROUND)) {
+ if (clientProcState < PROCESS_STATE_TRANSIENT_BACKGROUND) {
+ clientProcState =
+ PROCESS_STATE_TRANSIENT_BACKGROUND;
+ }
+ } else {
+ if (clientProcState < PROCESS_STATE_IMPORTANT_BACKGROUND) {
+ clientProcState =
+ PROCESS_STATE_IMPORTANT_BACKGROUND;
+ }
+ }
+
+ if (schedGroup < SCHED_GROUP_TOP_APP
+ && cr.hasFlag(Context.BIND_SCHEDULE_LIKE_TOP_APP)
+ && clientIsSystem) {
+ schedGroup = SCHED_GROUP_TOP_APP;
+ state.setScheduleLikeTopApp(true);
+ }
+
+ if (!trackedProcState) {
+ cr.trackProcState(clientProcState, mAdjSeq);
+ }
+
+ if (procState > clientProcState) {
+ procState = clientProcState;
+ state.setCurRawProcState(procState);
+ if (adjType == null) {
+ adjType = "service";
+ }
+ }
+ if (procState < PROCESS_STATE_IMPORTANT_BACKGROUND
+ && cr.hasFlag(Context.BIND_SHOWING_UI)) {
+ app.setPendingUiClean(true);
+ }
+ if (adjType != null) {
+ state.setAdjType(adjType);
+ state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo
+ .REASON_SERVICE_IN_USE);
+ state.setAdjSource(client);
+ state.setAdjSourceProcState(clientProcState);
+ state.setAdjTarget(cr.binding.service.instanceName);
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to " + adjType
+ + ": " + app + ", due to " + client
+ + " adj=" + adj + " procState="
+ + ProcessList.makeProcStateString(procState));
+ }
+ }
+ } else { // BIND_WAIVE_PRIORITY == true
+ // BIND_WAIVE_PRIORITY bindings are special when it comes to the
+ // freezer. Processes bound via WPRI are expected to be running,
+ // but they are not promoted in the LRU list to keep them out of
+ // cached. As a result, they can freeze based on oom_adj alone.
+ // Normally, bindToDeath would fire when a cached app would die
+ // in the background, but nothing will fire when a running process
+ // pings a frozen process. Accordingly, any cached app that is
+ // bound by an unfrozen app via a WPRI binding has to remain
+ // unfrozen.
+ if (clientAdj < CACHED_APP_MIN_ADJ) {
+ app.mOptRecord.setShouldNotFreeze(true);
+ }
+ }
+ if (cr.hasFlag(Context.BIND_TREAT_LIKE_ACTIVITY)) {
+ app.mServices.setTreatLikeActivity(true);
+ if (clientProcState <= PROCESS_STATE_CACHED_ACTIVITY
+ && procState > PROCESS_STATE_CACHED_ACTIVITY) {
+ // This is a cached process, but somebody wants us to treat it like it has
+ // an activity, okay!
+ procState = PROCESS_STATE_CACHED_ACTIVITY;
+ state.setAdjType("cch-as-act");
+ }
+ }
+ final ActivityServiceConnectionsHolder a = cr.activity;
+ if (cr.hasFlag(Context.BIND_ADJUST_WITH_ACTIVITY)) {
+ if (a != null && adj > FOREGROUND_APP_ADJ
+ && a.isActivityVisible()) {
+ adj = FOREGROUND_APP_ADJ;
+ state.setCurRawAdj(adj);
+ if (cr.notHasFlag(Context.BIND_NOT_FOREGROUND)) {
+ if (cr.hasFlag(Context.BIND_IMPORTANT)) {
+ schedGroup = SCHED_GROUP_TOP_APP_BOUND;
+ } else {
+ schedGroup = SCHED_GROUP_DEFAULT;
+ }
+ }
+ state.setCached(false);
+ state.setAdjType("service");
+ state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo
+ .REASON_SERVICE_IN_USE);
+ state.setAdjSource(a);
+ state.setAdjSourceProcState(procState);
+ state.setAdjTarget(cr.binding.service.instanceName);
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ,
+ "Raise to service w/activity: " + app);
+ }
+ }
+ }
+
+ capability |= getDefaultCapability(app, procState);
+
+ // Procstates below BFGS should never have this capability.
+ if (procState > PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
+ capability &= ~PROCESS_CAPABILITY_BFSL;
+ }
+
+ if (adj < prevRawAdj) {
+ schedGroup = setIntermediateAdjLSP(app, adj, prevRawAdj, schedGroup);
+ }
+ if (procState < prevProcState) {
+ setIntermediateProcStateLSP(app, procState, prevProcState);
+ }
+ if (schedGroup > prevSchedGroup) {
+ setIntermediateSchedGroupLSP(state, schedGroup);
+ }
+ state.setCurCapability(capability);
+
+ state.setEmpty(false);
+ }
+
+ protected void computeProviderHostOomAdjLSP(ContentProviderConnection conn, ProcessRecord app,
+ ProcessRecord client, long now, ProcessRecord topApp, boolean doingAll,
+ boolean cycleReEval, boolean computeClients, int oomAdjReason, int cachedAdj,
+ boolean couldRecurse) {
+ if (app.isPendingFinishAttach()) {
+ // We've set the attaching process state in the computeInitialOomAdjLSP. Skip it here.
+ return;
+ }
+
+ final ProcessStateRecord state = app.mState;
+ final ProcessStateRecord cstate = client.mState;
+
+ if (client == app) {
+ // Being our own client is not interesting.
+ return;
+ }
+ if (couldRecurse) {
+ if (computeClients) {
+ computeOomAdjLSP(client, cachedAdj, topApp, doingAll, now, cycleReEval, true,
+ oomAdjReason, true);
+ } else if (couldRecurse) {
+ cstate.setCurRawAdj(cstate.getCurAdj());
+ cstate.setCurRawProcState(cstate.getCurProcState());
+ }
+
+ if (shouldSkipDueToCycle(app, cstate, state.getCurRawProcState(), state.getCurRawAdj(),
+ cycleReEval)) {
+ return;
+ }
+ }
+
+ int clientAdj = cstate.getCurRawAdj();
+ int clientProcState = cstate.getCurRawProcState();
+
+ int adj = state.getCurRawAdj();
+ int procState = state.getCurRawProcState();
+ int schedGroup = state.getCurrentSchedulingGroup();
+ int capability = state.getCurCapability();
+
+ final int prevRawAdj = adj;
+ final int prevProcState = procState;
+ final int prevSchedGroup = schedGroup;
+
+ final int appUid = app.info.uid;
+ final int logUid = mService.mCurOomAdjUid;
+
+ // We always propagate PROCESS_CAPABILITY_BFSL to providers here,
+ // but, right before actually setting it to the process,
+ // we check the final procstate, and remove it if the procsate is below BFGS.
+ capability |= getBfslCapabilityFromClient(client);
+
+ if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) {
+ // If the other app is cached for any reason, for purposes here
+ // we are going to consider it empty.
+ clientProcState = PROCESS_STATE_CACHED_EMPTY;
+ }
+ if (client.mOptRecord.shouldNotFreeze()) {
+ // Propagate the shouldNotFreeze flag down the bindings.
+ app.mOptRecord.setShouldNotFreeze(true);
+ }
+
+ state.setCurBoundByNonBgRestrictedApp(state.isCurBoundByNonBgRestrictedApp()
+ || cstate.isCurBoundByNonBgRestrictedApp()
+ || clientProcState <= PROCESS_STATE_BOUND_TOP
+ || (clientProcState == PROCESS_STATE_FOREGROUND_SERVICE
+ && !cstate.isBackgroundRestricted()));
+
+ String adjType = null;
+ if (adj > clientAdj) {
+ if (state.hasShownUi() && !state.getCachedIsHomeProcess()
+ && clientAdj > PERCEPTIBLE_APP_ADJ) {
+ adjType = "cch-ui-provider";
+ } else {
+ adj = Math.max(clientAdj, FOREGROUND_APP_ADJ);
+ state.setCurRawAdj(adj);
+ adjType = "provider";
+ }
+ state.setCached(state.isCached() & cstate.isCached());
+ }
+
+ if (clientProcState <= PROCESS_STATE_FOREGROUND_SERVICE) {
+ if (adjType == null) {
+ adjType = "provider";
+ }
+ if (clientProcState == PROCESS_STATE_TOP) {
+ clientProcState = PROCESS_STATE_BOUND_TOP;
+ } else {
+ clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+ }
+ }
+
+ conn.trackProcState(clientProcState, mAdjSeq);
+ if (procState > clientProcState) {
+ procState = clientProcState;
+ state.setCurRawProcState(procState);
+ }
+ if (cstate.getCurrentSchedulingGroup() > schedGroup) {
+ schedGroup = SCHED_GROUP_DEFAULT;
+ }
+ if (adjType != null) {
+ state.setAdjType(adjType);
+ state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo
+ .REASON_PROVIDER_IN_USE);
+ state.setAdjSource(client);
+ state.setAdjSourceProcState(clientProcState);
+ state.setAdjTarget(conn.provider.name);
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to " + adjType
+ + ": " + app + ", due to " + client
+ + " adj=" + adj + " procState="
+ + ProcessList.makeProcStateString(procState));
+ }
+ }
+
+ // Procstates below BFGS should never have this capability.
+ if (procState > PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
+ capability &= ~PROCESS_CAPABILITY_BFSL;
+ }
+
+ if (adj < prevRawAdj) {
+ schedGroup = setIntermediateAdjLSP(app, adj, prevRawAdj, schedGroup);
+ }
+ if (procState < prevProcState) {
+ setIntermediateProcStateLSP(app, procState, prevProcState);
+ }
+ if (schedGroup > prevSchedGroup) {
+ setIntermediateSchedGroupLSP(state, schedGroup);
+ }
+ state.setCurCapability(capability);
+
+ state.setEmpty(false);
+ }
+
+ protected int getDefaultCapability(ProcessRecord app, int procState) {
final int networkCapabilities =
NetworkPolicyManager.getDefaultProcessNetworkCapabilities(procState);
final int baseCapabilities;
@@ -2882,7 +3098,7 @@
/**
* @return the BFSL capability from a client (of a service binding or provider).
*/
- int getBfslCapabilityFromClient(ProcessRecord client) {
+ protected int getBfslCapabilityFromClient(ProcessRecord client) {
// Procstates above FGS should always have this flag. We shouldn't need this logic,
// but let's do it just in case.
if (client.mState.getCurProcState() < PROCESS_STATE_FOREGROUND_SERVICE) {
@@ -2967,7 +3183,7 @@
/** Inform the oomadj observer of changes to oomadj. Used by tests. */
@GuardedBy("mService")
- private void reportOomAdjMessageLocked(String tag, String msg) {
+ protected void reportOomAdjMessageLocked(String tag, String msg) {
Slog.d(tag, msg);
synchronized (mService.mOomAdjObserverLock) {
if (mService.mCurOomAdjObserver != null) {
@@ -2983,7 +3199,7 @@
/** Applies the computed oomadj, procstate and sched group values and freezes them in set* */
@GuardedBy({"mService", "mProcLock"})
- private boolean applyOomAdjLSP(ProcessRecord app, boolean doingAll, long now,
+ protected boolean applyOomAdjLSP(ProcessRecord app, boolean doingAll, long now,
long nowElapsed, @OomAdjReason int oomAdjReson) {
boolean success = true;
final ProcessStateRecord state = app.mState;
@@ -3272,6 +3488,8 @@
int initialCapability = PROCESS_CAPABILITY_NONE;
boolean initialCached = true;
final ProcessStateRecord state = app.mState;
+ final int prevProcState = PROCESS_STATE_UNKNOWN;
+ final int prevAdj = UNKNOWN_ADJ;
// If the process has been marked as foreground, it is starting as the top app (with
// Zygote#START_AS_TOP_APP_ARG), so boost the thread priority of its default UI thread.
if (state.hasForegroundActivities()) {
@@ -3306,6 +3524,9 @@
state.setCurRawAdj(ProcessList.FOREGROUND_APP_ADJ);
state.setForcingToImportant(null);
state.setHasShownUi(false);
+
+ onProcessStateChanged(app, prevProcState);
+ onProcessOomAdjChanged(app, prevAdj);
}
// ONLY used for unit testing in OomAdjusterTests.java
@@ -3553,4 +3774,56 @@
}
processes.clear();
}
+
+ @GuardedBy("mService")
+ void onProcessBeginLocked(@NonNull ProcessRecord app) {
+ // Empty, the OomAdjusterModernImpl will have an implementation.
+ }
+
+ @GuardedBy("mService")
+ void onProcessEndLocked(@NonNull ProcessRecord app) {
+ // Empty, the OomAdjusterModernImpl will have an implementation.
+ }
+
+ /**
+ * Called when the process state is changed outside of the OomAdjuster.
+ */
+ @GuardedBy("mService")
+ void onProcessStateChanged(@NonNull ProcessRecord app, int prevProcState) {
+ // Empty, the OomAdjusterModernImpl will have an implementation.
+ }
+
+ /**
+ * Called when the oom adj is changed outside of the OomAdjuster.
+ */
+ @GuardedBy("mService")
+ void onProcessOomAdjChanged(@NonNull ProcessRecord app, int prevAdj) {
+ // Empty, the OomAdjusterModernImpl will have an implementation.
+ }
+
+ @VisibleForTesting
+ void resetInternal() {
+ // Empty, the OomAdjusterModernImpl will have an implementation.
+ }
+
+ @GuardedBy("mService")
+ protected int getInitialAdj(@NonNull ProcessRecord app) {
+ return app.mState.getCurAdj();
+ }
+
+ @GuardedBy("mService")
+ protected int getInitialProcState(@NonNull ProcessRecord app) {
+ return app.mState.getCurProcState();
+ }
+
+ @GuardedBy("mService")
+ protected int getInitialCapability(@NonNull ProcessRecord app) {
+ return app.mState.getCurCapability();
+ }
+
+ @GuardedBy("mService")
+ protected boolean getInitialIsCurBoundByNonBgRestrictedApp(@NonNull ProcessRecord app) {
+ // The caller will set the initial value in this implementation.
+ return app.mState.isCurBoundByNonBgRestrictedApp();
+ }
}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.md b/services/core/java/com/android/server/am/OomAdjuster.md
index 16091d1..da5e12e 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.md
+++ b/services/core/java/com/android/server/am/OomAdjuster.md
@@ -130,3 +130,28 @@
* Iterate the processes from least important to most important ones.
* A maximum retries of 10 is enforced, while in practice, the maximum retries could reach only 2 to 3.
+## The Modern Implementation
+
+As aforementioned, the OomAdjuster makes the computation in a recursive way, while this is inefficient in dealing with the cycles. The overall code complexity should be around **O((1 + num(retries)) * num(procs) * num(binding connections))**. In addition, depending on the ordering of the input, the algorithm may produce different results and sometimes it's wrong.
+
+The new "Modern Implementation" is based on the rationale that, apps can't promote the service/provider it connects to, to a higher bucket than itself. We are introducing a bucket based, breadth first search algorithm, as illustrated below:
+
+```
+for all processes in the process list
+ compute the state of each process, but, excluding its clients
+ put each process to the corresponding bucket according to the state value
+done
+
+for each bucket, starting from the top most to the bottom most
+ for each process in the bucket
+ for each process it binds to
+ if the state of the bindee process could be elevated because of the binding; then
+ move the bindee process to the higher bucket
+ fi
+ done
+ done
+done
+```
+
+The overall code complexity should be around **O(num(procs) * num(binding connections))**, which saves the retry time from the existing algorithm.
+
diff --git a/services/core/java/com/android/server/am/OomAdjusterModernImpl.java b/services/core/java/com/android/server/am/OomAdjusterModernImpl.java
new file mode 100644
index 0000000..b852ef5
--- /dev/null
+++ b/services/core/java/com/android/server/am/OomAdjusterModernImpl.java
@@ -0,0 +1,1125 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import static android.app.ActivityManager.PROCESS_STATE_BACKUP;
+import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP;
+import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
+import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT;
+import static android.app.ActivityManager.PROCESS_STATE_CACHED_EMPTY;
+import static android.app.ActivityManager.PROCESS_STATE_CACHED_RECENT;
+import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
+import static android.app.ActivityManager.PROCESS_STATE_HEAVY_WEIGHT;
+import static android.app.ActivityManager.PROCESS_STATE_HOME;
+import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
+import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
+import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT;
+import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT_UI;
+import static android.app.ActivityManager.PROCESS_STATE_RECEIVER;
+import static android.app.ActivityManager.PROCESS_STATE_SERVICE;
+import static android.app.ActivityManager.PROCESS_STATE_TOP;
+import static android.app.ActivityManager.PROCESS_STATE_TOP_SLEEPING;
+import static android.app.ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
+import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN;
+
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS;
+import static com.android.server.am.ActivityManagerService.TAG_UID_OBSERVERS;
+import static com.android.server.am.ProcessList.BACKUP_APP_ADJ;
+import static com.android.server.am.ProcessList.CACHED_APP_MIN_ADJ;
+import static com.android.server.am.ProcessList.FOREGROUND_APP_ADJ;
+import static com.android.server.am.ProcessList.HEAVY_WEIGHT_APP_ADJ;
+import static com.android.server.am.ProcessList.HOME_APP_ADJ;
+import static com.android.server.am.ProcessList.NATIVE_ADJ;
+import static com.android.server.am.ProcessList.PERCEPTIBLE_APP_ADJ;
+import static com.android.server.am.ProcessList.PERCEPTIBLE_LOW_APP_ADJ;
+import static com.android.server.am.ProcessList.PERCEPTIBLE_MEDIUM_APP_ADJ;
+import static com.android.server.am.ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ;
+import static com.android.server.am.ProcessList.PERSISTENT_PROC_ADJ;
+import static com.android.server.am.ProcessList.PERSISTENT_SERVICE_ADJ;
+import static com.android.server.am.ProcessList.PREVIOUS_APP_ADJ;
+import static com.android.server.am.ProcessList.SCHED_GROUP_BACKGROUND;
+import static com.android.server.am.ProcessList.SERVICE_ADJ;
+import static com.android.server.am.ProcessList.SERVICE_B_ADJ;
+import static com.android.server.am.ProcessList.SYSTEM_ADJ;
+import static com.android.server.am.ProcessList.UNKNOWN_ADJ;
+import static com.android.server.am.ProcessList.VISIBLE_APP_ADJ;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.ActivityManagerInternal.OomAdjReason;
+import android.content.pm.ServiceInfo;
+import android.os.IBinder;
+import android.os.SystemClock;
+import android.os.Trace;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.ServiceThread;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.function.Consumer;
+
+/**
+ * A modern implementation of the oom adjuster.
+ */
+public class OomAdjusterModernImpl extends OomAdjuster {
+ static final String TAG = "OomAdjusterModernImpl";
+
+ // The ADJ_SLOT_INVALID is NOT an actual slot.
+ static final int ADJ_SLOT_INVALID = -1;
+ static final int ADJ_SLOT_NATIVE = 0;
+ static final int ADJ_SLOT_SYSTEM = 1;
+ static final int ADJ_SLOT_PERSISTENT_PROC = 2;
+ static final int ADJ_SLOT_PERSISTENT_SERVICE = 3;
+ static final int ADJ_SLOT_FOREGROUND_APP = 4;
+ static final int ADJ_SLOT_PERCEPTIBLE_RECENT_FOREGROUND_APP = 5;
+ static final int ADJ_SLOT_VISIBLE_APP = 6;
+ static final int ADJ_SLOT_PERCEPTIBLE_APP = 7;
+ static final int ADJ_SLOT_PERCEPTIBLE_MEDIUM_APP = 8;
+ static final int ADJ_SLOT_PERCEPTIBLE_LOW_APP = 9;
+ static final int ADJ_SLOT_BACKUP_APP = 10;
+ static final int ADJ_SLOT_HEAVY_WEIGHT_APP = 11;
+ static final int ADJ_SLOT_SERVICE = 12;
+ static final int ADJ_SLOT_HOME_APP = 13;
+ static final int ADJ_SLOT_PREVIOUS_APP = 14;
+ static final int ADJ_SLOT_SERVICE_B = 15;
+ static final int ADJ_SLOT_CACHED_APP = 16;
+ static final int ADJ_SLOT_UNKNOWN = 17;
+
+ @IntDef(prefix = { "ADJ_SLOT_" }, value = {
+ ADJ_SLOT_INVALID,
+ ADJ_SLOT_NATIVE,
+ ADJ_SLOT_SYSTEM,
+ ADJ_SLOT_PERSISTENT_PROC,
+ ADJ_SLOT_PERSISTENT_SERVICE,
+ ADJ_SLOT_FOREGROUND_APP,
+ ADJ_SLOT_PERCEPTIBLE_RECENT_FOREGROUND_APP,
+ ADJ_SLOT_VISIBLE_APP,
+ ADJ_SLOT_PERCEPTIBLE_APP,
+ ADJ_SLOT_PERCEPTIBLE_MEDIUM_APP,
+ ADJ_SLOT_PERCEPTIBLE_LOW_APP,
+ ADJ_SLOT_BACKUP_APP,
+ ADJ_SLOT_HEAVY_WEIGHT_APP,
+ ADJ_SLOT_SERVICE,
+ ADJ_SLOT_HOME_APP,
+ ADJ_SLOT_PREVIOUS_APP,
+ ADJ_SLOT_SERVICE_B,
+ ADJ_SLOT_CACHED_APP,
+ ADJ_SLOT_UNKNOWN,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface AdjSlot{}
+
+ static final int[] ADJ_SLOT_VALUES = new int[] {
+ NATIVE_ADJ,
+ SYSTEM_ADJ,
+ PERSISTENT_PROC_ADJ,
+ PERSISTENT_SERVICE_ADJ,
+ FOREGROUND_APP_ADJ,
+ PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ,
+ VISIBLE_APP_ADJ,
+ PERCEPTIBLE_APP_ADJ,
+ PERCEPTIBLE_MEDIUM_APP_ADJ,
+ PERCEPTIBLE_LOW_APP_ADJ,
+ BACKUP_APP_ADJ,
+ HEAVY_WEIGHT_APP_ADJ,
+ SERVICE_ADJ,
+ HOME_APP_ADJ,
+ PREVIOUS_APP_ADJ,
+ SERVICE_B_ADJ,
+ CACHED_APP_MIN_ADJ,
+ UNKNOWN_ADJ,
+ };
+
+ /**
+ * Note: Always use the raw adj to call this API.
+ */
+ static @AdjSlot int adjToSlot(int adj) {
+ if (adj >= ADJ_SLOT_VALUES[0] && adj <= ADJ_SLOT_VALUES[ADJ_SLOT_VALUES.length - 1]) {
+ // Conduct a binary search, in most of the cases it'll get a hit.
+ final int index = Arrays.binarySearch(ADJ_SLOT_VALUES, adj);
+ if (index >= 0) {
+ return index;
+ }
+ // If not found, the returned index above should be (-(insertion point) - 1),
+ // let's return the first slot that's less than the adj value.
+ return -(index + 1) - 1;
+ }
+ return ADJ_SLOT_VALUES.length - 1;
+ }
+
+ static final int[] PROC_STATE_SLOTS = new int[] {
+ PROCESS_STATE_PERSISTENT, // 0
+ PROCESS_STATE_PERSISTENT_UI,
+ PROCESS_STATE_TOP,
+ PROCESS_STATE_BOUND_TOP,
+ PROCESS_STATE_FOREGROUND_SERVICE,
+ PROCESS_STATE_BOUND_FOREGROUND_SERVICE,
+ PROCESS_STATE_IMPORTANT_FOREGROUND,
+ PROCESS_STATE_IMPORTANT_BACKGROUND,
+ PROCESS_STATE_TRANSIENT_BACKGROUND,
+ PROCESS_STATE_BACKUP,
+ PROCESS_STATE_SERVICE,
+ PROCESS_STATE_RECEIVER,
+ PROCESS_STATE_TOP_SLEEPING,
+ PROCESS_STATE_HEAVY_WEIGHT,
+ PROCESS_STATE_HOME,
+ PROCESS_STATE_LAST_ACTIVITY,
+ PROCESS_STATE_CACHED_ACTIVITY,
+ PROCESS_STATE_CACHED_ACTIVITY_CLIENT,
+ PROCESS_STATE_CACHED_RECENT,
+ PROCESS_STATE_CACHED_EMPTY,
+ PROCESS_STATE_UNKNOWN, // -1
+ };
+
+ static int processStateToSlot(@ActivityManager.ProcessState int state) {
+ if (state >= PROCESS_STATE_PERSISTENT && state <= PROCESS_STATE_CACHED_EMPTY) {
+ return state;
+ }
+ return PROC_STATE_SLOTS.length - 1;
+ }
+
+ /**
+ * A container node in the {@link LinkedProcessRecordList},
+ * holding the references to {@link ProcessRecord}.
+ */
+ static class ProcessRecordNode {
+ static final int NODE_TYPE_PROC_STATE = 0;
+ static final int NODE_TYPE_ADJ = 1;
+
+ @IntDef(prefix = { "NODE_TYPE_" }, value = {
+ NODE_TYPE_PROC_STATE,
+ NODE_TYPE_ADJ,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface NodeType {}
+
+ static final int NUM_NODE_TYPE = NODE_TYPE_ADJ + 1;
+
+ @Nullable ProcessRecordNode mPrev;
+ @Nullable ProcessRecordNode mNext;
+ final @Nullable ProcessRecord mApp;
+
+ ProcessRecordNode(@Nullable ProcessRecord app) {
+ mApp = app;
+ }
+
+ void unlink() {
+ if (mPrev != null) {
+ mPrev.mNext = mNext;
+ }
+ if (mNext != null) {
+ mNext.mPrev = mPrev;
+ }
+ mPrev = mNext = null;
+ }
+
+ boolean isLinked() {
+ return mPrev != null && mNext != null;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("ProcessRecordNode{");
+ sb.append(Integer.toHexString(System.identityHashCode(this)));
+ sb.append(' ');
+ sb.append(mApp);
+ sb.append(' ');
+ sb.append(mApp != null ? mApp.mState.getCurProcState() : PROCESS_STATE_UNKNOWN);
+ sb.append(' ');
+ sb.append(mApp != null ? mApp.mState.getCurAdj() : UNKNOWN_ADJ);
+ sb.append(' ');
+ sb.append(Integer.toHexString(System.identityHashCode(mPrev)));
+ sb.append(' ');
+ sb.append(Integer.toHexString(System.identityHashCode(mNext)));
+ sb.append('}');
+ return sb.toString();
+ }
+ }
+
+ private class ProcessRecordNodes {
+ private final @ProcessRecordNode.NodeType int mType;
+
+ private final LinkedProcessRecordList[] mProcessRecordNodes;
+ // The last node besides the tail.
+ private final ProcessRecordNode[] mLastNode;
+
+ ProcessRecordNodes(@ProcessRecordNode.NodeType int type, int size) {
+ mType = type;
+ mProcessRecordNodes = new LinkedProcessRecordList[size];
+ for (int i = 0; i < size; i++) {
+ mProcessRecordNodes[i] = new LinkedProcessRecordList(type);
+ }
+ mLastNode = new ProcessRecordNode[size];
+ }
+
+ int size() {
+ return mProcessRecordNodes.length;
+ }
+
+ @VisibleForTesting
+ void reset() {
+ for (int i = 0; i < mProcessRecordNodes.length; i++) {
+ mProcessRecordNodes[i].reset();
+ mLastNode[i] = null;
+ }
+ }
+
+ void resetLastNodes() {
+ for (int i = 0; i < mProcessRecordNodes.length; i++) {
+ mLastNode[i] = mProcessRecordNodes[i].getLastNodeBeforeTail();
+ }
+ }
+
+ void setLastNodeToHead(int slot) {
+ mLastNode[slot] = mProcessRecordNodes[slot].HEAD;
+ }
+
+ void forEachNewNode(int slot, @NonNull Consumer<OomAdjusterArgs> callback) {
+ ProcessRecordNode node = mLastNode[slot].mNext;
+ final ProcessRecordNode tail = mProcessRecordNodes[slot].TAIL;
+ while (node != tail) {
+ mTmpOomAdjusterArgs.mApp = node.mApp;
+ // Save the next before calling callback, since that may change the node.mNext.
+ final ProcessRecordNode next = node.mNext;
+ callback.accept(mTmpOomAdjusterArgs);
+ // There are couple of cases:
+ // a) The current node is moved to another slot
+ // - for this case, we'd need to keep using the "next" node.
+ // b) There are one or more new nodes being appended to this slot
+ // - for this case, we'd need to make sure we scan the new node too.
+ // Based on the assumption that case a) is only possible with
+ // the computeInitialOomAdjLSP(), where the movings are for single node only,
+ // we may safely assume that, if the "next" used to be the "tail" here, and it's
+ // now a new tail somewhere else, that's case a); otherwise, it's case b);
+ node = next == tail && node.mNext != null && node.mNext.mNext != null
+ ? node.mNext : next;
+ }
+ }
+
+ int getNumberOfSlots() {
+ return mProcessRecordNodes.length;
+ }
+
+ void moveAppTo(@NonNull ProcessRecord app, int prevSlot, int newSlot) {
+ final ProcessRecordNode node = app.mLinkedNodes[mType];
+ if (prevSlot != ADJ_SLOT_INVALID) {
+ if (mLastNode[prevSlot] == node) {
+ mLastNode[prevSlot] = node.mPrev;
+ }
+ node.unlink();
+ }
+ mProcessRecordNodes[newSlot].append(node);
+ }
+
+ void moveAllNodesTo(int fromSlot, int toSlot) {
+ final LinkedProcessRecordList fromList = mProcessRecordNodes[fromSlot];
+ final LinkedProcessRecordList toList = mProcessRecordNodes[toSlot];
+ if (fromSlot != toSlot && fromList.HEAD.mNext != fromList.TAIL) {
+ fromList.moveTo(toList);
+ mLastNode[fromSlot] = fromList.getLastNodeBeforeTail();
+ }
+ }
+
+ void moveAppToTail(ProcessRecord app) {
+ final ProcessRecordNode node = app.mLinkedNodes[mType];
+ int slot;
+ switch (mType) {
+ case ProcessRecordNode.NODE_TYPE_PROC_STATE:
+ slot = processStateToSlot(app.mState.getCurProcState());
+ if (mLastNode[slot] == node) {
+ mLastNode[slot] = node.mPrev;
+ }
+ mProcessRecordNodes[slot].moveNodeToTail(node);
+ break;
+ case ProcessRecordNode.NODE_TYPE_ADJ:
+ slot = adjToSlot(app.mState.getCurRawAdj());
+ if (mLastNode[slot] == node) {
+ mLastNode[slot] = node.mPrev;
+ }
+ mProcessRecordNodes[slot].moveNodeToTail(node);
+ break;
+ default:
+ return;
+ }
+
+ }
+
+ void reset(int slot) {
+ mProcessRecordNodes[slot].reset();
+ }
+
+ void unlink(@NonNull ProcessRecord app) {
+ final ProcessRecordNode node = app.mLinkedNodes[mType];
+ final int slot = getCurrentSlot(app);
+ if (slot != ADJ_SLOT_INVALID) {
+ if (mLastNode[slot] == node) {
+ mLastNode[slot] = node.mPrev;
+ }
+ }
+ node.unlink();
+ }
+
+ void append(@NonNull ProcessRecord app) {
+ append(app, getCurrentSlot(app));
+ }
+
+ void append(@NonNull ProcessRecord app, int targetSlot) {
+ final ProcessRecordNode node = app.mLinkedNodes[mType];
+ mProcessRecordNodes[targetSlot].append(node);
+ }
+
+ private int getCurrentSlot(@NonNull ProcessRecord app) {
+ switch (mType) {
+ case ProcessRecordNode.NODE_TYPE_PROC_STATE:
+ return processStateToSlot(app.mState.getCurProcState());
+ case ProcessRecordNode.NODE_TYPE_ADJ:
+ return adjToSlot(app.mState.getCurRawAdj());
+ }
+ return ADJ_SLOT_INVALID;
+ }
+
+ String toString(int slot, int logUid) {
+ return "lastNode=" + mLastNode[slot] + " " + mProcessRecordNodes[slot].toString(logUid);
+ }
+
+ /**
+ * A simple version of {@link java.util.LinkedList}, as here we don't allocate new node
+ * while adding an object to it.
+ */
+ private static class LinkedProcessRecordList {
+ // Sentinel head/tail, to make bookkeeping work easier.
+ final ProcessRecordNode HEAD = new ProcessRecordNode(null);
+ final ProcessRecordNode TAIL = new ProcessRecordNode(null);
+ final @ProcessRecordNode.NodeType int mNodeType;
+
+ LinkedProcessRecordList(@ProcessRecordNode.NodeType int nodeType) {
+ HEAD.mNext = TAIL;
+ TAIL.mPrev = HEAD;
+ mNodeType = nodeType;
+ }
+
+ void append(@NonNull ProcessRecordNode node) {
+ node.mNext = TAIL;
+ node.mPrev = TAIL.mPrev;
+ TAIL.mPrev.mNext = node;
+ TAIL.mPrev = node;
+ }
+
+ void moveTo(@NonNull LinkedProcessRecordList toList) {
+ if (HEAD.mNext != TAIL) {
+ toList.TAIL.mPrev.mNext = HEAD.mNext;
+ HEAD.mNext.mPrev = toList.TAIL.mPrev;
+ toList.TAIL.mPrev = TAIL.mPrev;
+ TAIL.mPrev.mNext = toList.TAIL;
+ HEAD.mNext = TAIL;
+ TAIL.mPrev = HEAD;
+ }
+ }
+
+ void moveNodeToTail(@NonNull ProcessRecordNode node) {
+ node.unlink();
+ append(node);
+ }
+
+ @NonNull ProcessRecordNode getLastNodeBeforeTail() {
+ return TAIL.mPrev;
+ }
+
+ @VisibleForTesting
+ void reset() {
+ HEAD.mNext = TAIL;
+ TAIL.mPrev = HEAD;
+ }
+
+ String toString(int logUid) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("LinkedProcessRecordList{");
+ sb.append(HEAD);
+ sb.append(' ');
+ sb.append(TAIL);
+ sb.append('[');
+ ProcessRecordNode node = HEAD.mNext;
+ while (node != TAIL) {
+ if (node.mApp != null && node.mApp.uid == logUid) {
+ sb.append(node);
+ sb.append(',');
+ }
+ node = node.mNext;
+ }
+ sb.append(']');
+ sb.append('}');
+ return sb.toString();
+ }
+ }
+ }
+
+ /**
+ * A data class for holding the parameters in computing oom adj.
+ */
+ private class OomAdjusterArgs {
+ ProcessRecord mApp;
+ ProcessRecord mTopApp;
+ long mNow;
+ int mCachedAdj;
+ @OomAdjReason int mOomAdjReason;
+ @NonNull ActiveUids mUids;
+ boolean mFullUpdate;
+
+ void update(ProcessRecord topApp, long now, int cachedAdj,
+ @OomAdjReason int oomAdjReason, @NonNull ActiveUids uids, boolean fullUpdate) {
+ mTopApp = topApp;
+ mNow = now;
+ mCachedAdj = cachedAdj;
+ mOomAdjReason = oomAdjReason;
+ mUids = uids;
+ mFullUpdate = fullUpdate;
+ }
+ }
+
+ OomAdjusterModernImpl(ActivityManagerService service, ProcessList processList,
+ ActiveUids activeUids) {
+ this(service, processList, activeUids, createAdjusterThread());
+ }
+
+ OomAdjusterModernImpl(ActivityManagerService service, ProcessList processList,
+ ActiveUids activeUids, ServiceThread adjusterThread) {
+ super(service, processList, activeUids, adjusterThread);
+ }
+
+ private final ProcessRecordNodes mProcessRecordProcStateNodes = new ProcessRecordNodes(
+ ProcessRecordNode.NODE_TYPE_PROC_STATE, PROC_STATE_SLOTS.length);
+ private final ProcessRecordNodes mProcessRecordAdjNodes = new ProcessRecordNodes(
+ ProcessRecordNode.NODE_TYPE_ADJ, ADJ_SLOT_VALUES.length);
+ private final OomAdjusterArgs mTmpOomAdjusterArgs = new OomAdjusterArgs();
+
+ void linkProcessRecordToList(@NonNull ProcessRecord app) {
+ mProcessRecordProcStateNodes.append(app);
+ mProcessRecordAdjNodes.append(app);
+ }
+
+ void unlinkProcessRecordFromList(@NonNull ProcessRecord app) {
+ mProcessRecordProcStateNodes.unlink(app);
+ mProcessRecordAdjNodes.unlink(app);
+ }
+
+ @Override
+ @VisibleForTesting
+ void resetInternal() {
+ mProcessRecordProcStateNodes.reset();
+ mProcessRecordAdjNodes.reset();
+ }
+
+ @GuardedBy("mService")
+ @Override
+ void onProcessBeginLocked(@NonNull ProcessRecord app) {
+ // Check one type should be good enough.
+ if (app.mLinkedNodes[ProcessRecordNode.NODE_TYPE_PROC_STATE] == null) {
+ for (int i = 0; i < app.mLinkedNodes.length; i++) {
+ app.mLinkedNodes[i] = new ProcessRecordNode(app);
+ }
+ }
+ if (!app.mLinkedNodes[ProcessRecordNode.NODE_TYPE_PROC_STATE].isLinked()) {
+ linkProcessRecordToList(app);
+ }
+ }
+
+ @GuardedBy("mService")
+ @Override
+ void onProcessEndLocked(@NonNull ProcessRecord app) {
+ if (app.mLinkedNodes[ProcessRecordNode.NODE_TYPE_PROC_STATE] != null
+ && app.mLinkedNodes[ProcessRecordNode.NODE_TYPE_PROC_STATE].isLinked()) {
+ unlinkProcessRecordFromList(app);
+ }
+ }
+
+ @GuardedBy("mService")
+ @Override
+ void onProcessStateChanged(@NonNull ProcessRecord app, int prevProcState) {
+ updateProcStateSlotIfNecessary(app, prevProcState);
+ }
+
+ @GuardedBy("mService")
+ void onProcessOomAdjChanged(@NonNull ProcessRecord app, int prevAdj) {
+ updateAdjSlotIfNecessary(app, prevAdj);
+ }
+
+ @GuardedBy("mService")
+ @Override
+ protected int getInitialAdj(@NonNull ProcessRecord app) {
+ return UNKNOWN_ADJ;
+ }
+
+ @GuardedBy("mService")
+ @Override
+ protected int getInitialProcState(@NonNull ProcessRecord app) {
+ return PROCESS_STATE_UNKNOWN;
+ }
+
+ @GuardedBy("mService")
+ @Override
+ protected int getInitialCapability(@NonNull ProcessRecord app) {
+ return 0;
+ }
+
+ @GuardedBy("mService")
+ @Override
+ protected boolean getInitialIsCurBoundByNonBgRestrictedApp(@NonNull ProcessRecord app) {
+ return false;
+ }
+
+ private void updateAdjSlotIfNecessary(ProcessRecord app, int prevRawAdj) {
+ if (app.mState.getCurRawAdj() != prevRawAdj) {
+ final int slot = adjToSlot(app.mState.getCurRawAdj());
+ final int prevSlot = adjToSlot(prevRawAdj);
+ if (slot != prevSlot && slot != ADJ_SLOT_INVALID) {
+ mProcessRecordAdjNodes.moveAppTo(app, prevSlot, slot);
+ }
+ }
+ }
+
+ private void updateProcStateSlotIfNecessary(ProcessRecord app, int prevProcState) {
+ if (app.mState.getCurProcState() != prevProcState) {
+ final int slot = processStateToSlot(app.mState.getCurProcState());
+ final int prevSlot = processStateToSlot(prevProcState);
+ if (slot != prevSlot) {
+ mProcessRecordProcStateNodes.moveAppTo(app, prevSlot, slot);
+ }
+ }
+ }
+
+ @Override
+ protected boolean performUpdateOomAdjLSP(ProcessRecord app, @OomAdjReason int oomAdjReason) {
+ final ProcessRecord topApp = mService.getTopApp();
+
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, oomAdjReasonToString(oomAdjReason));
+ mService.mOomAdjProfiler.oomAdjStarted();
+ mAdjSeq++;
+
+ final ProcessStateRecord state = app.mState;
+ final int oldAdj = state.getCurRawAdj();
+ final int cachedAdj = oldAdj >= CACHED_APP_MIN_ADJ
+ ? oldAdj : UNKNOWN_ADJ;
+
+ final ActiveUids uids = mTmpUidRecords;
+ final ArraySet<ProcessRecord> targetProcesses = mTmpProcessSet;
+ final ArrayList<ProcessRecord> reachableProcesses = mTmpProcessList;
+ final long now = SystemClock.uptimeMillis();
+ final long nowElapsed = SystemClock.elapsedRealtime();
+
+ uids.clear();
+ targetProcesses.clear();
+ targetProcesses.add(app);
+ reachableProcesses.clear();
+
+ // Find out all reachable processes from this app.
+ collectReachableProcessesLocked(targetProcesses, reachableProcesses, uids);
+
+ // Copy all of the reachable processes into the target process set.
+ targetProcesses.addAll(reachableProcesses);
+ reachableProcesses.clear();
+
+ final boolean result = performNewUpdateOomAdjLSP(oomAdjReason,
+ topApp, targetProcesses, uids, false, now, cachedAdj);
+
+ reachableProcesses.addAll(targetProcesses);
+ assignCachedAdjIfNecessary(reachableProcesses);
+ for (int i = uids.size() - 1; i >= 0; i--) {
+ final UidRecord uidRec = uids.valueAt(i);
+ uidRec.forEachProcess(this::updateAppUidRecIfNecessaryLSP);
+ }
+ updateUidsLSP(uids, nowElapsed);
+ for (int i = 0, size = targetProcesses.size(); i < size; i++) {
+ applyOomAdjLSP(targetProcesses.valueAt(i), false, now, nowElapsed, oomAdjReason);
+ }
+ targetProcesses.clear();
+ reachableProcesses.clear();
+
+ mService.mOomAdjProfiler.oomAdjEnded();
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+ return result;
+ }
+
+ @GuardedBy({"mService", "mProcLock"})
+ @Override
+ protected void updateOomAdjInnerLSP(@OomAdjReason int oomAdjReason, final ProcessRecord topApp,
+ ArrayList<ProcessRecord> processes, ActiveUids uids, boolean potentialCycles,
+ boolean startProfiling) {
+ final boolean fullUpdate = processes == null;
+ final ArrayList<ProcessRecord> activeProcesses = fullUpdate
+ ? mProcessList.getLruProcessesLOSP() : processes;
+ ActiveUids activeUids = uids;
+ if (activeUids == null) {
+ final int numUids = mActiveUids.size();
+ activeUids = mTmpUidRecords;
+ activeUids.clear();
+ for (int i = 0; i < numUids; i++) {
+ UidRecord uidRec = mActiveUids.valueAt(i);
+ activeUids.put(uidRec.getUid(), uidRec);
+ }
+ }
+
+ if (startProfiling) {
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, oomAdjReasonToString(oomAdjReason));
+ mService.mOomAdjProfiler.oomAdjStarted();
+ }
+ final long now = SystemClock.uptimeMillis();
+ final long nowElapsed = SystemClock.elapsedRealtime();
+ final long oldTime = now - mConstants.mMaxEmptyTimeMillis;
+ final int numProc = activeProcesses.size();
+
+ mAdjSeq++;
+ if (fullUpdate) {
+ mNewNumServiceProcs = 0;
+ mNewNumAServiceProcs = 0;
+ }
+
+ final ArraySet<ProcessRecord> targetProcesses = mTmpProcessSet;
+ targetProcesses.clear();
+ if (!fullUpdate) {
+ targetProcesses.addAll(activeProcesses);
+ }
+
+ performNewUpdateOomAdjLSP(oomAdjReason, topApp, targetProcesses, activeUids,
+ fullUpdate, now, UNKNOWN_ADJ);
+
+ if (fullUpdate) {
+ assignCachedAdjIfNecessary(mProcessList.getLruProcessesLOSP());
+ postUpdateOomAdjInnerLSP(oomAdjReason, activeUids, now, nowElapsed, oldTime);
+ } else {
+ activeProcesses.clear();
+ activeProcesses.addAll(targetProcesses);
+ assignCachedAdjIfNecessary(activeProcesses);
+
+ for (int i = activeUids.size() - 1; i >= 0; i--) {
+ final UidRecord uidRec = activeUids.valueAt(i);
+ uidRec.forEachProcess(this::updateAppUidRecIfNecessaryLSP);
+ }
+ updateUidsLSP(activeUids, nowElapsed);
+
+ for (int i = 0, size = targetProcesses.size(); i < size; i++) {
+ applyOomAdjLSP(targetProcesses.valueAt(i), false, now, nowElapsed, oomAdjReason);
+ }
+
+ activeProcesses.clear();
+ }
+ targetProcesses.clear();
+
+ if (startProfiling) {
+ mService.mOomAdjProfiler.oomAdjEnded();
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+ }
+ return;
+ }
+
+ /**
+ * Perform the oom adj update on the given {@code targetProcesses}.
+ *
+ * <p>Note: The expectation to the given {@code targetProcesses} is, the caller
+ * must have called {@link collectReachableProcessesLocked} on it.
+ */
+ private boolean performNewUpdateOomAdjLSP(@OomAdjReason int oomAdjReason,
+ ProcessRecord topApp, ArraySet<ProcessRecord> targetProcesses, ActiveUids uids,
+ boolean fullUpdate, long now, int cachedAdj) {
+
+ final ArrayList<ProcessRecord> clientProcesses = mTmpProcessList2;
+ clientProcesses.clear();
+
+ // We'll need to collect the upstream processes of the target apps here, because those
+ // processes would potentially impact the procstate/adj via bindings.
+ if (!fullUpdate) {
+ final boolean containsCycle = collectReversedReachableProcessesLocked(targetProcesses,
+ clientProcesses);
+
+ // If any of its upstream processes are in a cycle,
+ // move them into the candidate targets.
+ if (containsCycle) {
+ // Add all client apps to the target process list.
+ for (int i = 0, size = clientProcesses.size(); i < size; i++) {
+ final ProcessRecord client = clientProcesses.get(i);
+ final UidRecord uidRec = client.getUidRecord();
+ targetProcesses.add(client);
+ if (uidRec != null) {
+ uids.put(uidRec.getUid(), uidRec);
+ }
+ }
+ clientProcesses.clear();
+ }
+ for (int i = 0, size = targetProcesses.size(); i < size; i++) {
+ final ProcessRecord app = targetProcesses.valueAt(i);
+ app.mState.resetCachedInfo();
+ final UidRecord uidRec = app.getUidRecord();
+ if (uidRec != null) {
+ if (DEBUG_UID_OBSERVERS) {
+ Slog.i(TAG_UID_OBSERVERS, "Starting update of " + uidRec);
+ }
+ uidRec.reset();
+ }
+ }
+ } else {
+ final ArrayList<ProcessRecord> lru = mProcessList.getLruProcessesLOSP();
+ for (int i = 0, size = lru.size(); i < size; i++) {
+ final ProcessRecord app = lru.get(i);
+ app.mState.resetCachedInfo();
+ final UidRecord uidRec = app.getUidRecord();
+ if (uidRec != null) {
+ if (DEBUG_UID_OBSERVERS) {
+ Slog.i(TAG_UID_OBSERVERS, "Starting update of " + uidRec);
+ }
+ uidRec.reset();
+ }
+ }
+ }
+
+ updateNewOomAdjInnerLSP(oomAdjReason, topApp, targetProcesses, clientProcesses, uids,
+ cachedAdj, now, fullUpdate);
+
+ clientProcesses.clear();
+
+ return true;
+ }
+
+ /**
+ * Collect the reversed reachable processes from the given {@code apps}, the result will be
+ * returned in the given {@code processes}, which will <em>NOT</em> include the processes from
+ * the given {@code apps}.
+ */
+ @GuardedBy("mService")
+ private boolean collectReversedReachableProcessesLocked(ArraySet<ProcessRecord> apps,
+ ArrayList<ProcessRecord> clientProcesses) {
+ final ArrayDeque<ProcessRecord> queue = mTmpQueue;
+ queue.clear();
+ clientProcesses.clear();
+ for (int i = 0, size = apps.size(); i < size; i++) {
+ final ProcessRecord app = apps.valueAt(i);
+ app.mState.setReachable(true);
+ app.mState.setReversedReachable(true);
+ queue.offer(app);
+ }
+
+ // Track if any of them reachables could include a cycle
+ boolean containsCycle = false;
+
+ // Scan upstreams of the process record
+ for (ProcessRecord pr = queue.poll(); pr != null; pr = queue.poll()) {
+ if (!pr.mState.isReachable()) {
+ // If not in the given initial set of apps, add it.
+ clientProcesses.add(pr);
+ }
+ final ProcessServiceRecord psr = pr.mServices;
+ for (int i = psr.numberOfRunningServices() - 1; i >= 0; i--) {
+ final ServiceRecord s = psr.getRunningServiceAt(i);
+ final ArrayMap<IBinder, ArrayList<ConnectionRecord>> serviceConnections =
+ s.getConnections();
+ for (int j = serviceConnections.size() - 1; j >= 0; j--) {
+ final ArrayList<ConnectionRecord> clist = serviceConnections.valueAt(j);
+ for (int k = clist.size() - 1; k >= 0; k--) {
+ final ConnectionRecord cr = clist.get(k);
+ final ProcessRecord client = cr.binding.client;
+ containsCycle |= client.mState.isReversedReachable();
+ if (client.mState.isReversedReachable()) {
+ continue;
+ }
+ queue.offer(client);
+ client.mState.setReversedReachable(true);
+ }
+ }
+ }
+ final ProcessProviderRecord ppr = pr.mProviders;
+ for (int i = ppr.numberOfProviders() - 1; i >= 0; i--) {
+ final ContentProviderRecord cpr = ppr.getProviderAt(i);
+ for (int j = cpr.connections.size() - 1; j >= 0; j--) {
+ final ContentProviderConnection conn = cpr.connections.get(j);
+ final ProcessRecord client = conn.client;
+ containsCycle |= client.mState.isReversedReachable();
+ if (client.mState.isReversedReachable()) {
+ continue;
+ }
+ queue.offer(client);
+ client.mState.setReversedReachable(true);
+ }
+ }
+ // If this process is a sandbox itself, also add the app on whose behalf
+ // its running
+ if (pr.isSdkSandbox) {
+ for (int is = psr.numberOfRunningServices() - 1; is >= 0; is--) {
+ ServiceRecord s = psr.getRunningServiceAt(is);
+ ArrayMap<IBinder, ArrayList<ConnectionRecord>> serviceConnections =
+ s.getConnections();
+ for (int conni = serviceConnections.size() - 1; conni >= 0; conni--) {
+ ArrayList<ConnectionRecord> clist = serviceConnections.valueAt(conni);
+ for (int i = clist.size() - 1; i >= 0; i--) {
+ ConnectionRecord cr = clist.get(i);
+ ProcessRecord attributedApp = cr.binding.attributedClient;
+ if (attributedApp == null || attributedApp == pr) {
+ continue;
+ }
+ containsCycle |= attributedApp.mState.isReversedReachable();
+ if (attributedApp.mState.isReversedReachable()) {
+ continue;
+ }
+ queue.offer(attributedApp);
+ attributedApp.mState.setReversedReachable(true);
+ }
+ }
+ }
+ }
+ }
+
+ // Reset the temporary bits.
+ for (int i = clientProcesses.size() - 1; i >= 0; i--) {
+ clientProcesses.get(i).mState.setReversedReachable(false);
+ }
+ for (int i = 0, size = apps.size(); i < size; i++) {
+ final ProcessRecord app = apps.valueAt(i);
+ app.mState.setReachable(false);
+ app.mState.setReversedReachable(false);
+ }
+ return containsCycle;
+ }
+
+ @GuardedBy({"mService", "mProcLock"})
+ private void updateNewOomAdjInnerLSP(@OomAdjReason int oomAdjReason, final ProcessRecord topApp,
+ ArraySet<ProcessRecord> targetProcesses, ArrayList<ProcessRecord> clientProcesses,
+ ActiveUids uids, int cachedAdj, long now, boolean fullUpdate) {
+ mTmpOomAdjusterArgs.update(topApp, now, cachedAdj, oomAdjReason, uids, fullUpdate);
+
+ mProcessRecordProcStateNodes.resetLastNodes();
+ mProcessRecordAdjNodes.resetLastNodes();
+
+ final int procStateTarget = mProcessRecordProcStateNodes.size() - 1;
+ final int adjTarget = mProcessRecordAdjNodes.size() - 1;
+
+ final int appUid = !fullUpdate && targetProcesses.size() > 0
+ ? targetProcesses.valueAt(0).uid : -1;
+ final int logUid = mService.mCurOomAdjUid;
+
+ mAdjSeq++;
+ // All apps to be updated will be moved to the lowest slot.
+ if (fullUpdate) {
+ // Move all the process record node to the lowest slot, we'll do recomputation on all of
+ // them. Use the processes from the lru list, because the scanning order matters here.
+ final ArrayList<ProcessRecord> lruList = mProcessList.getLruProcessesLOSP();
+ for (int i = procStateTarget; i >= 0; i--) {
+ mProcessRecordProcStateNodes.reset(i);
+ // Force the last node to the head since we'll recompute all of them.
+ mProcessRecordProcStateNodes.setLastNodeToHead(i);
+ }
+ // enqueue the targets in the reverse order of the lru list.
+ for (int i = lruList.size() - 1; i >= 0; i--) {
+ mProcessRecordProcStateNodes.append(lruList.get(i), procStateTarget);
+ }
+ // Do the same to the adj nodes.
+ for (int i = adjTarget; i >= 0; i--) {
+ mProcessRecordAdjNodes.reset(i);
+ // Force the last node to the head since we'll recompute all of them.
+ mProcessRecordAdjNodes.setLastNodeToHead(i);
+ }
+ for (int i = lruList.size() - 1; i >= 0; i--) {
+ mProcessRecordAdjNodes.append(lruList.get(i), adjTarget);
+ }
+ } else {
+ // Move the target processes to the lowest slot.
+ for (int i = 0, size = targetProcesses.size(); i < size; i++) {
+ final ProcessRecord app = targetProcesses.valueAt(i);
+ final int procStateSlot = processStateToSlot(app.mState.getCurProcState());
+ final int adjSlot = adjToSlot(app.mState.getCurRawAdj());
+ mProcessRecordProcStateNodes.moveAppTo(app, procStateSlot, procStateTarget);
+ mProcessRecordAdjNodes.moveAppTo(app, adjSlot, adjTarget);
+ }
+ // Move the "lastNode" to head to make sure we scan all nodes in this slot.
+ mProcessRecordProcStateNodes.setLastNodeToHead(procStateTarget);
+ mProcessRecordAdjNodes.setLastNodeToHead(adjTarget);
+ }
+
+ // All apps to be updated have been moved to the lowest slot.
+ // Do an initial pass of the computation.
+ mProcessRecordProcStateNodes.forEachNewNode(mProcessRecordProcStateNodes.size() - 1,
+ this::computeInitialOomAdjLSP);
+
+ if (!fullUpdate) {
+ // We didn't update the client processes with the computeInitialOomAdjLSP
+ // because they don't need to do so. But they'll be playing vital roles in
+ // computing the bindings. So include them into the scan list below.
+ for (int i = 0, size = clientProcesses.size(); i < size; i++) {
+ mProcessRecordProcStateNodes.moveAppToTail(clientProcesses.get(i));
+ }
+ // We don't update the adj list since we're resetting it below.
+ }
+
+ // Now nodes are set into their slots, without facting in the bindings.
+ // The nodes between the `lastNode` pointer and the TAIL should be the new nodes.
+ //
+ // The whole rationale here is that, the bindings from client to host app, won't elevate
+ // the host app's procstate/adj higher than the client app's state (BIND_ABOVE_CLIENT
+ // is a special case here, but client app's raw adj is still no less than the host app's).
+ // Therefore, starting from the top to the bottom, for each slot, scan all of the new nodes,
+ // check its bindings, elevate its host app's slot if necessary.
+ //
+ // We'd have to do this in two passes: 1) scan procstate node list; 2) scan adj node list.
+ // Because the procstate and adj are not always in sync - there are cases where
+ // the processes with lower proc state could be getting a higher oom adj score.
+ // And because of this, the procstate and adj node lists are basically two priority heaps.
+ //
+ // As the 2nd pass with the adj node lists potentially includes a significant amount of
+ // duplicated scans as the 1st pass has done, we'll reset the last node pointers for
+ // the adj node list before the 1st pass; so during the 1st pass, if any app's adj slot
+ // gets bumped, we'll only scan those in 2nd pass.
+
+ mProcessRecordAdjNodes.resetLastNodes();
+
+ // 1st pass, scan each slot in the procstate node list.
+ for (int i = 0, end = mProcessRecordProcStateNodes.size() - 1; i < end; i++) {
+ mProcessRecordProcStateNodes.forEachNewNode(i, this::computeHostOomAdjLSP);
+ }
+
+ // 2nd pass, scan each slot in the adj node list.
+ for (int i = 0, end = mProcessRecordAdjNodes.size() - 1; i < end; i++) {
+ mProcessRecordAdjNodes.forEachNewNode(i, this::computeHostOomAdjLSP);
+ }
+ }
+
+ @GuardedBy({"mService", "mProcLock"})
+ private void computeInitialOomAdjLSP(OomAdjusterArgs args) {
+ final ProcessRecord app = args.mApp;
+ final int cachedAdj = args.mCachedAdj;
+ final ProcessRecord topApp = args.mTopApp;
+ final long now = args.mNow;
+ final int oomAdjReason = args.mOomAdjReason;
+ final ActiveUids uids = args.mUids;
+ final boolean fullUpdate = args.mFullUpdate;
+
+ if (DEBUG_OOM_ADJ) {
+ Slog.i(TAG, "OOM ADJ initial args app=" + app
+ + " cachedAdj=" + cachedAdj
+ + " topApp=" + topApp
+ + " now=" + now
+ + " oomAdjReason=" + oomAdjReasonToString(oomAdjReason)
+ + " fullUpdate=" + fullUpdate);
+ }
+
+ if (uids != null) {
+ final UidRecord uidRec = app.getUidRecord();
+
+ if (uidRec != null) {
+ uids.put(uidRec.getUid(), uidRec);
+ }
+ }
+
+ computeOomAdjLSP(app, cachedAdj, topApp, fullUpdate, now, false, false, oomAdjReason,
+ false);
+ }
+
+ /**
+ * @return The proposed change to the schedGroup.
+ */
+ @GuardedBy({"mService", "mProcLock"})
+ @Override
+ protected int setIntermediateAdjLSP(ProcessRecord app, int adj, int prevRawAppAdj,
+ int schedGroup) {
+ schedGroup = super.setIntermediateAdjLSP(app, adj, prevRawAppAdj, schedGroup);
+
+ updateAdjSlotIfNecessary(app, prevRawAppAdj);
+
+ return schedGroup;
+ }
+
+ @GuardedBy({"mService", "mProcLock"})
+ @Override
+ protected void setIntermediateProcStateLSP(ProcessRecord app, int procState,
+ int prevProcState) {
+ super.setIntermediateProcStateLSP(app, procState, prevProcState);
+
+ updateProcStateSlotIfNecessary(app, prevProcState);
+ }
+
+ @GuardedBy({"mService", "mProcLock"})
+ private void computeHostOomAdjLSP(OomAdjusterArgs args) {
+ final ProcessRecord app = args.mApp;
+ final int cachedAdj = args.mCachedAdj;
+ final ProcessRecord topApp = args.mTopApp;
+ final long now = args.mNow;
+ final @OomAdjReason int oomAdjReason = args.mOomAdjReason;
+ final boolean fullUpdate = args.mFullUpdate;
+ final ActiveUids uids = args.mUids;
+
+ final ProcessServiceRecord psr = app.mServices;
+ for (int i = psr.numberOfConnections() - 1; i >= 0; i--) {
+ ConnectionRecord cr = psr.getConnectionAt(i);
+ ProcessRecord service = cr.hasFlag(ServiceInfo.FLAG_ISOLATED_PROCESS)
+ ? cr.binding.service.isolationHostProc : cr.binding.service.app;
+ if (service == null || service == app
+ || (service.mState.getMaxAdj() >= SYSTEM_ADJ
+ && service.mState.getMaxAdj() < FOREGROUND_APP_ADJ)
+ || (service.mState.getCurAdj() <= FOREGROUND_APP_ADJ
+ && service.mState.getCurrentSchedulingGroup() > SCHED_GROUP_BACKGROUND
+ && service.mState.getCurProcState() <= PROCESS_STATE_TOP)) {
+ continue;
+ }
+
+
+ computeServiceHostOomAdjLSP(cr, service, app, now, topApp, fullUpdate, false, false,
+ oomAdjReason, cachedAdj, false);
+ }
+
+ for (int i = psr.numberOfSdkSandboxConnections() - 1; i >= 0; i--) {
+ final ConnectionRecord cr = psr.getSdkSandboxConnectionAt(i);
+ final ProcessRecord service = cr.binding.service.app;
+ if (service == null || service == app
+ || (service.mState.getMaxAdj() >= SYSTEM_ADJ
+ && service.mState.getMaxAdj() < FOREGROUND_APP_ADJ)
+ || (service.mState.getCurAdj() <= FOREGROUND_APP_ADJ
+ && service.mState.getCurrentSchedulingGroup() > SCHED_GROUP_BACKGROUND
+ && service.mState.getCurProcState() <= PROCESS_STATE_TOP)) {
+ continue;
+ }
+
+ computeServiceHostOomAdjLSP(cr, service, app, now, topApp, fullUpdate, false, false,
+ oomAdjReason, cachedAdj, false);
+ }
+
+ final ProcessProviderRecord ppr = app.mProviders;
+ for (int i = ppr.numberOfProviderConnections() - 1; i >= 0; i--) {
+ ContentProviderConnection cpc = ppr.getProviderConnectionAt(i);
+ ProcessRecord provider = cpc.provider.proc;
+ if (provider == null || provider == app
+ || (provider.mState.getMaxAdj() >= ProcessList.SYSTEM_ADJ
+ && provider.mState.getMaxAdj() < FOREGROUND_APP_ADJ)
+ || (provider.mState.getCurAdj() <= FOREGROUND_APP_ADJ
+ && provider.mState.getCurrentSchedulingGroup() > SCHED_GROUP_BACKGROUND
+ && provider.mState.getCurProcState() <= PROCESS_STATE_TOP)) {
+ continue;
+ }
+
+ computeProviderHostOomAdjLSP(cpc, provider, app, now, topApp, fullUpdate, false, false,
+ oomAdjReason, cachedAdj, false);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index f532122c1..7037fec 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -22,6 +22,7 @@
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.ActivityManagerService.MY_PID;
+import static com.android.server.am.OomAdjusterModernImpl.ProcessRecordNode.NUM_NODE_TYPE;
import static java.util.Objects.requireNonNull;
@@ -63,6 +64,7 @@
import com.android.internal.app.procstats.ProcessStats;
import com.android.internal.os.Zygote;
import com.android.server.FgThread;
+import com.android.server.am.OomAdjusterModernImpl.ProcessRecordNode;
import com.android.server.wm.WindowProcessController;
import com.android.server.wm.WindowProcessListener;
@@ -434,6 +436,8 @@
*/
volatile boolean mSkipProcessGroupCreation;
+ final ProcessRecordNode[] mLinkedNodes = new ProcessRecordNode[NUM_NODE_TYPE];
+
void setStartParams(int startUid, HostingRecord hostingRecord, String seInfo,
long startUptime, long startElapsedTime) {
this.mStartUid = startUid;
@@ -1114,6 +1118,7 @@
mState.onCleanupApplicationRecordLSP();
mServices.onCleanupApplicationRecordLocked();
mReceivers.onCleanupApplicationRecordLocked();
+ mService.mOomAdjuster.onProcessEndLocked(this);
return mProviders.onCleanupApplicationRecordLocked(allowRestart);
}
diff --git a/services/core/java/com/android/server/am/ProcessServiceRecord.java b/services/core/java/com/android/server/am/ProcessServiceRecord.java
index 7ff6d11..a165e88 100644
--- a/services/core/java/com/android/server/am/ProcessServiceRecord.java
+++ b/services/core/java/com/android/server/am/ProcessServiceRecord.java
@@ -19,6 +19,7 @@
import static android.app.ProcessMemoryState.HOSTING_COMPONENT_TYPE_BOUND_SERVICE;
import static android.app.ProcessMemoryState.HOSTING_COMPONENT_TYPE_FOREGROUND_SERVICE;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.ServiceInfo;
@@ -134,6 +135,11 @@
private final ArraySet<ConnectionRecord> mConnections = new ArraySet<>();
/**
+ * All ConnectionRecord this process holds indirectly to SDK sandbox processes.
+ */
+ private @Nullable ArraySet<ConnectionRecord> mSdkSandboxConnections;
+
+ /**
* A set of UIDs of all bound clients.
*/
private ArraySet<Integer> mBoundClientUids = new ArraySet<>();
@@ -490,13 +496,18 @@
void addConnection(ConnectionRecord connection) {
mConnections.add(connection);
+ addSdkSandboxConnectionIfNecessary(connection);
}
void removeConnection(ConnectionRecord connection) {
mConnections.remove(connection);
+ removeSdkSandboxConnectionIfNecessary(connection);
}
void removeAllConnections() {
+ for (int i = 0, size = mConnections.size(); i < size; i++) {
+ removeSdkSandboxConnectionIfNecessary(mConnections.valueAt(i));
+ }
mConnections.clear();
}
@@ -508,6 +519,39 @@
return mConnections.size();
}
+ private void addSdkSandboxConnectionIfNecessary(ConnectionRecord connection) {
+ final ProcessRecord attributedClient = connection.binding.attributedClient;
+ if (attributedClient != null && connection.binding.service.isSdkSandbox) {
+ if (attributedClient.mServices.mSdkSandboxConnections == null) {
+ attributedClient.mServices.mSdkSandboxConnections = new ArraySet<>();
+ }
+ attributedClient.mServices.mSdkSandboxConnections.add(connection);
+ }
+ }
+
+ private void removeSdkSandboxConnectionIfNecessary(ConnectionRecord connection) {
+ final ProcessRecord attributedClient = connection.binding.attributedClient;
+ if (attributedClient != null && connection.binding.service.isSdkSandbox) {
+ if (attributedClient.mServices.mSdkSandboxConnections == null) {
+ attributedClient.mServices.mSdkSandboxConnections.remove(connection);
+ }
+ }
+ }
+
+ void removeAllSdkSandboxConnections() {
+ if (mSdkSandboxConnections != null) {
+ mSdkSandboxConnections.clear();
+ }
+ }
+
+ ConnectionRecord getSdkSandboxConnectionAt(int index) {
+ return mSdkSandboxConnections != null ? mSdkSandboxConnections.valueAt(index) : null;
+ }
+
+ int numberOfSdkSandboxConnections() {
+ return mSdkSandboxConnections != null ? mSdkSandboxConnections.size() : 0;
+ }
+
void addBoundClientUid(int clientUid, String clientPackageName, long bindFlags) {
mBoundClientUids.add(clientUid);
mApp.getWindowProcessController()
diff --git a/services/core/java/com/android/server/am/ProcessStateRecord.java b/services/core/java/com/android/server/am/ProcessStateRecord.java
index db341d2..a9c388c 100644
--- a/services/core/java/com/android/server/am/ProcessStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessStateRecord.java
@@ -378,6 +378,12 @@
private boolean mReachable;
/**
+ * Whether or not this process is reversed reachable from given process.
+ */
+ @GuardedBy("mService")
+ private boolean mReversedReachable;
+
+ /**
* The most recent time when the last visible activity within this process became invisible.
*
* <p> It'll be set to 0 if there is never a visible activity, or Long.MAX_VALUE if there is
@@ -454,6 +460,9 @@
@GuardedBy("mService")
private int mCachedSchedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
+ @GuardedBy("mService")
+ private boolean mScheduleLikeTopApp = false;
+
ProcessStateRecord(ProcessRecord app) {
mApp = app;
mService = app.mService;
@@ -614,9 +623,11 @@
void forceProcessStateUpTo(int newState) {
if (mRepProcState > newState) {
synchronized (mProcLock) {
+ final int prevProcState = mRepProcState;
setReportedProcState(newState);
setCurProcState(newState);
setCurRawProcState(newState);
+ mService.mOomAdjuster.onProcessStateChanged(mApp, prevProcState);
}
}
}
@@ -985,6 +996,16 @@
}
@GuardedBy("mService")
+ boolean isReversedReachable() {
+ return mReversedReachable;
+ }
+
+ @GuardedBy("mService")
+ void setReversedReachable(boolean reversedReachable) {
+ mReversedReachable = reversedReachable;
+ }
+
+ @GuardedBy("mService")
void resetCachedInfo() {
mCachedHasActivities = VALUE_INVALID;
mCachedIsHeavyWeight = VALUE_INVALID;
@@ -1134,6 +1155,16 @@
return mCachedSchedGroup;
}
+ @GuardedBy("mService")
+ boolean shouldScheduleLikeTopApp() {
+ return mScheduleLikeTopApp;
+ }
+
+ @GuardedBy("mService")
+ void setScheduleLikeTopApp(boolean scheduleLikeTopApp) {
+ mScheduleLikeTopApp = scheduleLikeTopApp;
+ }
+
@GuardedBy(anyOf = {"mService", "mProcLock"})
public String makeAdjReason() {
if (mAdjSource != null || mAdjTarget != null) {
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index 4f7a2ba..6191861 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -80,8 +80,7 @@
@VisibleForTesting
static final String UNIQUE_ID_PREFIX = "virtual:";
- private final ArrayMap<IBinder, VirtualDisplayDevice> mVirtualDisplayDevices =
- new ArrayMap<IBinder, VirtualDisplayDevice>();
+ private final ArrayMap<IBinder, VirtualDisplayDevice> mVirtualDisplayDevices = new ArrayMap<>();
private final Handler mHandler;
private final SurfaceControlDisplayFactory mSurfaceControlDisplayFactory;
@@ -113,9 +112,16 @@
public DisplayDevice createVirtualDisplayLocked(IVirtualDisplayCallback callback,
IMediaProjection projection, int ownerUid, String ownerPackageName, Surface surface,
int flags, VirtualDisplayConfig virtualDisplayConfig) {
+ IBinder appToken = callback.asBinder();
+ if (mVirtualDisplayDevices.containsKey(appToken)) {
+ Slog.wtfStack(TAG,
+ "Can't create virtual display, display with same appToken already exists");
+ return null;
+ }
+
String name = virtualDisplayConfig.getName();
boolean secure = (flags & VIRTUAL_DISPLAY_FLAG_SECURE) != 0;
- IBinder appToken = callback.asBinder();
+
IBinder displayToken = mSurfaceControlDisplayFactory.createDisplay(name, secure,
virtualDisplayConfig.getRequestedRefreshRate());
final String baseUniqueId =
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 2c866ab..8673b90 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -18,6 +18,7 @@
import static android.Manifest.permission.BIND_VOICE_INTERACTION;
import static android.Manifest.permission.CHANGE_CONFIGURATION;
+import static android.Manifest.permission.CONTROL_KEYGUARD;
import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
import static android.Manifest.permission.DETECT_SCREEN_CAPTURE;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
@@ -3549,6 +3550,7 @@
@Override
public void keyguardGoingAway(int flags) {
+ mAmInternal.enforceCallingPermission(CONTROL_KEYGUARD, "unlock keyguard");
enforceNotIsolatedCaller("keyguardGoingAway");
final long token = Binder.clearCallingIdentity();
try {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 6d0fd2a..029f46f 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -5682,6 +5682,12 @@
// TODO(b/233286785): Add sync support to wallpaper.
return true;
}
+ if (mActivityRecord != null && mViewVisibility != View.VISIBLE
+ && mWinAnimator.mAttrType != TYPE_BASE_APPLICATION
+ && mWinAnimator.mAttrType != TYPE_APPLICATION_STARTING) {
+ // Skip sync for invisible app windows which are not managed by activity lifecycle.
+ return false;
+ }
// In the WindowContainer implementation we immediately mark ready
// since a generic WindowContainer only needs to wait for its
// children to finish and is immediately ready from its own
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
index d16c9c5..bf23117 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -248,6 +248,8 @@
@Mock VirtualDeviceManagerInternal mMockVirtualDeviceManagerInternal;
@Mock IVirtualDisplayCallback.Stub mMockAppToken;
@Mock IVirtualDisplayCallback.Stub mMockAppToken2;
+
+ @Mock IVirtualDisplayCallback.Stub mMockAppToken3;
@Mock WindowManagerInternal mMockWindowManagerInternal;
@Mock LightsManager mMockLightsManager;
@Mock VirtualDisplayAdapter mMockVirtualDisplayAdapter;
@@ -838,6 +840,7 @@
registerDefaultDisplays(displayManager);
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
+ when(mMockAppToken2.asBinder()).thenReturn(mMockAppToken2);
IVirtualDevice virtualDevice = mock(IVirtualDevice.class);
when(virtualDevice.getDeviceId()).thenReturn(1);
@@ -851,7 +854,7 @@
int displayId1 =
localService.createVirtualDisplay(
builder1.build(),
- mMockAppToken /* callback */,
+ mMockAppToken2 /* callback */,
virtualDevice /* virtualDeviceToken */,
mock(DisplayWindowPolicyController.class),
PACKAGE_NAME);
@@ -893,6 +896,7 @@
registerDefaultDisplays(displayManager);
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
+ when(mMockAppToken2.asBinder()).thenReturn(mMockAppToken2);
IVirtualDevice virtualDevice = mock(IVirtualDevice.class);
when(virtualDevice.getDeviceId()).thenReturn(1);
@@ -927,7 +931,7 @@
int displayId2 =
localService.createVirtualDisplay(
builder2.build(),
- mMockAppToken /* callback */,
+ mMockAppToken2 /* callback */,
virtualDevice /* virtualDeviceToken */,
mock(DisplayWindowPolicyController.class),
PACKAGE_NAME);
@@ -950,6 +954,8 @@
registerDefaultDisplays(displayManager);
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
+ when(mMockAppToken2.asBinder()).thenReturn(mMockAppToken2);
+ when(mMockAppToken3.asBinder()).thenReturn(mMockAppToken3);
IVirtualDevice virtualDevice = mock(IVirtualDevice.class);
when(virtualDevice.getDeviceId()).thenReturn(1);
@@ -999,7 +1005,7 @@
int ownDisplayGroupDisplayId =
localService.createVirtualDisplay(
ownDisplayGroupConfig,
- mMockAppToken /* callback */,
+ mMockAppToken2 /* callback */,
virtualDevice /* virtualDeviceToken */,
mock(DisplayWindowPolicyController.class),
PACKAGE_NAME);
@@ -1024,7 +1030,7 @@
int defaultDisplayGroupDisplayId =
localService.createVirtualDisplay(
defaultDisplayGroupConfig,
- mMockAppToken /* callback */,
+ mMockAppToken3 /* callback */,
null /* virtualDeviceToken */,
mock(DisplayWindowPolicyController.class),
PACKAGE_NAME);
diff --git a/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java b/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java
new file mode 100644
index 0000000..8bbacc4
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.hardware.display.IVirtualDisplayCallback;
+import android.hardware.display.VirtualDisplayConfig;
+import android.os.IBinder;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.server.testutils.TestHandler;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class VirtualDisplayAdapterTest {
+
+ @Mock
+ Context mContextMock;
+
+ @Mock
+ VirtualDisplayAdapter.SurfaceControlDisplayFactory mMockSufaceControlDisplayFactory;
+
+ @Mock
+ DisplayAdapter.Listener mMockListener;
+
+ @Mock
+ IVirtualDisplayCallback mMockCallback;
+
+ @Mock
+ IBinder mMockBinder;
+
+ private TestHandler mHandler;
+
+ private VirtualDisplayAdapter mVirtualDisplayAdapter;
+
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mHandler = new TestHandler(null);
+ mVirtualDisplayAdapter = new VirtualDisplayAdapter(new DisplayManagerService.SyncRoot(),
+ mContextMock, mHandler, mMockListener, mMockSufaceControlDisplayFactory);
+
+ when(mMockCallback.asBinder()).thenReturn(mMockBinder);
+ }
+
+ @Test
+ public void testCreatesVirtualDisplay() {
+ VirtualDisplayConfig config = new VirtualDisplayConfig.Builder("test", /* width= */ 1,
+ /* height= */ 1, /* densityDpi= */ 1).build();
+
+ DisplayDevice result = mVirtualDisplayAdapter.createVirtualDisplayLocked(mMockCallback,
+ /* projection= */ null, /* ownerUid= */ 10, /* packageName= */ "testpackage",
+ /* surface= */ null, /* flags= */ 0, config);
+
+ assertNotNull(result);
+ }
+
+ @Test
+ public void testDoesNotCreateVirtualDisplayForSameCallback() {
+ VirtualDisplayConfig config1 = new VirtualDisplayConfig.Builder("test", /* width= */ 1,
+ /* height= */ 1, /* densityDpi= */ 1).build();
+ VirtualDisplayConfig config2 = new VirtualDisplayConfig.Builder("test2", /* width= */ 1,
+ /* height= */ 1, /* densityDpi= */ 1).build();
+ mVirtualDisplayAdapter.createVirtualDisplayLocked(mMockCallback, /* projection= */ null,
+ /* ownerUid= */ 10, /* packageName= */ "testpackage", /* surface= */ null,
+ /* flags= */ 0, config1);
+
+ DisplayDevice result = mVirtualDisplayAdapter.createVirtualDisplayLocked(mMockCallback,
+ /* projection= */ null, /* ownerUid= */ 10, /* packageName= */ "testpackage",
+ /* surface= */ null, /* flags= */ 0, config2);
+
+ assertNull(result);
+ }
+}
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 1f4563f..976e740 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -105,6 +105,7 @@
import com.android.server.wm.ActivityTaskManagerService;
import com.android.server.wm.WindowProcessController;
+import org.junit.After;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -206,8 +207,10 @@
setFieldValue(AppProfiler.class, profiler, "mProfilerLock", new Object());
doReturn(new ActivityManagerService.ProcessChangeItem()).when(pr)
.enqueueProcessChangeItemLocked(anyInt(), anyInt());
- sService.mOomAdjuster = new OomAdjuster(sService, sService.mProcessList,
- new ActiveUids(sService, false));
+ sService.mOomAdjuster = sService.mConstants.ENABLE_NEW_OOMADJ
+ ? new OomAdjusterModernImpl(sService, sService.mProcessList,
+ new ActiveUids(sService, false))
+ : new OomAdjuster(sService, sService.mProcessList, new ActiveUids(sService, false));
sService.mOomAdjuster.mAdjSeq = 10000;
sService.mWakefulness = new AtomicInteger(PowerManagerInternal.WAKEFULNESS_AWAKE);
if (sService.mConstants.USE_TIERED_CACHED_ADJ) {
@@ -220,6 +223,11 @@
LocalServices.removeServiceForTest(PackageManagerInternal.class);
}
+ @After
+ public void tearDown() {
+ sService.mOomAdjuster.resetInternal();
+ }
+
private static <T> void setFieldValue(Class clazz, Object obj, String fieldName, T val) {
try {
Field field = clazz.getDeclaredField(fieldName);
@@ -249,6 +257,9 @@
ArrayList<ProcessRecord> lru = sService.mProcessList.getLruProcessesLOSP();
lru.clear();
Collections.addAll(lru, apps);
+ for (ProcessRecord app : apps) {
+ sService.mOomAdjuster.onProcessBeginLocked(app);
+ }
}
/**
@@ -259,6 +270,7 @@
@SuppressWarnings("GuardedBy")
private void updateOomAdj(ProcessRecord... apps) {
if (apps.length == 1) {
+ sService.mOomAdjuster.onProcessBeginLocked(apps[0]);
sService.mOomAdjuster.updateOomAdjLocked(apps[0], OOM_ADJ_REASON_NONE);
} else {
setProcessesToLru(apps);
@@ -600,10 +612,13 @@
s.lastTopAlmostPerceptibleBindRequestUptimeMs = nowUptime;
s.getConnections().clear();
app.mServices.updateHasTopStartedAlmostPerceptibleServices();
+ sService.mOomAdjuster.onProcessBeginLocked(system);
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertEquals(PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ + 2, app.mState.getSetAdj());
+
+ sService.mOomAdjuster.resetInternal();
}
// Out of grace period but valid binding allows the adjustment.
@@ -620,10 +635,13 @@
s.lastTopAlmostPerceptibleBindRequestUptimeMs =
nowUptime - 2 * sService.mConstants.mServiceBindAlmostPerceptibleTimeoutMs;
app.mServices.updateHasTopStartedAlmostPerceptibleServices();
+ sService.mOomAdjuster.onProcessBeginLocked(system);
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertEquals(PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ + 2, app.mState.getSetAdj());
+
+ sService.mOomAdjuster.resetInternal();
}
// Out of grace period and no valid binding so no adjustment.
@@ -641,10 +659,13 @@
nowUptime - 2 * sService.mConstants.mServiceBindAlmostPerceptibleTimeoutMs;
s.getConnections().clear();
app.mServices.updateHasTopStartedAlmostPerceptibleServices();
+ sService.mOomAdjuster.onProcessBeginLocked(system);
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertNotEquals(PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ + 2, app.mState.getSetAdj());
+
+ sService.mOomAdjuster.resetInternal();
}
}
@@ -657,11 +678,12 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, true));
system.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
system.mState.setHasTopUi(true);
+ sService.mOomAdjuster.onProcessBeginLocked(system);
// Simulate the system starting and binding to a service in the app.
ServiceRecord s = bindService(app, system,
null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class));
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
- sService.mOomAdjuster.updateOomAdjLocked(app, OOM_ADJ_REASON_NONE);
+ updateOomAdj(system, app);
assertProcStates(app, PROCESS_STATE_IMPORTANT_FOREGROUND,
PERCEPTIBLE_APP_ADJ + 1, SCHED_GROUP_DEFAULT);
@@ -850,6 +872,7 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+ client.mServices.setTreatLikeActivity(true);
bindService(app, client, null, Context.BIND_WAIVE_PRIORITY
| Context.BIND_TREAT_LIKE_ACTIVITY, mock(IBinder.class));
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
@@ -1006,7 +1029,7 @@
bindService(app, client, null, Context.BIND_NOT_FOREGROUND, mock(IBinder.class));
client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
- updateOomAdj(app);
+ updateOomAdj(client, app);
assertEquals(PROCESS_STATE_TRANSIENT_BACKGROUND, app.mState.getSetProcState());
assertNoBfsl(app);
@@ -1132,7 +1155,7 @@
assertNoBfsl(app);
client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
- updateOomAdj(app);
+ updateOomAdj(client, app);
assertEquals(PERSISTENT_SERVICE_ADJ, app.mState.getSetAdj());
assertBfsl(app);
@@ -1148,7 +1171,7 @@
bindService(app, client, null, Context.BIND_NOT_PERCEPTIBLE, mock(IBinder.class));
client.mState.setRunningRemoteAnimation(true);
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
- updateOomAdj(app);
+ updateOomAdj(client, app);
assertEquals(PERCEPTIBLE_LOW_APP_ADJ, app.mState.getSetAdj());
}
@@ -1199,6 +1222,8 @@
updateOomAdj(client, app);
assertEquals(PERCEPTIBLE_MEDIUM_APP_ADJ + 2, app.mState.getSetAdj());
+
+ sService.mOomAdjuster.resetInternal();
}
{
@@ -1217,6 +1242,8 @@
doReturn(false).when(wpc).isHeavyWeightProcess();
assertEquals(PERCEPTIBLE_MEDIUM_APP_ADJ + 2, app.mState.getSetAdj());
+
+ sService.mOomAdjuster.resetInternal();
}
{
@@ -1229,9 +1256,11 @@
mock(IBinder.class));
client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
- sService.mOomAdjuster.updateOomAdjLocked(app, OOM_ADJ_REASON_NONE);
+ updateOomAdj(client, app);
assertEquals(PERCEPTIBLE_APP_ADJ + 1, app.mState.getSetAdj());
+
+ sService.mOomAdjuster.resetInternal();
}
{
@@ -1246,10 +1275,12 @@
mock(IBinder.class));
client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
- sService.mOomAdjuster.updateOomAdjLocked(app, OOM_ADJ_REASON_NONE);
+ updateOomAdj(client, app);
doReturn(false).when(wpc).isHeavyWeightProcess();
assertEquals(PERCEPTIBLE_APP_ADJ + 1, app.mState.getSetAdj());
+
+ sService.mOomAdjuster.resetInternal();
}
}
@@ -1849,7 +1880,7 @@
bindService(app1, client1, null, Context.BIND_SCHEDULE_LIKE_TOP_APP, mock(IBinder.class));
bindService(app2, client2, null, Context.BIND_SCHEDULE_LIKE_TOP_APP, mock(IBinder.class));
- updateOomAdj(app1, app2);
+ updateOomAdj(client1, client2, app1, app2);
assertProcStates(app1, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, VISIBLE_APP_ADJ,
SCHED_GROUP_TOP_APP);
@@ -1899,6 +1930,8 @@
s1.getConnections().clear();
s2.getConnections().clear();
+ client1.mServices.removeAllConnections();
+ client2.mServices.removeAllConnections();
client1.mState.setMaxAdj(UNKNOWN_ADJ);
client2.mState.setMaxAdj(UNKNOWN_ADJ);
client1.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
@@ -1909,7 +1942,7 @@
bindService(app2, client2, s2, Context.BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE,
mock(IBinder.class));
- updateOomAdj(app1, app2);
+ updateOomAdj(client1, client2, app1, app2);
// VISIBLE_APP_ADJ is the max oom-adj for BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE.
assertProcStates(app1, PROCESS_STATE_FOREGROUND_SERVICE, VISIBLE_APP_ADJ,
@@ -1922,7 +1955,7 @@
doReturn(client2).when(sService).getTopApp();
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
- sService.mOomAdjuster.updateOomAdjLocked(app2, OOM_ADJ_REASON_NONE);
+ updateOomAdj(client2, app2);
assertProcStates(app2, PROCESS_STATE_BOUND_TOP, VISIBLE_APP_ADJ,
SCHED_GROUP_DEFAULT);
}
@@ -1977,6 +2010,7 @@
app.setPendingFinishAttach(true);
app.mState.setHasForegroundActivities(false);
+ sService.mOomAdjuster.onProcessBeginLocked(app);
sService.mOomAdjuster.setAttachingProcessStatesLSP(app);
updateOomAdj(app);
@@ -1991,7 +2025,9 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
app.setPendingFinishAttach(true);
app.mState.setHasForegroundActivities(true);
+ doReturn(app).when(sService).getTopApp();
+ sService.mOomAdjuster.onProcessBeginLocked(app);
sService.mOomAdjuster.setAttachingProcessStatesLSP(app);
updateOomAdj(app);
@@ -2088,7 +2124,7 @@
anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
doNothing().when(sService.mServices)
.scheduleServiceTimeoutLocked(any(ProcessRecord.class));
- sService.mOomAdjuster.updateOomAdjLocked(client1, OOM_ADJ_REASON_NONE);
+ updateOomAdj(client1, client2, app1, app2, app3);
assertEquals(PROCESS_STATE_CACHED_EMPTY, client1.mState.getSetProcState());
assertEquals(PROCESS_STATE_SERVICE, app1.mState.getSetProcState());
@@ -2426,6 +2462,8 @@
lru.clear();
lru.add(app2);
lru.add(app);
+ sService.mOomAdjuster.onProcessBeginLocked(app2);
+ sService.mOomAdjuster.onProcessBeginLocked(app);
final ComponentName cn = ComponentName.unflattenFromString(
MOCKAPP_PACKAGENAME + "/.TestService");
@@ -2528,7 +2566,7 @@
doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
doReturn(app).when(sService).getTopApp();
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
- sService.mOomAdjuster.updateOomAdjLocked(app, OOM_ADJ_REASON_NONE);
+ updateOomAdj(app);
assertEquals(FOREGROUND_APP_ADJ, app.mState.getSetAdj());
diff --git a/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java b/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java
index 1c6408b..56c3ec0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java
@@ -50,7 +50,6 @@
import android.util.Log;
import android.view.IWindowManager;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.MediumTest;
import com.android.server.am.AssistDataRequester;
@@ -154,7 +153,6 @@
.noteOpNoThrow(eq(OP_ASSIST_SCREENSHOT), anyInt(), anyString(), any(), any());
}
- @FlakyTest(bugId = 280107567)
@Test
public void testRequestData() throws Exception {
setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
@@ -262,7 +260,6 @@
assertReceivedDataCount(0, 1, 0, 1);
}
- @FlakyTest(bugId = 280107567)
@Test
public void testNoFetchScreenshots_expectNoScreenshotCallbacks() throws Exception {
setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
@@ -274,7 +271,6 @@
assertReceivedDataCount(5, 5, 0, 0);
}
- @FlakyTest(bugId = 280107567)
@Test
public void testDisallowAssistScreenshot_expectNullScreenshotCallback() throws Exception {
setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
@@ -321,7 +317,8 @@
assertEquals("Expected " + numPendingScreenshots + " pending screenshots, got "
+ mDataRequester.getPendingScreenshotCount(),
numPendingScreenshots, mDataRequester.getPendingScreenshotCount());
- assertFalse("Expected request NOT completed", mCallbacks.mRequestCompleted);
+ assertEquals("Expected request NOT completed, unless no pending data",
+ numPendingData == 0 && numPendingScreenshots == 0, mCallbacks.mRequestCompleted);
mGate.countDown();
waitForIdle(mHandler);
assertEquals("Expected " + numReceivedData + " data, received "
@@ -380,14 +377,7 @@
@Override
public void onAssistRequestCompleted() {
- mHandler.post(() -> {
- try {
- mGate.await(10, TimeUnit.SECONDS);
- mRequestCompleted = true;
- } catch (InterruptedException e) {
- Log.e(TAG, "Failed to wait", e);
- }
- });
+ mRequestCompleted = true;
}
}
}