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

Commit 22d69a14 authored by Biswarup Pal's avatar Biswarup Pal
Browse files

Prevent crash in CoreSettingsObserver

When any setting changes, CoreSettingsObserver enumerates all
virtual devices and fetches the setting value for every virtual
device id (by creating an explicit device context and calling
Settings#getString with that context). However, by the time it
calls Context#createDeviceContext with a device id, it is possible
(though rare) that the virtual device is gone. This CL handles that
exception and skips the fetching of settings for any invalid device
id.

Test: atest CoreSettingsObserverTest
Fixes: 425014464
Flag: android.companion.virtualdevice.flags.device_aware_settings_override
Change-Id: I0a39d4208fef0d4cfe46a2c487ffc27a14ccdd57
parent 100f285b
Loading
Loading
Loading
Loading
+19 −7
Original line number Original line Diff line number Diff line
@@ -27,6 +27,7 @@ import android.net.Uri;
import android.os.Bundle;
import android.os.Bundle;
import android.provider.DeviceConfig;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.provider.Settings;
import android.util.Slog;
import android.widget.WidgetFlags;
import android.widget.WidgetFlags;


import com.android.internal.R;
import com.android.internal.R;
@@ -47,6 +48,8 @@ import java.util.Objects;
 */
 */
final class CoreSettingsObserver extends ContentObserver {
final class CoreSettingsObserver extends ContentObserver {


    private static final String TAG = "CoreSettingsObserver";

    private static class DeviceConfigEntry<T> {
    private static class DeviceConfigEntry<T> {
        String namespace;
        String namespace;
        String flag;
        String flag;
@@ -232,16 +235,25 @@ final class CoreSettingsObserver extends ContentObserver {
            deviceIds.add(Context.DEVICE_ID_DEFAULT);
            deviceIds.add(Context.DEVICE_ID_DEFAULT);
            for (int deviceId : deviceIds) {
            for (int deviceId : deviceIds) {
                final Bundle deviceBundle = new Bundle();
                final Bundle deviceBundle = new Bundle();
                final Context deviceContext = context.createDeviceContext(deviceId);
                Context deviceContext = null;
                try {
                    deviceContext = context.createDeviceContext(deviceId);
                } catch (IllegalArgumentException e) {
                    Slog.w(TAG, "Exception during Context#createDeviceContext", e);
                }

                if (deviceContext != null) {
                    populateSettings(deviceContext, deviceBundle, sSecureSettingToTypeMap);
                    populateSettings(deviceContext, deviceBundle, sSecureSettingToTypeMap);
                    populateSettings(deviceContext, deviceBundle, sSystemSettingToTypeMap);
                    populateSettings(deviceContext, deviceBundle, sSystemSettingToTypeMap);


                // Copy global settings and device config values, as they don't vary across devices.
                    // Copy global settings and device config values, as they don't vary across
                    // devices.
                    deviceBundle.putAll(globalSettingsBundle);
                    deviceBundle.putAll(globalSettingsBundle);
                    deviceBundle.putAll(deviceConfigBundle);
                    deviceBundle.putAll(deviceConfigBundle);


                    mCoreSettings.putBundle(String.valueOf(deviceId), deviceBundle);
                    mCoreSettings.putBundle(String.valueOf(deviceId), deviceBundle);
                }
                }
            }
        } else {
        } else {
            populateSettings(context, mCoreSettings, sSecureSettingToTypeMap);
            populateSettings(context, mCoreSettings, sSecureSettingToTypeMap);
            populateSettings(context, mCoreSettings, sSystemSettingToTypeMap);
            populateSettings(context, mCoreSettings, sSystemSettingToTypeMap);
+17 −8
Original line number Original line Diff line number Diff line
@@ -34,10 +34,9 @@ import android.content.res.TypedArray;
import android.os.Bundle;
import android.os.Bundle;
import android.os.Handler;
import android.os.Handler;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.provider.Settings;
import android.provider.Settings;
import android.test.mock.MockContentResolver;
import android.test.mock.MockContentResolver;
import android.virtualdevice.cts.common.VirtualDeviceRule;


import androidx.test.filters.SmallTest;
import androidx.test.filters.SmallTest;


@@ -69,13 +68,16 @@ public class CoreSettingsObserverTest {
    private static final float TEST_FLOAT = 3.14f;
    private static final float TEST_FLOAT = 3.14f;
    private static final String TEST_STRING = "testString";
    private static final String TEST_STRING = "testString";


    @Rule public ServiceThreadRule mServiceThreadRule = new ServiceThreadRule();
    @Rule
    @Rule public final CheckFlagsRule checkFlagsRule =
    public ServiceThreadRule mServiceThreadRule = new ServiceThreadRule();
            DeviceFlagsValueProvider.createCheckFlagsRule();
    @Rule
    public final VirtualDeviceRule mVirtualDeviceRule = VirtualDeviceRule.createDefault();


    private ActivityManagerService mAms;
    private ActivityManagerService mAms;
    @Mock private Context mContext;
    @Mock
    @Mock private Resources mResources;
    private Context mContext;
    @Mock
    private Resources mResources;


    private MockContentResolver mContentResolver;
    private MockContentResolver mContentResolver;
    private CoreSettingsObserver mCoreSettingsObserver;
    private CoreSettingsObserver mCoreSettingsObserver;
@@ -171,6 +173,13 @@ public class CoreSettingsObserverTest {
                TEST_STRING, settingsBundle.getString(TEST_SETTING_SYSTEM_STRING));
                TEST_STRING, settingsBundle.getString(TEST_SETTING_SYSTEM_STRING));
    }
    }


    @Test
    public void testPopulateSettings_withInvalidDeviceId() {
        mVirtualDeviceRule.createManagedVirtualDevice();
        when(mContext.createDeviceContext(anyInt())).thenThrow(new IllegalArgumentException());
        testPopulateSettings();
    }

    private Bundle getPopulatedBundle() {
    private Bundle getPopulatedBundle() {
        mCoreSettingsObserver.onChange(false);
        mCoreSettingsObserver.onChange(false);
        return mCoreSettingsObserver.getCoreSettingsLocked().getBundle(
        return mCoreSettingsObserver.getCoreSettingsLocked().getBundle(