diff options
| author | 2024-10-31 15:05:35 +0000 | |
|---|---|---|
| committer | 2024-11-05 18:11:21 +0000 | |
| commit | fd0184f144e6e660fbbde06c62d57db22af5b39b (patch) | |
| tree | 3d358571f261e5149e1b121d77d90910e72ba30f | |
| parent | 5eb9df5102c8d8ea01c0d3d80ae3201b3710a3f5 (diff) | |
Fix multiuser race in FeatureFlagsClassicDebug constructor.
Under HSUM, the constructor may be called while the system is still
running as user 0. In this case, we register the iGET_FLAGS receiver
under user 0. However, the flippin app runs as user 10 so will then
see an empty response to it's GET_FLAGS ordered broadcast and crash.
This change installs a callback to capture the system switching
from user 0 to user 10 (or indeed, any subsequent user switch) and
ensure re-registers the receiver so it's running in the correct user.
Bug: 345443431
Flag: com.android.systemui.classic_flags_multi_user
Test: Manually verified; atest -c com.android.systemui.flags.FeatureFlagsClassicDebugTest
Change-Id: If8b5273963e67ab23fb10a9ad930fa9fa7b09590
2 files changed, 43 insertions, 14 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/flags/FeatureFlagsClassicDebugTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/flags/FeatureFlagsClassicDebugTest.kt index 3388a785a26a..20cd8608d204 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/flags/FeatureFlagsClassicDebugTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/flags/FeatureFlagsClassicDebugTest.kt @@ -28,11 +28,13 @@ import androidx.test.filters.SmallTest import com.android.systemui.Flags.FLAG_SYSUI_TEAMFOOD import com.android.systemui.SysuiTestCase import com.android.systemui.settings.FakeUserTracker +import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.nullable import com.android.systemui.util.mockito.withArgCaptor import com.android.systemui.util.settings.GlobalSettings +import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth.assertThat import java.io.PrintWriter import java.io.Serializable @@ -68,6 +70,7 @@ class FeatureFlagsClassicDebugTest : SysuiTestCase() { @Mock private lateinit var systemProperties: SystemPropertiesHelper @Mock private lateinit var resources: Resources @Mock private lateinit var restarter: Restarter + private lateinit var fakeExecutor: FakeExecutor private lateinit var userTracker: FakeUserTracker private val flagMap = mutableMapOf<String, Flag<*>>() private lateinit var broadcastReceiver: BroadcastReceiver @@ -83,6 +86,7 @@ class FeatureFlagsClassicDebugTest : SysuiTestCase() { flagMap.put(teamfoodableFlagA.name, teamfoodableFlagA) flagMap.put(releasedFlagB.name, releasedFlagB) + fakeExecutor = FakeExecutor(FakeSystemClock()) userTracker = FakeUserTracker(onCreateCurrentUserContext = { mockContext }) mFeatureFlagsClassicDebug = @@ -95,7 +99,8 @@ class FeatureFlagsClassicDebugTest : SysuiTestCase() { serverFlagReader, flagMap, restarter, - userTracker + userTracker, + fakeExecutor, ) mFeatureFlagsClassicDebug.init() verify(flagManager).onSettingsChangedAction = any() @@ -325,14 +330,14 @@ class FeatureFlagsClassicDebugTest : SysuiTestCase() { // trying to erase an id not in the map does nothing broadcastReceiver.onReceive( mockContext, - Intent(FlagManager.ACTION_SET_FLAG).putExtra(FlagManager.EXTRA_NAME, "") + Intent(FlagManager.ACTION_SET_FLAG).putExtra(FlagManager.EXTRA_NAME, ""), ) verifyNoMoreInteractions(flagManager, globalSettings) // valid id with no value puts empty string in the setting broadcastReceiver.onReceive( mockContext, - Intent(FlagManager.ACTION_SET_FLAG).putExtra(FlagManager.EXTRA_NAME, "1") + Intent(FlagManager.ACTION_SET_FLAG).putExtra(FlagManager.EXTRA_NAME, "1"), ) verifyPutData("1", "", numReads = 0) } @@ -415,7 +420,7 @@ class FeatureFlagsClassicDebugTest : SysuiTestCase() { serverFlagReader.setFlagValue( teamfoodableFlagA.namespace, teamfoodableFlagA.name, - !teamfoodableFlagA.default + !teamfoodableFlagA.default, ) verify(restarter, never()).restartSystemUI(anyString()) } @@ -428,7 +433,7 @@ class FeatureFlagsClassicDebugTest : SysuiTestCase() { serverFlagReader.setFlagValue( teamfoodableFlagA.namespace, teamfoodableFlagA.name, - !teamfoodableFlagA.default + !teamfoodableFlagA.default, ) verify(restarter).restartSystemUI(anyString()) } @@ -441,7 +446,7 @@ class FeatureFlagsClassicDebugTest : SysuiTestCase() { serverFlagReader.setFlagValue( teamfoodableFlagA.namespace, teamfoodableFlagA.name, - teamfoodableFlagA.default + teamfoodableFlagA.default, ) verify(restarter, never()).restartSystemUI(anyString()) } diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsClassicDebug.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsClassicDebug.java index 303f91688575..911331b8bff1 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsClassicDebug.java +++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsClassicDebug.java @@ -42,7 +42,7 @@ import androidx.annotation.Nullable; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.settings.UserContextProvider; +import com.android.systemui.settings.UserTracker; import com.android.systemui.util.settings.GlobalSettings; import java.io.PrintWriter; @@ -51,6 +51,7 @@ import java.util.Map; import java.util.Objects; import java.util.TreeMap; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; import java.util.function.Consumer; import javax.inject.Inject; @@ -74,7 +75,6 @@ public class FeatureFlagsClassicDebug implements FeatureFlagsClassic { static final String TAG = "SysUIFlags"; private final FlagManager mFlagManager; - private final Context mContext; private final GlobalSettings mGlobalSettings; private final Resources mResources; private final SystemPropertiesHelper mSystemProperties; @@ -84,6 +84,8 @@ public class FeatureFlagsClassicDebug implements FeatureFlagsClassic { private final Map<String, String> mStringFlagCache = new ConcurrentHashMap<>(); private final Map<String, Integer> mIntFlagCache = new ConcurrentHashMap<>(); private final Restarter mRestarter; + private final UserTracker mUserTracker; + private final Executor mMainExecutor; private final ServerFlagReader.ChangeListener mOnPropertiesChanged = new ServerFlagReader.ChangeListener() { @@ -118,6 +120,18 @@ public class FeatureFlagsClassicDebug implements FeatureFlagsClassic { } }; + private final UserTracker.Callback mUserChangedCallback = + new UserTracker.Callback() { + @Override + public void onUserChanged(int newUser, @NonNull Context userContext) { + mContext.unregisterReceiver(mReceiver); + mContext = userContext; + registerReceiver(); + } + }; + + private Context mContext; + @Inject public FeatureFlagsClassicDebug( FlagManager flagManager, @@ -128,10 +142,11 @@ public class FeatureFlagsClassicDebug implements FeatureFlagsClassic { ServerFlagReader serverFlagReader, @Named(ALL_FLAGS) Map<String, Flag<?>> allFlags, Restarter restarter, - UserContextProvider userContextProvider) { + UserTracker userTracker, + @Main Executor executor) { mFlagManager = flagManager; if (classicFlagsMultiUser()) { - mContext = userContextProvider.createCurrentUserContext(context); + mContext = userTracker.createCurrentUserContext(context); } else { mContext = context; } @@ -141,19 +156,28 @@ public class FeatureFlagsClassicDebug implements FeatureFlagsClassic { mServerFlagReader = serverFlagReader; mAllFlags = allFlags; mRestarter = restarter; + mUserTracker = userTracker; + mMainExecutor = executor; } /** Call after construction to setup listeners. */ void init() { - IntentFilter filter = new IntentFilter(); - filter.addAction(ACTION_SET_FLAG); - filter.addAction(ACTION_GET_FLAGS); mFlagManager.setOnSettingsChangedAction( suppressRestart -> restartSystemUI(suppressRestart, "Settings changed")); mFlagManager.setClearCacheAction(this::removeFromCache); + registerReceiver(); + if (classicFlagsMultiUser()) { + mUserTracker.addCallback(mUserChangedCallback, mMainExecutor); + } + mServerFlagReader.listenForChanges(mAllFlags.values(), mOnPropertiesChanged); + } + + void registerReceiver() { + IntentFilter filter = new IntentFilter(); + filter.addAction(ACTION_SET_FLAG); + filter.addAction(ACTION_GET_FLAGS); mContext.registerReceiver(mReceiver, filter, null, null, Context.RECEIVER_EXPORTED_UNAUDITED); - mServerFlagReader.listenForChanges(mAllFlags.values(), mOnPropertiesChanged); } @Override |