Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3984215f authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "[Dev options] Use Android.os.SystemProperties instead of...

Merge "[Dev options] Use Android.os.SystemProperties instead of java.lang.System.setProperty for caching toggle overrides." into main
parents 23cbe12b 725313d2
Loading
Loading
Loading
Loading
+46 −24
Original line number Diff line number Diff line
@@ -17,16 +17,20 @@
package com.android.wm.shell.shared.desktopmode

import android.content.Context
import android.os.SystemProperties
import android.provider.Settings
import android.util.Log
import com.android.window.flags.Flags

/*
 * A shared class to check desktop mode flags state.
/**
 * Util to check desktop mode flags state.
 *
 * The class computes whether a Desktop Windowing flag should be enabled by using the aconfig flag
 * This utility is used to allow developer option toggles to override flags related to Desktop
 * Windowing.
 *
 * Computes whether Desktop Windowing related flags should be enabled by using the aconfig flag
 * value and the developer option override state (if applicable).
 **/
 */
enum class DesktopModeFlags(
    // Function called to obtain aconfig flag value.
    private val flagFunction: () -> Boolean,
@@ -67,35 +71,52 @@ enum class DesktopModeFlags(
              // Cache toggle override the first time we encounter context. Override does not change
              // with context, as context is just used to fetch System Property and Settings.Global
              cachedToggleOverride = override
              Log.d(TAG, "Toggle override initialized to: $override")
              Log.d(TAG, "Local toggle override initialized to: $override")
              override
            }

    return override
  }

  /**
   * Returns [ToggleOverride] from a non-persistent system property if present. Otherwise
   * initializes the system property by reading Settings.Global.
   */
  private fun getToggleOverrideFromSystem(context: Context): ToggleOverride {
    // A non-persistent System Property is used to store override to ensure it remains
    // constant till reboot.
    val overrideFromSystemProperties: ToggleOverride? =
        System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, null).convertToToggleOverride()
        SystemProperties.getInt(SYSTEM_PROPERTY_OVERRIDE_KEY, INVALID_TOGGLE_OVERRIDE_SETTING)
            .convertToToggleOverride()

    return overrideFromSystemProperties
        ?: run {
          // Read Setting Global if System Property is not present (just after reboot)
          // or not valid (user manually changed the value)
          val overrideFromSettingsGlobal =
              convertToToggleOverrideWithFallback(
          // TODO(b/348193756): Remove the initialization after adding it in core. If
          //  SystemProperty is still not present then return OVERRIDE_UNSET
          // Initialize System Property if not present (just after reboot)
          initializeOverrideInSystemProperty(context)
        }
  }

  /** Initializes Override System property based on Settings.Global set by toggle. */
  private fun initializeOverrideInSystemProperty(context: Context): ToggleOverride {
    val settingValue =
        Settings.Global.getInt(
            context.contentResolver,
            Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES,
                      ToggleOverride.OVERRIDE_UNSET.setting),
                  ToggleOverride.OVERRIDE_UNSET)
          // Initialize System Property
          System.setProperty(
              SYSTEM_PROPERTY_OVERRIDE_KEY, overrideFromSettingsGlobal.setting.toString())

          overrideFromSettingsGlobal
            ToggleOverride.OVERRIDE_UNSET.setting)
    try {
      SystemProperties.set(SYSTEM_PROPERTY_OVERRIDE_KEY, settingValue.toString())
      Log.d(TAG, "Initialized system property with override setting: $settingValue")
    } catch (e: RuntimeException) {
      // Thrown in device tests that don't mock SystemProperties
      Log.w(
          TAG,
          "Failed to set a system property: key=$SYSTEM_PROPERTY_OVERRIDE_KEY, " +
              "value=$settingValue, message=${e.message}")
    }

    return convertToToggleOverrideWithFallback(settingValue, ToggleOverride.OVERRIDE_UNSET)
  }

  /**
@@ -113,11 +134,10 @@ enum class DesktopModeFlags(
    OVERRIDE_ON(1)
  }

  private fun String?.convertToToggleOverride(): ToggleOverride? {
    val intValue = this?.toIntOrNull() ?: return null
    return settingToToggleOverrideMap[intValue]
  private fun Int.convertToToggleOverride(): ToggleOverride? {
    return settingToToggleOverrideMap[this]
        ?: run {
          Log.w(TAG, "Unknown toggleOverride int $intValue")
          Log.w(TAG, "Unknown toggleOverride int $this")
          null
        }
  }
@@ -131,6 +151,8 @@ enum class DesktopModeFlags(
     */
    private const val SYSTEM_PROPERTY_OVERRIDE_KEY = "sys.wmshell.desktopmode.dev_toggle_override"

    private const val INVALID_TOGGLE_OVERRIDE_SETTING = -2

    /**
     * Local cache for toggle override, which is initialized once on its first access. It needs to
     * be refreshed only on reboots as overridden state takes effect on reboots.
+51 −41
Original line number Diff line number Diff line
@@ -16,12 +16,15 @@

package com.android.wm.shell.shared.desktopmode

import android.os.SystemProperties
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.SetFlagsRule
import android.provider.Settings
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.dx.mockito.inline.extended.ExtendedMockito
import com.android.modules.utils.testing.ExtendedMockitoRule
import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE
import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY
import com.android.window.flags.Flags.FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION
@@ -37,6 +40,9 @@ import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito
import org.mockito.kotlin.any
import org.mockito.kotlin.eq

/**
 * Test class for [DesktopModeFlags]
@@ -47,7 +53,14 @@ import org.junit.runner.RunWith
@RunWith(AndroidTestingRunner::class)
class DesktopModeFlagsTest : ShellTestCase() {

  @JvmField @Rule val setFlagsRule = SetFlagsRule()
  @Rule(order = 1)
  @JvmField
  val setFlagsRule = SetFlagsRule()

  @Rule(order = 2)
  @JvmField
  val extendedMockitoRule: ExtendedMockitoRule =
    ExtendedMockitoRule.Builder(this).mockStatic(SystemProperties::class.java).build()

  @Before
  fun setUp() {
@@ -119,7 +132,7 @@ class DesktopModeFlagsTest : ShellTestCase() {
  @Test
  @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
  fun isEnabled_unrecognizableOverride_featureFlagOn_returnsTrue() {
    setOverride(-2)
    setOverride(INVALID_TOGGLE_OVERRIDE_SETTING)

    // For overridableFlag, for recognizable overrides, follow flag
    assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue()
@@ -129,7 +142,7 @@ class DesktopModeFlagsTest : ShellTestCase() {
  @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
  @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
  fun isEnabled_unrecognizableOverride_featureFlagOff_returnsFalse() {
    setOverride(-2)
    setOverride(INVALID_TOGGLE_OVERRIDE_SETTING)

    // For overridableFlag, for recognizable overrides, follow flag
    assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse()
@@ -187,102 +200,82 @@ class DesktopModeFlagsTest : ShellTestCase() {
  @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
  @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
  fun isEnabled_noSystemProperty_overrideOn_featureFlagOff_returnsTrueAndStoresPropertyOn() {
    System.clearProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)
    setSystemProperty(INVALID_TOGGLE_OVERRIDE_SETTING)
    setOverride(OVERRIDE_ON.setting)

    assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue()
    // Store System Property if not present
    assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY))
        .isEqualTo(OVERRIDE_ON.setting.toString())
    verifySystemPropertySet(OVERRIDE_ON.setting)
  }

  @Test
  @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
  fun isEnabled_noSystemProperty_overrideUnset_featureFlagOn_returnsTrueAndStoresPropertyUnset() {
    System.clearProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)
    setSystemProperty(INVALID_TOGGLE_OVERRIDE_SETTING)
    setOverride(OVERRIDE_UNSET.setting)

    assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue()
    // Store System Property if not present
    assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY))
        .isEqualTo(OVERRIDE_UNSET.setting.toString())
    verifySystemPropertySet(OVERRIDE_UNSET.setting)
  }

  @Test
  @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
  @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
  fun isEnabled_noSystemProperty_overrideUnset_featureFlagOff_returnsFalseAndStoresPropertyUnset() {
    System.clearProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)
    setSystemProperty(INVALID_TOGGLE_OVERRIDE_SETTING)
    setOverride(OVERRIDE_UNSET.setting)

    assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse()
    // Store System Property if not present
    assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY))
        .isEqualTo(OVERRIDE_UNSET.setting.toString())
  }

  @Test
  @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
  @Suppress("ktlint:standard:max-line-length")
  fun isEnabled_systemPropertyNotInteger_overrideOff_featureFlagOn_returnsFalseAndStoresPropertyOff() {
    System.setProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, "abc")
    setOverride(OVERRIDE_OFF.setting)

    assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse()
    // Store System Property if currently invalid
    assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY))
        .isEqualTo(OVERRIDE_OFF.setting.toString())
    verifySystemPropertySet(OVERRIDE_UNSET.setting)
  }

  @Test
  @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
  @Suppress("ktlint:standard:max-line-length")
  fun isEnabled_systemPropertyInvalidInteger_overrideOff_featureFlagOn_returnsFalseAndStoresPropertyOff() {
    System.setProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, "-2")
    setSystemProperty(INVALID_TOGGLE_OVERRIDE_SETTING)
    setOverride(OVERRIDE_OFF.setting)

    assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse()
    // Store System Property if currently invalid
    assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY))
        .isEqualTo(OVERRIDE_OFF.setting.toString())
    verifySystemPropertySet(OVERRIDE_OFF.setting)
  }

  @Test
  @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
  fun isEnabled_systemPropertyOff_overrideOn_featureFlagOn_returnsFalseAndDoesNotUpdateProperty() {
    System.setProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, OVERRIDE_OFF.setting.toString())
    setSystemProperty(OVERRIDE_OFF.setting)
    setOverride(OVERRIDE_ON.setting)

    // Have a consistent override until reboot
    assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse()
    assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY))
        .isEqualTo(OVERRIDE_OFF.setting.toString())
    verifySystemPropertyNotUpdated()
  }

  @Test
  @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
  @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
  fun isEnabled_systemPropertyOn_overrideOff_featureFlagOff_returnsTrueAndDoesNotUpdateProperty() {
    System.setProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, OVERRIDE_ON.setting.toString())
    setSystemProperty(OVERRIDE_ON.setting)
    setOverride(OVERRIDE_OFF.setting)

    // Have a consistent override until reboot
    assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue()
    assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY))
        .isEqualTo(OVERRIDE_ON.setting.toString())
    verifySystemPropertyNotUpdated()
  }

  @Test
  @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
  @Suppress("ktlint:standard:max-line-length")
  fun isEnabled_systemPropertyUnset_overrideOff_featureFlagOn_returnsTrueAndDoesNotUpdateProperty() {
    System.setProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, OVERRIDE_UNSET.setting.toString())
    setSystemProperty(OVERRIDE_UNSET.setting)
    setOverride(OVERRIDE_OFF.setting)

    // Have a consistent override until reboot
    assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue()
    assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY))
        .isEqualTo(OVERRIDE_UNSET.setting.toString())
    verifySystemPropertyNotUpdated()
  }

  @Test
@@ -441,16 +434,33 @@ class DesktopModeFlagsTest : ShellTestCase() {
  }

  private fun resetCache() {
    val cachedToggleOverride =
      DesktopModeFlags::class.java.getDeclaredField("cachedToggleOverride")
    val cachedToggleOverride = DesktopModeFlags::class.java.getDeclaredField("cachedToggleOverride")
    cachedToggleOverride.isAccessible = true
    cachedToggleOverride.set(null, null)

    // Clear override cache stored in System property
    System.clearProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)
    setSystemProperty(INVALID_TOGGLE_OVERRIDE_SETTING)
  }

  private fun setSystemProperty(systemProperty: Int) {
    ExtendedMockito.doReturn(systemProperty).`when` {
      SystemProperties.getInt(eq(SYSTEM_PROPERTY_OVERRIDE_KEY), any())
    }
  }

  private fun verifySystemPropertySet(systemProperty: Int) {
    ExtendedMockito.verify {
      SystemProperties.set(eq(SYSTEM_PROPERTY_OVERRIDE_KEY), eq(systemProperty.toString()))
    }
  }

  private fun verifySystemPropertyNotUpdated() {
    ExtendedMockito.verify(
        { SystemProperties.set(eq(SYSTEM_PROPERTY_OVERRIDE_KEY), any()) }, Mockito.never())
  }

  private companion object {
    const val SYSTEM_PROPERTY_OVERRIDE_KEY = "sys.wmshell.desktopmode.dev_toggle_override"

    const val INVALID_TOGGLE_OVERRIDE_SETTING = -2
  }
}
+32 −37
Original line number Diff line number Diff line
@@ -18,8 +18,8 @@ package com.android.server.wm.utils;

import static com.android.server.wm.utils.DesktopModeFlagsUtil.ToggleOverride.OVERRIDE_UNSET;

import android.annotation.Nullable;
import android.content.Context;
import android.os.SystemProperties;
import android.provider.Settings;
import android.util.Log;

@@ -29,14 +29,12 @@ import java.util.function.Supplier;

/**
 * Util to check desktop mode flags state.
 *
 * This utility is used to allow developer option toggles to override flags related to desktop
 * <p> This utility is used to allow developer option toggles to override flags related to desktop
 * windowing.
 *
 * Computes whether Desktop Windowing related flags should be enabled by using the aconfig flag
 * <p> Computes whether Desktop Windowing related flags should be enabled by using the aconfig flag
 * value and the developer option override state (if applicable).
 *
 * This is a partial copy of {@link com.android.wm.shell.shared.desktopmode.DesktopModeFlags} which
 * <p> This is a partial copy of {@link com.android.wm.shell.shared.desktopmode.DesktopModeFlags}
 * which
 * is to be used in WM core.
 */
public enum DesktopModeFlagsUtil {
@@ -97,7 +95,7 @@ public enum DesktopModeFlagsUtil {
        // Otherwise, fetch and cache it
        ToggleOverride override = getToggleOverrideFromSystem(context);
        sCachedToggleOverride = override;
        Log.d(TAG, "Toggle override initialized to: " + override);
        Log.d(TAG, "Local Toggle override initialized to: " + override);
        return override;
    }

@@ -108,43 +106,40 @@ public enum DesktopModeFlagsUtil {
    private ToggleOverride getToggleOverrideFromSystem(Context context) {
        // A non-persistent System Property is used to store override to ensure it remains
        // constant till reboot.
        String overrideProperty = System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, null);
        ToggleOverride overrideFromSystemProperties = convertToToggleOverride(overrideProperty);
        int overrideProperty = SystemProperties.getInt(SYSTEM_PROPERTY_OVERRIDE_KEY, -2);
        ToggleOverride overrideFromSystemProperties = ToggleOverride.fromSetting(overrideProperty,
                null);

        // Initialize System Property if not present (just after reboot)
        if (overrideFromSystemProperties == null) {
            return initializeOverrideInSystemProperty(context);
        }

        // If valid system property, return it
        if (overrideFromSystemProperties != null) {
        return overrideFromSystemProperties;
    }

        // Fallback when System Property is not present (just after reboot) or not valid (user
        // manually changed the value): Read from Settings.Global
    /**
     * Initializes Override System property based on Settings.Global set by toggle.
     */
    // TODO(b/348193756): Make this method public, and call it in WindowManagerService constructor
    //  to ensure initialization.
    private static ToggleOverride initializeOverrideInSystemProperty(Context context) {
        int settingValue = Settings.Global.getInt(
                context.getContentResolver(),
                Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES,
                OVERRIDE_UNSET.getSetting()
        );
        ToggleOverride overrideFromSettingsGlobal =
                ToggleOverride.fromSetting(settingValue, OVERRIDE_UNSET);
        // Initialize System Property
        System.setProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, String.valueOf(settingValue));
        return overrideFromSettingsGlobal;
    }

    /**
     * Converts {@code intString} into {@link ToggleOverride}. Return {@code null} if
     * {@code intString} does not correspond to a {@link ToggleOverride}.
     */
    private static @Nullable ToggleOverride convertToToggleOverride(
            @Nullable String intString
    ) {
        if (intString == null) return null;
        try {
            int intValue = Integer.parseInt(intString);
            return ToggleOverride.fromSetting(intValue, null);
        } catch (NumberFormatException e) {
            Log.w(TAG, "Unknown toggleOverride int " + intString);
            return null;
            SystemProperties.set(SYSTEM_PROPERTY_OVERRIDE_KEY, String.valueOf(settingValue));
            Log.d(TAG, "Initialize system property with override setting: " + settingValue);
        } catch (RuntimeException e) {
            // Thrown in device tests that don't mock SystemProperties
            Log.w(TAG, "Failed to set a system property: key=" + SYSTEM_PROPERTY_OVERRIDE_KEY
                    + " value=" + settingValue + " " + e.getMessage());
        }

        return ToggleOverride.fromSetting(settingValue, OVERRIDE_UNSET);
    }

    /** Override state of desktop mode developer option toggle. */
@@ -161,7 +156,7 @@ public enum DesktopModeFlagsUtil {
            };
        }

        static ToggleOverride fromSetting(int setting, @Nullable ToggleOverride fallback) {
        static ToggleOverride fromSetting(int setting, ToggleOverride fallback) {
            return switch (setting) {
                case 1 -> OVERRIDE_ON;
                case 0 -> OVERRIDE_OFF;
+2 −0
Original line number Diff line number Diff line
@@ -68,6 +68,7 @@ import android.os.PowerManager;
import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
import android.os.StrictMode;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.DeviceConfig;
@@ -204,6 +205,7 @@ public class SystemServicesTestRule implements TestRule {
                .mockStatic(Watchdog.class, mockStubOnly)
                .spyStatic(DesktopModeHelper.class)
                .spyStatic(DesktopModeBoundsCalculator.class)
                .spyStatic(SystemProperties.class)
                .strictness(Strictness.LENIENT)
                .startMocking();

+51 −51

File changed.

Preview size limit exceeded, changes collapsed.