blob: f8c7447fc55d4d48bec754ebbeef5c739fa99e8a [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
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;
import java.util.Arrays;
import java.util.List;
/**
* Utilities for interacting with the {@link android.provider.DeviceConfig}.
*
* @hide
*/
public final class FlagNamespaceUtils {
/**
* Special String used for communicating through {@link #RESET_PLATFORM_PACKAGE_FLAG} that
* Settings were reset by the RescueParty, no actual namespace with this name exists in
* {@link DeviceConfig}.
*/
public static final String NAMESPACE_NO_PACKAGE = "no_package";
/**
* Name of the special namespace in DeviceConfig table used for communicating resets.
*/
@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}.
*/
@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.
*/
@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}
* when communicating recently reset by the RescueParty namespace values.
*/
private static final int MAX_COUNTER_VALUE = 50;
private static int sKnownResetNamespacesFlagCounter = -1;
/**
* Sets the union of {@link #RESET_PLATFORM_PACKAGE_FLAG} with
* {@link #sKnownResetNamespacesFlagCounter} in the DeviceConfig for each namespace
* in the consumed namespacesList. These flags are used for communicating the namespaces
* (aka platform packages) whose flags in {@link DeviceConfig} were just reset
* by the RescueParty.
*/
public static void addToKnownResetNamespaces(@Nullable List<String> namespacesList) {
if (namespacesList == null) {
return;
}
for (String namespace : namespacesList) {
addToKnownResetNamespaces(namespace);
}
}
/**
* Sets the union of {@link #RESET_PLATFORM_PACKAGE_FLAG} with
* {@link #sKnownResetNamespacesFlagCounter} in the DeviceConfig for the consumed namespace.
* This flag is used for communicating the namespace (aka platform package) whose flags
* in {@link DeviceConfig} were just reset by the RescueParty.
*/
public static void addToKnownResetNamespaces(String namespace) {
int nextFlagCounter = incrementAndRetrieveResetNamespacesFlagCounter();
DeviceConfig.setProperty(NAMESPACE_RESCUE_PARTY,
RESET_PLATFORM_PACKAGE_FLAG + nextFlagCounter,
namespace, /*makeDefault=*/ true);
}
/**
* Reset all namespaces in DeviceConfig with consumed resetMode.
*/
public static void resetDeviceConfig(int resetMode) {
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(namespacesList);
}
/**
* Resets known reset namespaces flag counter for tests only.
*/
@VisibleForTesting
public static void resetKnownResetNamespacesFlagCounterForTest() {
sKnownResetNamespacesFlagCounter = -1;
}
/**
* Returns a list of all known DeviceConfig namespaces, except for the special {@link
* #NAMESPACE_RESCUE_PARTY}
*/
private static List<String> getAllKnownDeviceConfigNamespacesList() {
String namespacesStr = DeviceConfig.getProperty(NAMESPACE_RESCUE_PARTY,
ALL_KNOWN_NAMESPACES_FLAG);
List<String> namespacesList = toStringList(namespacesStr);
namespacesList.remove(NAMESPACE_RESCUE_PARTY);
return namespacesList;
}
private static List<String> toStringList(String serialized) {
if (serialized == null || serialized.length() == 0) {
return new ArrayList<>();
}
return Arrays.asList(serialized.split(DELIMITER));
}
private static int incrementAndRetrieveResetNamespacesFlagCounter() {
sKnownResetNamespacesFlagCounter++;
if (sKnownResetNamespacesFlagCounter == MAX_COUNTER_VALUE) {
sKnownResetNamespacesFlagCounter = 0;
}
return sKnownResetNamespacesFlagCounter;
}
}