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

Commit 7d3033b1 authored by Annie Meng's avatar Annie Meng
Browse files

DO NOT MERGE Create a key value settings observer for backup parameters

Extracts an abstract class to observe changes in backup parameter settings that
are stored as a comma-separated key value list. This class is
responsible for registering and unregistering a content observer on the
setting and updating local references to the parameters.

Refactor BackupManagerConstants and LocalTransportParameters to use this
implementation. This will also be used for the new backup timeout
setting.

Bug: 74346317
Test: 1) m -j RunFrameworksServicesRoboTests ROBOTEST_FILTER=BackupManagerConstantsTest
2) gts-tradefed run commandAndExit gts-dev -m GtsBackupHostTestCases -t com.google.android.gts.backup.TransportFlagsHostSideTest

Change-Id: Id4c50fbcf7479c925515887e3fa70e166dd9955c
parent fd95ca6d
Loading
Loading
Loading
Loading
+97 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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 android.util;

import android.content.ContentResolver;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;

/**
 * Abstract class for observing changes to a specified setting stored as a comma-separated key value
 * list of parameters. Registers and unregisters a {@link ContentObserver} and handles updates when
 * the setting changes.
 *
 * <p>Subclasses should pass in the relevant setting's {@link Uri} in the constructor and implement
 * {@link #update(KeyValueListParser)} to receive updates when the value changes.
 * Calls to {@link #update(KeyValueListParser)} only trigger after calling {@link
 * #start()}.
 *
 * <p>To get the most up-to-date parameter values, first call {@link #start()} before accessing the
 * values to start observing changes, and then call {@link #stop()} once finished.
 *
 * @hide
 */
public abstract class KeyValueSettingObserver {
    private static final String TAG = "KeyValueSettingObserver";

    private final KeyValueListParser mParser = new KeyValueListParser(',');

    private final ContentObserver mObserver;
    private final ContentResolver mResolver;
    private final Uri mSettingUri;

    public KeyValueSettingObserver(Handler handler, ContentResolver resolver,
            Uri uri) {
        mObserver = new SettingObserver(handler);
        mResolver = resolver;
        mSettingUri = uri;
    }

    /** Starts observing changes for the setting. Pair with {@link #stop()}. */
    public void start() {
        mResolver.registerContentObserver(mSettingUri, false, mObserver);
        setParserValue();
        update(mParser);
    }

    /** Stops observing changes for the setting. */
    public void stop() {
        mResolver.unregisterContentObserver(mObserver);
    }

    /**
     * Returns the {@link String} representation of the setting. Subclasses should implement this
     * for their setting.
     */
    public abstract String getSettingValue(ContentResolver resolver);

    /** Updates the parser with the current setting value. */
    private void setParserValue() {
        String setting = getSettingValue(mResolver);
        try {
            mParser.setString(setting);
        } catch (IllegalArgumentException e) {
            Slog.e(TAG, "Malformed setting: " + setting);
        }
    }

    /** Subclasses should implement this to update references to their parameters. */
    public abstract void update(KeyValueListParser parser);

    private class SettingObserver extends ContentObserver {
        private SettingObserver(Handler handler) {
            super(handler);
        }

        @Override
        public void onChange(boolean selfChange) {
            setParserValue();
            update(mParser);
        }
    }
}
+7 −37
Original line number Diff line number Diff line
@@ -16,62 +16,32 @@

package com.android.internal.backup;

import android.util.KeyValueSettingObserver;
import android.content.ContentResolver;
import android.database.ContentObserver;
import android.os.Handler;
import android.provider.Settings;
import android.util.KeyValueListParser;
import android.util.Slog;

class LocalTransportParameters {
class LocalTransportParameters extends KeyValueSettingObserver {
    private static final String TAG = "LocalTransportParams";
    private static final String SETTING = Settings.Secure.BACKUP_LOCAL_TRANSPORT_PARAMETERS;
    private static final String KEY_FAKE_ENCRYPTION_FLAG = "fake_encryption_flag";

    private final KeyValueListParser mParser = new KeyValueListParser(',');
    private final ContentObserver mObserver;
    private final ContentResolver mResolver;
    private boolean mFakeEncryptionFlag;

    LocalTransportParameters(Handler handler, ContentResolver resolver) {
        mObserver = new Observer(handler);
        mResolver = resolver;
    }

    /** Observes for changes in the setting. This method MUST be paired with {@link #stop()}. */
    void start() {
        mResolver.registerContentObserver(Settings.Secure.getUriFor(SETTING), false, mObserver);
        update();
    }

    /** Stop observing for changes in the setting. */
    void stop() {
        mResolver.unregisterContentObserver(mObserver);
        super(handler, resolver, Settings.Secure.getUriFor(SETTING));
    }

    boolean isFakeEncryptionFlag() {
        return mFakeEncryptionFlag;
    }

    private void update() {
        String parameters = "";
        try {
            parameters = Settings.Secure.getString(mResolver, SETTING);
        } catch (IllegalArgumentException e) {
            Slog.e(TAG, "Malformed " + SETTING + " setting: " + e.getMessage());
        }
        mParser.setString(parameters);
        mFakeEncryptionFlag = mParser.getBoolean(KEY_FAKE_ENCRYPTION_FLAG, false);
    }

    private class Observer extends ContentObserver {
        private Observer(Handler handler) {
            super(handler);
    public String getSettingValue(ContentResolver resolver) {
        return Settings.Secure.getString(resolver, SETTING);
    }

        @Override
        public void onChange(boolean selfChange) {
            update();
        }
    public void update(KeyValueListParser parser) {
        mFakeEncryptionFlag = parser.getBoolean(KEY_FAKE_ENCRYPTION_FLAG, false);
    }
}
+110 −78
Original line number Diff line number Diff line
@@ -18,53 +18,76 @@ package com.android.server.backup;

import android.app.AlarmManager;
import android.content.ContentResolver;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.KeyValueListParser;
import android.util.KeyValueSettingObserver;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;

/**
 * Class to access backup manager constants.
 *
 * The backup manager constants are encoded as a key value list separated by commas
 * and stored as a Settings.Secure.
 * <p>The backup manager constants are encoded as a key value list separated by commas and stored as
 * a Settings.Secure.
 */
class BackupManagerConstants extends ContentObserver {
class BackupManagerConstants extends KeyValueSettingObserver {
    private static final String TAG = "BackupManagerConstants";
    private static final String SETTING = Settings.Secure.BACKUP_MANAGER_CONSTANTS;

    // Key names stored in the secure settings value.
    private static final String KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS =
    @VisibleForTesting
    public static final String KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS =
            "key_value_backup_interval_milliseconds";
    private static final String KEY_VALUE_BACKUP_FUZZ_MILLISECONDS =

    @VisibleForTesting
    public static final String KEY_VALUE_BACKUP_FUZZ_MILLISECONDS =
            "key_value_backup_fuzz_milliseconds";
    private static final String KEY_VALUE_BACKUP_REQUIRE_CHARGING =

    @VisibleForTesting
    public static final String KEY_VALUE_BACKUP_REQUIRE_CHARGING =
            "key_value_backup_require_charging";
    private static final String KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE =

    @VisibleForTesting
    public static final String KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE =
            "key_value_backup_required_network_type";
    private static final String FULL_BACKUP_INTERVAL_MILLISECONDS =

    @VisibleForTesting
    public static final String FULL_BACKUP_INTERVAL_MILLISECONDS =
            "full_backup_interval_milliseconds";
    private static final String FULL_BACKUP_REQUIRE_CHARGING =
            "full_backup_require_charging";
    private static final String FULL_BACKUP_REQUIRED_NETWORK_TYPE =

    @VisibleForTesting
    public static final String FULL_BACKUP_REQUIRE_CHARGING = "full_backup_require_charging";

    @VisibleForTesting
    public static final String FULL_BACKUP_REQUIRED_NETWORK_TYPE =
            "full_backup_required_network_type";
    private static final String BACKUP_FINISHED_NOTIFICATION_RECEIVERS =

    @VisibleForTesting
    public static final String BACKUP_FINISHED_NOTIFICATION_RECEIVERS =
            "backup_finished_notification_receivers";

    // Hard coded default values.
    private static final long DEFAULT_KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS =
    @VisibleForTesting
    public static final long DEFAULT_KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS =
            4 * AlarmManager.INTERVAL_HOUR;
    private static final long DEFAULT_KEY_VALUE_BACKUP_FUZZ_MILLISECONDS =
            10 * 60 * 1000;
    private static final boolean DEFAULT_KEY_VALUE_BACKUP_REQUIRE_CHARGING = true;
    private static final int DEFAULT_KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE = 1;
    private static final long DEFAULT_FULL_BACKUP_INTERVAL_MILLISECONDS =

    @VisibleForTesting
    public static final long DEFAULT_KEY_VALUE_BACKUP_FUZZ_MILLISECONDS = 10 * 60 * 1000;

    @VisibleForTesting public static final boolean DEFAULT_KEY_VALUE_BACKUP_REQUIRE_CHARGING = true;
    @VisibleForTesting public static final int DEFAULT_KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE = 1;

    @VisibleForTesting
    public static final long DEFAULT_FULL_BACKUP_INTERVAL_MILLISECONDS =
            24 * AlarmManager.INTERVAL_HOUR;
    private static final boolean DEFAULT_FULL_BACKUP_REQUIRE_CHARGING = true;
    private static final int DEFAULT_FULL_BACKUP_REQUIRED_NETWORK_TYPE = 2;
    private static final String DEFAULT_BACKUP_FINISHED_NOTIFICATION_RECEIVERS = "";

    @VisibleForTesting public static final boolean DEFAULT_FULL_BACKUP_REQUIRE_CHARGING = true;
    @VisibleForTesting public static final int DEFAULT_FULL_BACKUP_REQUIRED_NETWORK_TYPE = 2;

    @VisibleForTesting
    public static final String DEFAULT_BACKUP_FINISHED_NOTIFICATION_RECEIVERS = "";

    // Backup manager constants.
    private long mKeyValueBackupIntervalMilliseconds;
@@ -76,47 +99,44 @@ class BackupManagerConstants extends ContentObserver {
    private int mFullBackupRequiredNetworkType;
    private String[] mBackupFinishedNotificationReceivers;

    private ContentResolver mResolver;
    private final KeyValueListParser mParser = new KeyValueListParser(',');

    public BackupManagerConstants(Handler handler, ContentResolver resolver) {
        super(handler);
        mResolver = resolver;
        updateSettings();
        mResolver.registerContentObserver(
                Settings.Secure.getUriFor(Settings.Secure.BACKUP_MANAGER_CONSTANTS), false, this);
        super(handler, resolver, Settings.Secure.getUriFor(SETTING));
    }

    @Override
    public void onChange(boolean selfChange, Uri uri) {
        updateSettings();
    public String getSettingValue(ContentResolver resolver) {
        return Settings.Secure.getString(resolver, SETTING);
    }

    private synchronized void updateSettings() {
        try {
            mParser.setString(Settings.Secure.getString(mResolver,
                    Settings.Secure.BACKUP_MANAGER_CONSTANTS));
        } catch (IllegalArgumentException e) {
            // Failed to parse the settings string. Use defaults.
            Slog.e(TAG, "Bad backup manager constants: " + e.getMessage());
        }

        mKeyValueBackupIntervalMilliseconds = mParser.getLong(
    public synchronized void update(KeyValueListParser parser) {
        mKeyValueBackupIntervalMilliseconds =
                parser.getLong(
                        KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS,
                        DEFAULT_KEY_VALUE_BACKUP_INTERVAL_MILLISECONDS);
        mKeyValueBackupFuzzMilliseconds = mParser.getLong(KEY_VALUE_BACKUP_FUZZ_MILLISECONDS,
        mKeyValueBackupFuzzMilliseconds =
                parser.getLong(
                        KEY_VALUE_BACKUP_FUZZ_MILLISECONDS,
                        DEFAULT_KEY_VALUE_BACKUP_FUZZ_MILLISECONDS);
        mKeyValueBackupRequireCharging = mParser.getBoolean(KEY_VALUE_BACKUP_REQUIRE_CHARGING,
        mKeyValueBackupRequireCharging =
                parser.getBoolean(
                        KEY_VALUE_BACKUP_REQUIRE_CHARGING,
                        DEFAULT_KEY_VALUE_BACKUP_REQUIRE_CHARGING);
        mKeyValueBackupRequiredNetworkType = mParser.getInt(KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE,
        mKeyValueBackupRequiredNetworkType =
                parser.getInt(
                        KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE,
                        DEFAULT_KEY_VALUE_BACKUP_REQUIRED_NETWORK_TYPE);
        mFullBackupIntervalMilliseconds = mParser.getLong(FULL_BACKUP_INTERVAL_MILLISECONDS,
        mFullBackupIntervalMilliseconds =
                parser.getLong(
                        FULL_BACKUP_INTERVAL_MILLISECONDS,
                        DEFAULT_FULL_BACKUP_INTERVAL_MILLISECONDS);
        mFullBackupRequireCharging = mParser.getBoolean(FULL_BACKUP_REQUIRE_CHARGING,
                DEFAULT_FULL_BACKUP_REQUIRE_CHARGING);
        mFullBackupRequiredNetworkType = mParser.getInt(FULL_BACKUP_REQUIRED_NETWORK_TYPE,
        mFullBackupRequireCharging =
                parser.getBoolean(
                        FULL_BACKUP_REQUIRE_CHARGING, DEFAULT_FULL_BACKUP_REQUIRE_CHARGING);
        mFullBackupRequiredNetworkType =
                parser.getInt(
                        FULL_BACKUP_REQUIRED_NETWORK_TYPE,
                        DEFAULT_FULL_BACKUP_REQUIRED_NETWORK_TYPE);
        String backupFinishedNotificationReceivers = mParser.getString(
        String backupFinishedNotificationReceivers =
                parser.getString(
                        BACKUP_FINISHED_NOTIFICATION_RECEIVERS,
                        DEFAULT_BACKUP_FINISHED_NOTIFICATION_RECEIVERS);
        if (backupFinishedNotificationReceivers.isEmpty()) {
@@ -132,7 +152,9 @@ class BackupManagerConstants extends ContentObserver {
    // a reference of this object.
    public synchronized long getKeyValueBackupIntervalMilliseconds() {
        if (BackupManagerService.DEBUG_SCHEDULING) {
            Slog.v(TAG, "getKeyValueBackupIntervalMilliseconds(...) returns "
            Slog.v(
                    TAG,
                    "getKeyValueBackupIntervalMilliseconds(...) returns "
                            + mKeyValueBackupIntervalMilliseconds);
        }
        return mKeyValueBackupIntervalMilliseconds;
@@ -140,7 +162,9 @@ class BackupManagerConstants extends ContentObserver {

    public synchronized long getKeyValueBackupFuzzMilliseconds() {
        if (BackupManagerService.DEBUG_SCHEDULING) {
            Slog.v(TAG, "getKeyValueBackupFuzzMilliseconds(...) returns "
            Slog.v(
                    TAG,
                    "getKeyValueBackupFuzzMilliseconds(...) returns "
                            + mKeyValueBackupFuzzMilliseconds);
        }
        return mKeyValueBackupFuzzMilliseconds;
@@ -148,7 +172,9 @@ class BackupManagerConstants extends ContentObserver {

    public synchronized boolean getKeyValueBackupRequireCharging() {
        if (BackupManagerService.DEBUG_SCHEDULING) {
            Slog.v(TAG, "getKeyValueBackupRequireCharging(...) returns "
            Slog.v(
                    TAG,
                    "getKeyValueBackupRequireCharging(...) returns "
                            + mKeyValueBackupRequireCharging);
        }
        return mKeyValueBackupRequireCharging;
@@ -156,7 +182,9 @@ class BackupManagerConstants extends ContentObserver {

    public synchronized int getKeyValueBackupRequiredNetworkType() {
        if (BackupManagerService.DEBUG_SCHEDULING) {
            Slog.v(TAG, "getKeyValueBackupRequiredNetworkType(...) returns "
            Slog.v(
                    TAG,
                    "getKeyValueBackupRequiredNetworkType(...) returns "
                            + mKeyValueBackupRequiredNetworkType);
        }
        return mKeyValueBackupRequiredNetworkType;
@@ -164,7 +192,9 @@ class BackupManagerConstants extends ContentObserver {

    public synchronized long getFullBackupIntervalMilliseconds() {
        if (BackupManagerService.DEBUG_SCHEDULING) {
            Slog.v(TAG, "getFullBackupIntervalMilliseconds(...) returns "
            Slog.v(
                    TAG,
                    "getFullBackupIntervalMilliseconds(...) returns "
                            + mFullBackupIntervalMilliseconds);
        }
        return mFullBackupIntervalMilliseconds;
@@ -179,18 +209,20 @@ class BackupManagerConstants extends ContentObserver {

    public synchronized int getFullBackupRequiredNetworkType() {
        if (BackupManagerService.DEBUG_SCHEDULING) {
            Slog.v(TAG, "getFullBackupRequiredNetworkType(...) returns "
            Slog.v(
                    TAG,
                    "getFullBackupRequiredNetworkType(...) returns "
                            + mFullBackupRequiredNetworkType);
        }
        return mFullBackupRequiredNetworkType;
    }

    /**
     * Returns an array of package names that should be notified whenever a backup finishes.
     */
    /** Returns an array of package names that should be notified whenever a backup finishes. */
    public synchronized String[] getBackupFinishedNotificationReceivers() {
        if (BackupManagerService.DEBUG_SCHEDULING) {
            Slog.v(TAG, "getBackupFinishedNotificationReceivers(...) returns "
            Slog.v(
                    TAG,
                    "getBackupFinishedNotificationReceivers(...) returns "
                            + TextUtils.join(", ", mBackupFinishedNotificationReceivers));
        }
        return mBackupFinishedNotificationReceivers;
+4 −0
Original line number Diff line number Diff line
@@ -851,6 +851,10 @@ public class BackupManagerService implements BackupManagerServiceInterface {
        mJournal = null;        // will be created on first use

        mConstants = new BackupManagerConstants(mBackupHandler, mContext.getContentResolver());
        // We are observing changes to the constants throughout the lifecycle of BMS. This is
        // because we reference the constants in multiple areas of BMS, which otherwise would
        // require frequent starting and stopping.
        mConstants.start();

        // Set up the various sorts of package tracking we do
        mFullBackupScheduleFile = new File(mBaseStateDir, "fb-schedule");
+2 −1
Original line number Diff line number Diff line
@@ -62,7 +62,8 @@ LOCAL_SRC_FILES := \
    $(call all-java-files-under, ../../core/java/android/app/backup) \
    $(call all-Iaidl-files-under, ../../core/java/android/app/backup) \
    ../../core/java/android/content/pm/PackageInfo.java \
    ../../core/java/android/app/IBackupAgent.aidl
    ../../core/java/android/app/IBackupAgent.aidl \
    ../../core/java/android/util/KeyValueSettingObserver.java

LOCAL_AIDL_INCLUDES := \
    $(call all-Iaidl-files-under, $(INTERNAL_BACKUP)) \
Loading