diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 2b5cece4bb35b..e46a5f05c48d7 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -12338,6 +12338,28 @@ public final class Settings { * @hide */ public static final String SHOW_ZEN_UPGRADE_NOTIFICATION = "show_zen_upgrade_notification"; + + /** + * Backup and restore agent timeout parameters. + * These parameters are represented by a comma-delimited key-value list. + * + * The following strings are supported as keys: + *
+         *     kv_backup_agent_timeout_millis         (long)
+         *     full_backup_agent_timeout_millis       (long)
+         *     shared_backup_agent_timeout_millis     (long)
+         *     restore_agent_timeout_millis           (long)
+         *     restore_agent_finished_timeout_millis  (long)
+         * 
+ * + * They map to milliseconds represented as longs. + * + * Ex: "kv_backup_agent_timeout_millis=30000,full_backup_agent_timeout_millis=300000" + * + * @hide + */ + public static final String BACKUP_AGENT_TIMEOUT_PARAMETERS = + "backup_agent_timeout_parameters"; } /** diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto index 23c5661f05332..a818e2095ca31 100644 --- a/core/proto/android/providers/settings.proto +++ b/core/proto/android/providers/settings.proto @@ -502,9 +502,10 @@ message GlobalSettingsProto { optional SettingProto show_restart_in_crash_dialog = 383 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto show_mute_in_crash_dialog = 384 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingsProto show_zen_upgrade_notification = 385 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingsProto backup_agent_timeout_parameters = 386; // Please insert fields in the same order as in // frameworks/base/core/java/android/provider/Settings.java. - // Next tag = 386; + // Next tag = 387; } message SecureSettingsProto { diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index 73fb7139cbd48..a08eae94b3f66 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -463,8 +463,8 @@ public class SettingsBackupTest { Settings.Global.ZRAM_ENABLED, Settings.Global.OVERRIDE_SETTINGS_PROVIDER_RESTORE_ANY_VERSION, Settings.Global.CHAINED_BATTERY_ATTRIBUTION_ENABLED, - Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS); - + Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS, + Settings.Global.BACKUP_AGENT_TIMEOUT_PARAMETERS); private static final Set BACKUP_BLACKLISTED_SECURE_SETTINGS = newHashSet( Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml index 1cd02f418352e..ecda53a15f481 100644 --- a/packages/SettingsProvider/res/values/defaults.xml +++ b/packages/SettingsProvider/res/values/defaults.xml @@ -207,4 +207,7 @@ Else (if negative), turning on dnd manually will surface a dialog that prompts user to specify a duration.--> 0 + + + diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index 53cff4e845493..9a438398127d6 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -1253,6 +1253,9 @@ class SettingsProtoDumpUtil { dumpSetting(s, p, Settings.Global.SHOW_ZEN_UPGRADE_NOTIFICATION, GlobalSettingsProto.SHOW_ZEN_UPGRADE_NOTIFICATION); + dumpSetting(s, p, + Settings.Global.BACKUP_AGENT_TIMEOUT_PARAMETERS, + GlobalSettingsProto.BACKUP_AGENT_TIMEOUT_PARAMETERS); // Please insert new settings using the same order as in Settings.Global. p.end(token); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index 6398858479076..da62d94f9c637 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -2938,7 +2938,7 @@ public class SettingsProvider extends ContentProvider { } private final class UpgradeController { - private static final int SETTINGS_VERSION = 157; + private static final int SETTINGS_VERSION = 158; private final int mUserId; @@ -3584,7 +3584,7 @@ public class SettingsProvider extends ContentProvider { } if (currentVersion == 155) { - // Version 155: Set the default value for CHARGING_STARTED_SOUND. + // Version 156: Set the default value for CHARGING_STARTED_SOUND. final SettingsState globalSettings = getGlobalSettingsLocked(); final String oldValue = globalSettings.getSettingLocked( Global.CHARGING_STARTED_SOUND).getValue(); @@ -3605,7 +3605,7 @@ public class SettingsProvider extends ContentProvider { } if (currentVersion == 156) { - // Version 156: Set a default value for zen duration + // Version 157: Set a default value for zen duration final SettingsState globalSettings = getGlobalSettingsLocked(); final Setting currentSetting = globalSettings.getSettingLocked( Global.ZEN_DURATION); @@ -3616,9 +3616,26 @@ public class SettingsProvider extends ContentProvider { Global.ZEN_DURATION, defaultZenDuration, null, true, SettingsState.SYSTEM_PACKAGE_NAME); } - currentVersion = 157; } + + if (currentVersion == 157) { + // Version 158: Set default value for BACKUP_AGENT_TIMEOUT_PARAMETERS. + final SettingsState globalSettings = getGlobalSettingsLocked(); + final String oldValue = globalSettings.getSettingLocked( + Settings.Global.BACKUP_AGENT_TIMEOUT_PARAMETERS).getValue(); + if (TextUtils.equals(null, oldValue)) { + final String defaultValue = getContext().getResources().getString( + R.string.def_backup_agent_timeout_parameters); + if (!TextUtils.isEmpty(defaultValue)) { + globalSettings.insertSettingLocked( + Settings.Global.BACKUP_AGENT_TIMEOUT_PARAMETERS, defaultValue, + null, true, + SettingsState.SYSTEM_PACKAGE_NAME); + } + } + currentVersion = 158; + } // vXXX: Add new settings above this point. if (currentVersion != newVersion) { diff --git a/services/backup/java/com/android/server/backup/BackupAgentTimeoutParameters.java b/services/backup/java/com/android/server/backup/BackupAgentTimeoutParameters.java new file mode 100644 index 0000000000000..4de2c9b8e79f4 --- /dev/null +++ b/services/backup/java/com/android/server/backup/BackupAgentTimeoutParameters.java @@ -0,0 +1,150 @@ +/* + * 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 com.android.server.backup; + +import android.content.ContentResolver; +import android.os.Handler; +import android.provider.Settings; +import android.util.KeyValueListParser; +import android.util.KeyValueSettingObserver; +import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; + +/** + * Configure backup and restore agent timeouts. + * + *

These timeout parameters are stored in Settings.Global to be configurable flags with P/H. They + * are represented as a comma-delimited key value list. + */ +public class BackupAgentTimeoutParameters extends KeyValueSettingObserver { + @VisibleForTesting + public static final String SETTING = Settings.Global.BACKUP_AGENT_TIMEOUT_PARAMETERS; + + @VisibleForTesting + public static final String SETTING_KV_BACKUP_AGENT_TIMEOUT_MILLIS = + "kv_backup_agent_timeout_millis"; + + @VisibleForTesting + public static final String SETTING_FULL_BACKUP_AGENT_TIMEOUT_MILLIS = + "full_backup_agent_timeout_millis"; + + @VisibleForTesting + public static final String SETTING_SHARED_BACKUP_AGENT_TIMEOUT_MILLIS = + "shared_backup_agent_timeout_millis"; + + @VisibleForTesting + public static final String SETTING_RESTORE_AGENT_TIMEOUT_MILLIS = + "restore_agent_timeout_millis"; + + @VisibleForTesting + public static final String SETTING_RESTORE_AGENT_FINISHED_TIMEOUT_MILLIS = + "restore_agent_finished_timeout_millis"; + + // Default values + @VisibleForTesting public static final long DEFAULT_KV_BACKUP_AGENT_TIMEOUT_MILLIS = 30 * 1000; + + @VisibleForTesting + public static final long DEFAULT_FULL_BACKUP_AGENT_TIMEOUT_MILLIS = 5 * 60 * 1000; + + @VisibleForTesting + public static final long DEFAULT_SHARED_BACKUP_AGENT_TIMEOUT_MILLIS = 30 * 60 * 1000; + + @VisibleForTesting public static final long DEFAULT_RESTORE_AGENT_TIMEOUT_MILLIS = 60 * 1000; + + @VisibleForTesting + public static final long DEFAULT_RESTORE_AGENT_FINISHED_TIMEOUT_MILLIS = 30 * 1000; + + @GuardedBy("mLock") + private long mKvBackupAgentTimeoutMillis; + + @GuardedBy("mLock") + private long mFullBackupAgentTimeoutMillis; + + @GuardedBy("mLock") + private long mSharedBackupAgentTimeoutMillis; + + @GuardedBy("mLock") + private long mRestoreAgentTimeoutMillis; + + @GuardedBy("mLock") + private long mRestoreAgentFinishedTimeoutMillis; + + private final Object mLock = new Object(); + + public BackupAgentTimeoutParameters(Handler handler, ContentResolver resolver) { + super(handler, resolver, Settings.Global.getUriFor(SETTING)); + } + + public String getSettingValue(ContentResolver resolver) { + return Settings.Global.getString(resolver, SETTING); + } + + public void update(KeyValueListParser parser) { + synchronized (mLock) { + mKvBackupAgentTimeoutMillis = + parser.getLong( + SETTING_KV_BACKUP_AGENT_TIMEOUT_MILLIS, + DEFAULT_KV_BACKUP_AGENT_TIMEOUT_MILLIS); + mFullBackupAgentTimeoutMillis = + parser.getLong( + SETTING_FULL_BACKUP_AGENT_TIMEOUT_MILLIS, + DEFAULT_FULL_BACKUP_AGENT_TIMEOUT_MILLIS); + mSharedBackupAgentTimeoutMillis = + parser.getLong( + SETTING_SHARED_BACKUP_AGENT_TIMEOUT_MILLIS, + DEFAULT_SHARED_BACKUP_AGENT_TIMEOUT_MILLIS); + mRestoreAgentTimeoutMillis = + parser.getLong( + SETTING_RESTORE_AGENT_TIMEOUT_MILLIS, + DEFAULT_RESTORE_AGENT_TIMEOUT_MILLIS); + mRestoreAgentFinishedTimeoutMillis = + parser.getLong( + SETTING_RESTORE_AGENT_FINISHED_TIMEOUT_MILLIS, + DEFAULT_RESTORE_AGENT_FINISHED_TIMEOUT_MILLIS); + } + } + + public long getKvBackupAgentTimeoutMillis() { + synchronized (mLock) { + return mKvBackupAgentTimeoutMillis; + } + } + + public long getFullBackupAgentTimeoutMillis() { + synchronized (mLock) { + return mFullBackupAgentTimeoutMillis; + } + } + + public long getSharedBackupAgentTimeoutMillis() { + synchronized (mLock) { + return mSharedBackupAgentTimeoutMillis; + } + } + + public long getRestoreAgentTimeoutMillis() { + synchronized (mLock) { + return mRestoreAgentTimeoutMillis; + } + } + + public long getRestoreAgentFinishedTimeoutMillis() { + synchronized (mLock) { + return mRestoreAgentFinishedTimeoutMillis; + } + } +} diff --git a/services/robotests/src/com/android/server/backup/BackupAgentTimeoutParametersTest.java b/services/robotests/src/com/android/server/backup/BackupAgentTimeoutParametersTest.java new file mode 100644 index 0000000000000..801451ee549b9 --- /dev/null +++ b/services/robotests/src/com/android/server/backup/BackupAgentTimeoutParametersTest.java @@ -0,0 +1,140 @@ +/* + * 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 com.android.server.backup; + +import static org.junit.Assert.assertEquals; + +import android.content.ContentResolver; +import android.content.Context; +import android.os.Handler; +import android.platform.test.annotations.Presubmit; +import android.provider.Settings; +import android.util.KeyValueSettingObserver; +import com.android.server.testing.FrameworkRobolectricTestRunner; +import com.android.server.testing.SystemLoaderClasses; +import com.android.server.testing.SystemLoaderPackages; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +/** Tests for {@link BackupAgentTimeoutParameters}. */ +@RunWith(FrameworkRobolectricTestRunner.class) +@Config(manifest = Config.NONE, sdk = 26) +@SystemLoaderPackages({"com.android.server.backup"}) +@SystemLoaderClasses({KeyValueSettingObserver.class}) +@Presubmit +public class BackupAgentTimeoutParametersTest { + private ContentResolver mContentResolver; + private BackupAgentTimeoutParameters mParameters; + + /** Initialize timeout parameters and start observing changes. */ + @Before + public void setUp() { + Context context = RuntimeEnvironment.application.getApplicationContext(); + + mContentResolver = context.getContentResolver(); + mParameters = new BackupAgentTimeoutParameters(new Handler(), mContentResolver); + mParameters.start(); + } + + /** Stop observing changes to the setting. */ + @After + public void tearDown() { + mParameters.stop(); + } + + /** Tests that timeout parameters are initialized with default values on creation. */ + @Test + public void testGetParameters_afterConstructorWithStart_returnsDefaultValues() { + long kvBackupAgentTimeoutMillis = mParameters.getKvBackupAgentTimeoutMillis(); + long fullBackupAgentTimeoutMillis = mParameters.getFullBackupAgentTimeoutMillis(); + long sharedBackupAgentTimeoutMillis = mParameters.getSharedBackupAgentTimeoutMillis(); + long restoreAgentTimeoutMillis = mParameters.getRestoreAgentTimeoutMillis(); + long restoreAgentFinishedTimeoutMillis = mParameters.getRestoreAgentFinishedTimeoutMillis(); + + assertEquals( + BackupAgentTimeoutParameters.DEFAULT_KV_BACKUP_AGENT_TIMEOUT_MILLIS, + kvBackupAgentTimeoutMillis); + assertEquals( + BackupAgentTimeoutParameters.DEFAULT_FULL_BACKUP_AGENT_TIMEOUT_MILLIS, + fullBackupAgentTimeoutMillis); + assertEquals( + BackupAgentTimeoutParameters.DEFAULT_SHARED_BACKUP_AGENT_TIMEOUT_MILLIS, + sharedBackupAgentTimeoutMillis); + assertEquals( + BackupAgentTimeoutParameters.DEFAULT_RESTORE_AGENT_TIMEOUT_MILLIS, + restoreAgentTimeoutMillis); + assertEquals( + BackupAgentTimeoutParameters.DEFAULT_RESTORE_AGENT_FINISHED_TIMEOUT_MILLIS, + restoreAgentFinishedTimeoutMillis); + } + + /** + * Tests that timeout parameters are updated when we call start, even when a setting change + * occurs while we are not observing. + */ + @Test + public void testGetParameters_withSettingChangeBeforeStart_updatesValues() { + mParameters.stop(); + long testTimeout = BackupAgentTimeoutParameters.DEFAULT_KV_BACKUP_AGENT_TIMEOUT_MILLIS * 2; + final String setting = + BackupAgentTimeoutParameters.SETTING_KV_BACKUP_AGENT_TIMEOUT_MILLIS + + "=" + + testTimeout; + putStringAndNotify(setting); + mParameters.start(); + + long kvBackupAgentTimeoutMillis = mParameters.getKvBackupAgentTimeoutMillis(); + + assertEquals(testTimeout, kvBackupAgentTimeoutMillis); + } + + /** + * Tests that timeout parameters are updated when a setting change occurs while we are observing + * changes. + */ + @Test + public void testGetParameters_withSettingChangeAfterStart_updatesValues() { + long testTimeout = BackupAgentTimeoutParameters.DEFAULT_KV_BACKUP_AGENT_TIMEOUT_MILLIS * 2; + final String setting = + BackupAgentTimeoutParameters.SETTING_KV_BACKUP_AGENT_TIMEOUT_MILLIS + + "=" + + testTimeout; + putStringAndNotify(setting); + + long kvBackupAgentTimeoutMillis = mParameters.getKvBackupAgentTimeoutMillis(); + + assertEquals(testTimeout, kvBackupAgentTimeoutMillis); + } + + /** + * Robolectric does not notify observers of changes to settings so we have to trigger it here. + * Currently, the mock of {@link Settings.Secure#putString(ContentResolver, String, String)} + * only stores the value. TODO: Implement properly in ShadowSettings. + */ + private void putStringAndNotify(String value) { + Settings.Global.putString(mContentResolver, BackupAgentTimeoutParameters.SETTING, value); + + // We pass null as the observer since notifyChange iterates over all available observers and + // we don't have access to the local observer. + mContentResolver.notifyChange( + Settings.Global.getUriFor(BackupAgentTimeoutParameters.SETTING), /*observer*/ null); + } +}