diff options
| author | 2018-11-30 12:09:08 +0000 | |
|---|---|---|
| committer | 2018-12-10 12:33:28 +0000 | |
| commit | a6d828755ee306c0e01a078530c22bd83d56f55f (patch) | |
| tree | 43f9f9ff4f532e50e537846628132c64ae0a91e9 | |
| parent | 348c897729fef9a4c3d2f522efea0c6946071971 (diff) | |
[Multi-user] Create setting for multi-user backup service support
Whether the backup service supports multi-user is now configured in a
Global setting: backup_multi_user_enabled
This allows us to develop multi-user support hidden behind a flag. In a
future CL, we'll also gate the types of users we support.
Also create basic infrastructure for starting the service for a newly
unlocked user (currently a no-op).
Bug: 120212806
Test: 1) atest TrampolineTest
2) adb shell settings put global backup_multi_user_enabled 0;
unlock system user -> verify service started;
unlock user 10 -> verify service not started;
3) adb shell settings put global backup_multi_user_enabled 1;
unlock system user -> verify service started;
unlock user 10 -> verify service started;
Change-Id: I048e017cfa6148097cebe2eb2916d1b53c53d3b0
7 files changed, 111 insertions, 13 deletions
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 3437e1d09cd4..de6afcbad9a6 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -13795,6 +13795,14 @@ public final class Settings { "backup_agent_timeout_parameters"; /** + * Whether the backup system service supports multiple users (0 = disabled, 1 = enabled). If + * disabled, the service will only be active for the system user. + * + * @hide + */ + public static final String BACKUP_MULTI_USER_ENABLED = "backup_multi_user_enabled"; + + /** * Blacklist of GNSS satellites. * * This is a list of integers separated by commas to represent pairs of (constellation, diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto index da6e20867cca..11bd43b11977 100644 --- a/core/proto/android/providers/settings/global.proto +++ b/core/proto/android/providers/settings/global.proto @@ -109,7 +109,15 @@ message GlobalSettingsProto { } optional Autofill autofill = 140; - optional SettingProto backup_agent_timeout_parameters = 18; + reserved 18; // Used to be backup_agent_timeout_parameters + + message Backup { + option (android.msg_privacy).dest = DEST_EXPLICIT; + + optional SettingProto backup_agent_timeout_parameters = 1; + optional SettingProto backup_multi_user_enabled = 2; + } + optional Backup backup = 146; message Battery { option (android.msg_privacy).dest = DEST_EXPLICIT; @@ -1007,5 +1015,5 @@ message GlobalSettingsProto { // Please insert fields in alphabetical order and group them into messages // if possible (to avoid reaching the method limit). - // Next tag = 146; + // Next tag = 147; } diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index 79eaab8a6e85..49a7555c2ac4 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -541,7 +541,8 @@ public class SettingsBackupTest { Settings.Global.OVERRIDE_SETTINGS_PROVIDER_RESTORE_ANY_VERSION, Settings.Global.CHAINED_BATTERY_ATTRIBUTION_ENABLED, Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS, - Settings.Global.BACKUP_AGENT_TIMEOUT_PARAMETERS); + Settings.Global.BACKUP_AGENT_TIMEOUT_PARAMETERS, + Settings.Global.BACKUP_MULTI_USER_ENABLED); private static final Set<String> BACKUP_BLACKLISTED_SECURE_SETTINGS = newHashSet( Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index 533956f69835..e3d3d81704a8 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -208,9 +208,14 @@ class SettingsProtoDumpUtil { GlobalSettingsProto.Autofill.MAX_VISIBLE_DATASETS); p.end(autofillToken); + final long backupToken = p.start(GlobalSettingsProto.BACKUP); dumpSetting(s, p, Settings.Global.BACKUP_AGENT_TIMEOUT_PARAMETERS, - GlobalSettingsProto.BACKUP_AGENT_TIMEOUT_PARAMETERS); + GlobalSettingsProto.Backup.BACKUP_AGENT_TIMEOUT_PARAMETERS); + dumpSetting(s, p, + Settings.Global.BACKUP_MULTI_USER_ENABLED, + GlobalSettingsProto.Backup.BACKUP_MULTI_USER_ENABLED); + p.end(backupToken); final long batteryToken = p.start(GlobalSettingsProto.BATTERY); dumpSetting(s, p, diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index 0b06f286441a..e62ec7ac41aa 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -184,6 +184,15 @@ public class BackupManagerService { Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } + /** + * Starts the backup service for user {@code userId} by creating a new instance of {@link + * UserBackupManagerService} and registering it with this service. + */ + // TODO(b/120212806): Add UserBackupManagerService initialization logic. + void startServiceForUser(int userId) { + // Intentionally empty. + } + /* * The following methods are implementations of IBackupManager methods called from Trampoline. * They delegate to the appropriate per-user instance of UserBackupManagerService to perform the @@ -626,7 +635,9 @@ public class BackupManagerService { @Override public void onUnlockUser(int userId) { if (userId == UserHandle.USER_SYSTEM) { - sInstance.unlockSystemUser(); + sInstance.initializeServiceAndUnlockSystemUser(); + } else { + sInstance.startServiceForUser(userId); } } } diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java index 59629aac7b4d..9ca2070c7bab 100644 --- a/services/backup/java/com/android/server/backup/Trampoline.java +++ b/services/backup/java/com/android/server/backup/Trampoline.java @@ -41,6 +41,7 @@ import android.os.RemoteException; import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; +import android.provider.Settings; import android.util.Slog; import com.android.internal.annotations.GuardedBy; @@ -81,6 +82,12 @@ public class Trampoline extends IBackupManager.Stub { // Product-level suppression of backup/restore. private static final String BACKUP_DISABLE_PROPERTY = "ro.backup.disable"; + private static final String BACKUP_THREAD = "backup"; + + /** Values for setting {@link Settings.Global#BACKUP_MULTI_USER_ENABLED} */ + private static final int MULTI_USER_DISABLED = 0; + private static final int MULTI_USER_ENABLED = 1; + private final Context mContext; @GuardedBy("mStateLock") @@ -91,18 +98,31 @@ public class Trampoline extends IBackupManager.Stub { private volatile BackupManagerService mService; private HandlerThread mHandlerThread; + private Handler mHandler; public Trampoline(Context context) { mContext = context; mGlobalDisable = isBackupDisabled(); mSuppressFile = getSuppressFile(); mSuppressFile.getParentFile().mkdirs(); + + mHandlerThread = new HandlerThread(BACKUP_THREAD, Process.THREAD_PRIORITY_BACKGROUND); + mHandlerThread.start(); + mHandler = new Handler(mHandlerThread.getLooper()); } protected boolean isBackupDisabled() { return SystemProperties.getBoolean(BACKUP_DISABLE_PROPERTY, false); } + protected boolean isMultiUserEnabled() { + return Settings.Global.getInt( + mContext.getContentResolver(), + Settings.Global.BACKUP_MULTI_USER_ENABLED, + MULTI_USER_DISABLED) + == MULTI_USER_ENABLED; + } + protected int binderGetCallingUid() { return Binder.getCallingUid(); } @@ -147,15 +167,9 @@ public class Trampoline extends IBackupManager.Stub { /** * Called from {@link BackupManagerService.Lifecycle} when the system user is unlocked. Attempts * to initialize {@link BackupManagerService} and set backup state for the system user. - * - * @see BackupManagerService#unlockSystemUser() */ - void unlockSystemUser() { - mHandlerThread = new HandlerThread("backup", Process.THREAD_PRIORITY_BACKGROUND); - mHandlerThread.start(); - - Handler h = new Handler(mHandlerThread.getLooper()); - h.post( + void initializeServiceAndUnlockSystemUser() { + mHandler.post( () -> { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup init"); initializeService(UserHandle.USER_SYSTEM); @@ -170,6 +184,29 @@ public class Trampoline extends IBackupManager.Stub { } /** + * Called from {@link BackupManagerService.Lifecycle} when a non-system user {@code userId} is + * unlocked. Starts the backup service for this user if the service supports multi-user. + * Offloads work onto the handler thread {@link #mHandlerThread} to keep unlock time low. + */ + // TODO(b/120212806): Consolidate service start for system and non-system users when system + // user-only logic is removed. + void startServiceForUser(int userId) { + if (!isMultiUserEnabled()) { + Slog.i(TAG, "Multi-user disabled, cannot start service for user: " + userId); + return; + } + + mHandler.post( + () -> { + BackupManagerService service = mService; + if (service != null) { + Slog.i(TAG, "Starting service for user: " + userId); + service.startServiceForUser(userId); + } + }); + } + + /** * Only privileged callers should be changing the backup state. This method only acts on {@link * UserHandle#USER_SYSTEM} and is a no-op if passed non-system users. Deactivating backup in the * system user also deactivates backup in all users. diff --git a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java index 7c002995a769..fd010f1fed4f 100644 --- a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java +++ b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java @@ -23,6 +23,7 @@ import static junit.framework.Assert.assertNull; import static junit.framework.Assert.assertTrue; import static junit.framework.Assert.fail; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; @@ -43,10 +44,14 @@ import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; import android.platform.test.annotations.Presubmit; +import android.provider.Settings; +import android.test.mock.MockContentResolver; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.util.test.FakeSettingsProvider; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -97,6 +102,7 @@ public class TrampolineTest { private FileDescriptor mFileDescriptorStub = new FileDescriptor(); private TrampolineTestable mTrampoline; + private MockContentResolver mContentResolver; @Before public void setUp() { @@ -110,6 +116,10 @@ public class TrampolineTest { when(mSuppressFileMock.getParentFile()).thenReturn(mSuppressFileParentMock); mTrampoline = new TrampolineTestable(mContextMock); + + mContentResolver = new MockContentResolver(); + mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); + when(mContextMock.getContentResolver()).thenReturn(mContentResolver); } @Test @@ -118,6 +128,24 @@ public class TrampolineTest { } @Test + public void startServiceForUser_whenMultiUserSettingDisabled_isIgnored() { + Settings.Global.putInt(mContentResolver, Settings.Global.BACKUP_MULTI_USER_ENABLED, 0); + + mTrampoline.startServiceForUser(10); + + verify(mBackupManagerServiceMock, never()).startServiceForUser(10); + } + + @Test + public void startServiceForUser_whenMultiUserSettingEnabled_callsBackupManagerService() { + Settings.Global.putInt(mContentResolver, Settings.Global.BACKUP_MULTI_USER_ENABLED, 1); + + mTrampoline.startServiceForUser(10); + + verify(mBackupManagerServiceMock).startServiceForUser(10); + } + + @Test public void initializeService_forUserSystem_successfullyInitialized() { mTrampoline.initializeService(UserHandle.USER_SYSTEM); |