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

Commit 93075f45 authored by bpetrivs's avatar bpetrivs
Browse files

Add handling of NativeRescueParty resets to RescueParty.

Test: unit tests.

Change-Id: I60d1393d483fccae405ca69a6aaedea84e1a090e
parent bebec75d
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -38,9 +38,11 @@ import android.util.StatsLog;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.server.am.SettingsToPropertiesMapper;
import com.android.server.utils.FlagNamespaceUtils;

import java.io.File;
import java.util.Arrays;

/**
 * Utilities to help rescue the system from crash loops. Callers are expected to
@@ -158,6 +160,7 @@ public class RescueParty {
     * opportunity to reset any settings depending on our rescue level.
     */
    public static void onSettingsProviderPublished(Context context) {
        handleNativeRescuePartyResets();
        executeRescueLevel(context);
    }

@@ -176,6 +179,13 @@ public class RescueParty {
        return SystemClock.elapsedRealtime();
    }

    private static void handleNativeRescuePartyResets() {
        if (SettingsToPropertiesMapper.isNativeFlagsResetPerformed()) {
            FlagNamespaceUtils.resetDeviceConfig(Settings.RESET_MODE_TRUSTED_DEFAULTS,
                    Arrays.asList(SettingsToPropertiesMapper.getResetNativeCategories()));
        }
    }

    /**
     * Escalate to the next rescue level. After incrementing the level you'll
     * probably want to call {@link #executeRescueLevel(Context)}.
+2 −1
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.am;

import android.annotation.NonNull;
import android.content.ContentResolver;
import android.database.ContentObserver;
import android.net.Uri;
@@ -167,7 +168,7 @@ public class SettingsToPropertiesMapper {
     * booting.
     * @return
     */
    public static String[] getResetNativeCategories() {
    public static @NonNull String[] getResetNativeCategories() {
        if (!isNativeFlagsResetPerformed()) {
            return new String[0];
        }
+24 −6
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.server.utils;
import android.annotation.Nullable;
import android.provider.DeviceConfig;

import com.android.internal.annotations.VisibleForTesting;
import com.android.server.RescueParty;

import java.util.ArrayList;
@@ -41,20 +42,23 @@ public final class FlagNamespaceUtils {
    /**
     * Name of the special namespace in DeviceConfig table used for communicating resets.
     */
    private static final String NAMESPACE_RESCUE_PARTY = "rescue_party_namespace";
    @VisibleForTesting
    public static final String NAMESPACE_RESCUE_PARTY = "rescue_party_namespace";
    /**
     * Flag in the {@link DeviceConfig} in {@link #NAMESPACE_RESCUE_PARTY}, holding all known {@link
     * DeviceConfig} namespaces, as a {@link #DELIMITER} separated String. It's updated after the
     * first time flags are written to the new namespace in the {@link DeviceConfig}.
     */
    private static final String ALL_KNOWN_NAMESPACES_FLAG = "all_known_namespaces";
    @VisibleForTesting
    public static final String ALL_KNOWN_NAMESPACES_FLAG = "all_known_namespaces";
    /**
     * Flag in the {@link DeviceConfig} in {@link #NAMESPACE_RESCUE_PARTY} with integer counter
     * suffix added to it, holding {@link DeviceConfig} namespace value whose flags were recently
     * reset by the {@link RescueParty}. It's updated by {@link RescueParty} every time given
     * namespace flags are reset.
     */
    private static final String RESET_PLATFORM_PACKAGE_FLAG = "reset_platform_package";
    @VisibleForTesting
    public static final String RESET_PLATFORM_PACKAGE_FLAG = "reset_platform_package";
    private static final String DELIMITER = ":";
    /**
     * Maximum value of the counter used in combination with {@link #RESET_PLATFORM_PACKAGE_FLAG}
@@ -97,11 +101,25 @@ public final class FlagNamespaceUtils {
     * Reset all namespaces in DeviceConfig with consumed resetMode.
     */
    public static void resetDeviceConfig(int resetMode) {
        List<String> allKnownNamespaces = getAllKnownDeviceConfigNamespacesList();
        for (String namespace : allKnownNamespaces) {
        resetDeviceConfig(resetMode, getAllKnownDeviceConfigNamespacesList());
    }

    /**
     * Reset all consumed namespaces in DeviceConfig with consumed resetMode.
     */
    public static void resetDeviceConfig(int resetMode, List<String> namespacesList) {
        for (String namespace : namespacesList) {
            DeviceConfig.resetToDefaults(resetMode, namespace);
        }
        addToKnownResetNamespaces(allKnownNamespaces);
        addToKnownResetNamespaces(namespacesList);
    }

    /**
     * Resets known reset namespaces flag counter for tests only.
     */
    @VisibleForTesting
    public static void resetKnownResetNamespacesFlagCounterForTest() {
        sKnownResetNamespacesFlagCounter = -1;
    }

    /**
+42 −2
Original line number Diff line number Diff line
@@ -35,9 +35,12 @@ import android.content.Context;
import android.os.RecoverySystem;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.provider.Settings;

import com.android.dx.mockito.inline.extended.ExtendedMockito;
import com.android.server.am.SettingsToPropertiesMapper;
import com.android.server.utils.FlagNamespaceUtils;

import org.junit.After;
import org.junit.Before;
@@ -56,6 +59,10 @@ import java.util.HashMap;
public class RescuePartyTest {
    private static final int PERSISTENT_APP_UID = 12;
    private static final long CURRENT_NETWORK_TIME_MILLIS = 0L;
    private static final String FAKE_NATIVE_NAMESPACE1 = "native1";
    private static final String FAKE_NATIVE_NAMESPACE2 = "native2";
    private static final String[] FAKE_RESET_NATIVE_NAMESPACES =
            {FAKE_NATIVE_NAMESPACE1, FAKE_NATIVE_NAMESPACE2};

    private MockitoSession mSession;

@@ -73,9 +80,11 @@ public class RescuePartyTest {
                ExtendedMockito.mockitoSession().initMocks(
                        this)
                        .strictness(Strictness.LENIENT)
                        .spyStatic(DeviceConfig.class)
                        .spyStatic(SystemProperties.class)
                        .spyStatic(Settings.Global.class)
                        .spyStatic(Settings.Secure.class)
                        .spyStatic(SettingsToPropertiesMapper.class)
                        .spyStatic(RecoverySystem.class)
                        .spyStatic(RescueParty.class)
                        .startMocking();
@@ -121,8 +130,17 @@ public class RescuePartyTest {
                }
        ).when(() -> SystemProperties.getLong(anyString(), anyLong()));

        // Mock DeviceConfig
        doAnswer((Answer<Boolean>) invocationOnMock -> true)
                .when(() -> DeviceConfig.setProperty(anyString(), anyString(), anyString(),
                        anyBoolean()));
        doAnswer((Answer<Void>) invocationOnMock -> null)
                .when(() -> DeviceConfig.resetToDefaults(anyInt(), anyString()));


        doReturn(CURRENT_NETWORK_TIME_MILLIS).when(() -> RescueParty.getElapsedRealtime());
        RescueParty.resetAllThresholds();
        FlagNamespaceUtils.resetKnownResetNamespacesFlagCounterForTest();

        SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL,
                Integer.toString(RescueParty.LEVEL_NONE));
@@ -278,10 +296,32 @@ public class RescuePartyTest {
                SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
    }

    @Test
    public void testNativeRescuePartyResets() {
        doReturn(true).when(() -> SettingsToPropertiesMapper.isNativeFlagsResetPerformed());
        doReturn(FAKE_RESET_NATIVE_NAMESPACES).when(
                () -> SettingsToPropertiesMapper.getResetNativeCategories());

        RescueParty.onSettingsProviderPublished(mMockContext);

        verify(() -> DeviceConfig.resetToDefaults(Settings.RESET_MODE_TRUSTED_DEFAULTS,
                FAKE_NATIVE_NAMESPACE1));
        verify(() -> DeviceConfig.resetToDefaults(Settings.RESET_MODE_TRUSTED_DEFAULTS,
                FAKE_NATIVE_NAMESPACE2));

        ExtendedMockito.verify(
                () -> DeviceConfig.setProperty(FlagNamespaceUtils.NAMESPACE_RESCUE_PARTY,
                        FlagNamespaceUtils.RESET_PLATFORM_PACKAGE_FLAG + 0,
                        FAKE_NATIVE_NAMESPACE1, /*makeDefault=*/true));
        ExtendedMockito.verify(
                () -> DeviceConfig.setProperty(FlagNamespaceUtils.NAMESPACE_RESCUE_PARTY,
                        FlagNamespaceUtils.RESET_PLATFORM_PACKAGE_FLAG + 1,
                        FAKE_NATIVE_NAMESPACE2, /*makeDefault=*/true));
    }

    private void verifySettingsResets(int resetMode) {
        verify(() -> Settings.Global.resetToDefaultsAsUser(mMockContentResolver, null,
                resetMode,
                UserHandle.USER_SYSTEM));
                resetMode, UserHandle.USER_SYSTEM));
        verify(() -> Settings.Secure.resetToDefaultsAsUser(eq(mMockContentResolver), isNull(),
                eq(resetMode), anyInt()));
    }