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

Commit efaa814a authored by Lucas Dupin's avatar Lucas Dupin
Browse files

Don't allow background apps to change theme

A background app that changes the wallpaper, was able to change the
device theme.

This change will apply the theme if the app is on the foreground, like
WallpaperPicker would be, but would defer the event until the next power
button cycles, like we do with Live Wallpapers, to avoid the same type
of DoS.

Test: manual
Test: atest ThemeOverlayControllerTest
Fixes: 205140487
Change-Id: I2086b29ef9bf3bb6fb7d9ebba6e7b8db9392e459
Merged-In: I2086b29ef9bf3bb6fb7d9ebba6e7b8db9392e459
parent 2a14be36
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -226,6 +226,14 @@ public class WallpaperManager {
     */
    public static final String EXTRA_NEW_WALLPAPER_ID = "android.service.wallpaper.extra.ID";

    /**
     * Extra passed on {@link Intent.ACTION_WALLPAPER_CHANGED} indicating if wallpaper was set from
     * a foreground app.
     * @hide
     */
    public static final String EXTRA_FROM_FOREGROUND_APP =
            "android.service.wallpaper.extra.FROM_FOREGROUND_APP";

    // flags for which kind of wallpaper to act on

    /** @hide */
+7 −2
Original line number Diff line number Diff line
@@ -253,8 +253,13 @@ public class ThemeOverlayController extends SystemUI implements Dumpable {
                if (DEBUG) Log.d(TAG, "Updating overlays for user switch / profile added.");
                reevaluateSystemTheme(true /* forceReload */);
            } else if (Intent.ACTION_WALLPAPER_CHANGED.equals(intent.getAction())) {
                if (intent.getBooleanExtra(WallpaperManager.EXTRA_FROM_FOREGROUND_APP, false)) {
                    mAcceptColorEvents = true;
                Log.i(TAG, "Allowing color events again");
                    Log.i(TAG, "Wallpaper changed, allowing color events again");
                } else {
                    Log.i(TAG, "Wallpaper changed from background app, "
                            + "keep deferring color events. Accepting: " + mAcceptColorEvents);
                }
            }
        }
    };
+35 −3
Original line number Diff line number Diff line
@@ -152,7 +152,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
    }

    @Test
    public void onWallpaperColorsChanged_setsTheme() {
    public void onWallpaperColorsChanged_setsTheme_whenForeground() {
        // Should ask for a new theme when wallpaper colors change
        WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
                Color.valueOf(Color.BLUE), null);
@@ -180,12 +180,42 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {

        // But should change theme after changing wallpapers
        clearInvocations(mThemeOverlayApplier);
        mBroadcastReceiver.getValue().onReceive(null, new Intent(Intent.ACTION_WALLPAPER_CHANGED));
        Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED);
        intent.putExtra(WallpaperManager.EXTRA_FROM_FOREGROUND_APP, true);
        mBroadcastReceiver.getValue().onReceive(null, intent);
        mColorsListener.getValue().onColorsChanged(new WallpaperColors(Color.valueOf(Color.BLACK),
                null, null), WallpaperManager.FLAG_SYSTEM);
        verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any());
    }

    @Test
    public void onWallpaperColorsChanged_setsTheme_skipWhenBackground() {
        // Should ask for a new theme when wallpaper colors change
        WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
                Color.valueOf(Color.BLUE), null);
        mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
        ArgumentCaptor<Map<String, OverlayIdentifier>> themeOverlays =
                ArgumentCaptor.forClass(Map.class);

        verify(mThemeOverlayApplier)
                .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any());

        // Assert that we received the colors that we were expecting
        assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE))
                .isEqualTo(new OverlayIdentifier("ffff0000"));
        assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_ACCENT_COLOR))
                .isEqualTo(new OverlayIdentifier("ffff0000"));

        // Should not change theme after changing wallpapers, if intent doesn't have
        // WallpaperManager.EXTRA_FROM_FOREGROUND_APP set to true.
        clearInvocations(mThemeOverlayApplier);
        mBroadcastReceiver.getValue().onReceive(null, new Intent(Intent.ACTION_WALLPAPER_CHANGED));
        mColorsListener.getValue().onColorsChanged(new WallpaperColors(Color.valueOf(Color.BLACK),
                null, null), WallpaperManager.FLAG_SYSTEM);
        verify(mThemeOverlayApplier, never())
                .applyCurrentUserOverlays(any(), any(), anyInt(), any());
    }

    @Test
    public void onWallpaperColorsChanged_preservesWallpaperPickerTheme() {
        // Should ask for a new theme when wallpaper colors change
@@ -455,7 +485,9 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
        // Regression test: null events should not reset the internal state and allow colors to be
        // applied again.
        clearInvocations(mThemeOverlayApplier);
        mBroadcastReceiver.getValue().onReceive(null, new Intent(Intent.ACTION_WALLPAPER_CHANGED));
        Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED);
        intent.putExtra(WallpaperManager.EXTRA_FROM_FOREGROUND_APP, true);
        mBroadcastReceiver.getValue().onReceive(null, intent);
        mColorsListener.getValue().onColorsChanged(null, WallpaperManager.FLAG_SYSTEM);
        verify(mThemeOverlayApplier, never()).applyCurrentUserOverlays(any(), any(), anyInt(),
                any());
+13 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.wallpaper;

import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
import static android.app.WallpaperManager.COMMAND_REAPPLY;
import static android.app.WallpaperManager.FLAG_LOCK;
import static android.app.WallpaperManager.FLAG_SYSTEM;
@@ -775,6 +776,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
    private final Context mContext;
    private final WindowManagerInternal mWindowManagerInternal;
    private final IPackageManager mIPackageManager;
    private final ActivityManager mActivityManager;
    private final MyPackageMonitor mMonitor;
    private final AppOpsManager mAppOpsManager;

@@ -923,6 +925,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
         */
        WallpaperColors primaryColors;

        /**
         * If the wallpaper was set from a foreground app (instead of from a background service).
         */
        public boolean fromForegroundApp;

        WallpaperConnection connection;
        long lastDiedTime;
        boolean wallpaperUpdating;
@@ -1672,6 +1679,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
        mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
        mDisplayManager = mContext.getSystemService(DisplayManager.class);
        mDisplayManager.registerDisplayListener(mDisplayListener, null /* handler */);
        mActivityManager = mContext.getSystemService(ActivityManager.class);
        mMonitor = new MyPackageMonitor();
        mColorsChangedListeners = new SparseArray<>();

@@ -2613,6 +2621,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
            }
        }

        final boolean fromForegroundApp = Binder.withCleanCallingIdentity(() ->
                mActivityManager.getPackageImportance(callingPackage) == IMPORTANCE_FOREGROUND);

        synchronized (mLock) {
            if (DEBUG) Slog.v(TAG, "setWallpaper which=0x" + Integer.toHexString(which));
            WallpaperData wallpaper;
@@ -2635,6 +2646,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
                    wallpaper.imageWallpaperPending = true;
                    wallpaper.whichPending = which;
                    wallpaper.setComplete = completion;
                    wallpaper.fromForegroundApp = fromForegroundApp;
                    wallpaper.cropHint.set(cropHint);
                    wallpaper.allowBackup = allowBackup;
                }
@@ -3017,6 +3029,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
        wallpaper.callbacks.finishBroadcast();

        final Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED);
        intent.putExtra(WallpaperManager.EXTRA_FROM_FOREGROUND_APP, wallpaper.fromForegroundApp);
        mContext.sendBroadcastAsUser(intent, new UserHandle(mCurrentUserId));
    }