[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
This commit is contained in:
Annie Meng
2018-11-30 12:09:08 +00:00
parent 348c897729
commit a6d828755e
7 changed files with 111 additions and 13 deletions

View File

@@ -13794,6 +13794,14 @@ public final class Settings {
public static final String BACKUP_AGENT_TIMEOUT_PARAMETERS =
"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.
*

View File

@@ -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;
}

View File

@@ -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,

View File

@@ -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,

View File

@@ -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);
}
}
}

View File

@@ -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);
@@ -169,6 +183,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

View File

@@ -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
@@ -117,6 +127,24 @@ public class TrampolineTest {
verify(mSuppressFileParentMock).mkdirs();
}
@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);