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

Commit 59f6f7ff authored by Annie Meng's avatar Annie Meng
Browse files

[Multi-user] Initialize user state in UserBMS

Move per-user state initialization (directories for bookkeeping data and
transport manager) from BMS to UserBMS.

The UserBMS constructor is now private and callers should use the static
helper to create a new instance. This is primarily for three reasons:
1) Allows for extracting logic out of the constructor into helpers.
2) Allows for performing necessary user-specific setup in the future
such as data migration.
3) Allows for writing unit tests without having setters/getters
exclusively for tests.

Bug: 120212806
Test: 1) atest RunFrameworksServicesRoboTests
2) boot -> unlock user -> service started and verify transports
registered
3) adb shell bmgr backupnow [package] -> writes to /data dir
   adb shell bmgr enable false -> writes to /data dir
4) adb shell bmgr backupnow --all -> writes to /cache dir

Change-Id: If88d95059951dbae0abf691629db1a05d27f743d
parent 604eb2a8
Loading
Loading
Loading
Loading
+3 −29
Original line number Diff line number Diff line
@@ -37,8 +37,6 @@ import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.Trace;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Slog;

import com.android.internal.annotations.VisibleForTesting;
@@ -85,9 +83,7 @@ public class BackupManagerService {

    /** Instantiate a new instance of {@link BackupManagerService}. */
    public BackupManagerService(
            Context context,
            Trampoline trampoline,
            HandlerThread backupThread) {
            Context context, Trampoline trampoline, HandlerThread backupThread) {
        // Set up our transport options and initialize the default transport
        SystemConfig systemConfig = SystemConfig.getInstance();
        Set<ComponentName> transportWhitelist = systemConfig.getBackupTransportWhitelist();
@@ -95,31 +91,9 @@ public class BackupManagerService {
            transportWhitelist = Collections.emptySet();
        }

        String transport =
                Settings.Secure.getString(
                        context.getContentResolver(), Settings.Secure.BACKUP_TRANSPORT);
        if (TextUtils.isEmpty(transport)) {
            transport = null;
        }
        if (DEBUG) {
            Slog.v(TAG, "Starting with transport " + transport);
        }
        TransportManager transportManager =
                new TransportManager(
                        context,
                        transportWhitelist,
                        transport);

        // If encrypted file systems is enabled or disabled, this call will return the
        // correct directory.
        File baseStateDir = new File(Environment.getDataDirectory(), "backup");

        // This dir on /cache is managed directly in init.rc
        File dataDir = new File(Environment.getDownloadCacheDirectory(), "backup_stage");

        mUserBackupManagerService =
                new UserBackupManagerService(
                        context, trampoline, backupThread, baseStateDir, dataDir, transportManager);
                UserBackupManagerService.createAndInitializeService(
                        context, trampoline, backupThread, transportWhitelist);
    }

    // TODO(b/118520567): Remove when tests are modified to use per-user instance.
+70 −6
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server.backup;

import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND;

import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.server.backup.BackupManagerService.DEBUG;
import static com.android.server.backup.BackupManagerService.DEBUG_SCHEDULING;
import static com.android.server.backup.BackupManagerService.MORE_DEBUG;
@@ -68,6 +69,7 @@ import android.database.ContentObserver;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
@@ -86,6 +88,7 @@ import android.os.WorkSource;
import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.EventLog;
@@ -167,6 +170,10 @@ public class UserBackupManagerService {
    // Persistently track the need to do a full init.
    private static final String INIT_SENTINEL_FILE_NAME = "_need_init_";

    // Name of the directories the service stores bookkeeping data under.
    private static final String BACKUP_PERSISTENT_DIR = "backup";
    private static final String BACKUP_STAGING_DIR = "backup_stage";

    // System-private key used for backing up an app's widget state.  Must
    // begin with U+FFxx by convention (we reserve all keys starting
    // with U+FF00 or higher for system use).
@@ -360,15 +367,71 @@ public class UserBackupManagerService {
    private long mAncestralToken = 0;
    private long mCurrentToken = 0;

    /**
     * Creates an instance of {@link UserBackupManagerService} and initializes state for it. This
     * includes setting up the directories where we keep our bookkeeping and transport management.
     *
     * @see #createAndInitializeService(Context, Trampoline, HandlerThread, File, File,
     *     TransportManager)
     */
    static UserBackupManagerService createAndInitializeService(
            Context context,
            Trampoline trampoline,
            HandlerThread backupThread,
            Set<ComponentName> transportWhitelist) {
        String currentTransport =
                Settings.Secure.getString(
                        context.getContentResolver(), Settings.Secure.BACKUP_TRANSPORT);
        if (TextUtils.isEmpty(currentTransport)) {
            currentTransport = null;
        }

        if (DEBUG) {
            Slog.v(TAG, "Starting with transport " + currentTransport);
        }
        TransportManager transportManager =
                new TransportManager(context, transportWhitelist, currentTransport);

        File baseStateDir = new File(Environment.getDataDirectory(), BACKUP_PERSISTENT_DIR);

        // This dir on /cache is managed directly in init.rc
        File dataDir = new File(Environment.getDownloadCacheDirectory(), BACKUP_STAGING_DIR);

        return createAndInitializeService(
                context, trampoline, backupThread, baseStateDir, dataDir, transportManager);
    }

    /**
     * Creates an instance of {@link UserBackupManagerService}.
     *
     * @param context The system server context.
     * @param trampoline A reference to the proxy to {@link BackupManagerService}.
     * @param backupThread The thread running backup/restore operations for the user.
     * @param baseStateDir The directory we store the user's persistent bookkeeping data.
     * @param dataDir The directory we store the user's temporary staging data.
     * @param transportManager The {@link TransportManager} responsible for handling the user's
     *     transports.
     */
    @VisibleForTesting
    public UserBackupManagerService(
    public static UserBackupManagerService createAndInitializeService(
            Context context,
            Trampoline trampoline,
            HandlerThread backupThread,
            File baseStateDir,
            File dataDir,
            TransportManager transportManager) {
        return new UserBackupManagerService(
                context, trampoline, backupThread, baseStateDir, dataDir, transportManager);
    }

    private UserBackupManagerService(
            Context context,
            Trampoline parent,
            HandlerThread backupThread,
            File baseStateDir,
            File dataDir,
            TransportManager transportManager) {
        mContext = context;
        mContext = checkNotNull(context, "context cannot be null");
        mPackageManager = context.getPackageManager();
        mPackageManagerBinder = AppGlobals.getPackageManager();
        mActivityManager = ActivityManager.getService();
@@ -377,6 +440,7 @@ public class UserBackupManagerService {
        mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        mStorageManager = IStorageManager.Stub.asInterface(ServiceManager.getService("mount"));

        checkNotNull(parent, "trampoline cannot be null");
        mBackupManagerBinder = Trampoline.asInterface(parent.asBinder());

        mAgentTimeoutParameters = new
@@ -384,6 +448,7 @@ public class UserBackupManagerService {
        mAgentTimeoutParameters.start();

        // spin up the backup/restore handler thread
        checkNotNull(backupThread, "backupThread cannot be null");
        mBackupHandler = new BackupHandler(this, backupThread.getLooper());

        // Set up our bookkeeping
@@ -398,13 +463,13 @@ public class UserBackupManagerService {
                Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED),
                false, mProvisionedObserver);

        mBaseStateDir = baseStateDir;
        mBaseStateDir = checkNotNull(baseStateDir, "baseStateDir cannot be null");
        mBaseStateDir.mkdirs();
        if (!SELinux.restorecon(mBaseStateDir)) {
            Slog.e(TAG, "SELinux restorecon failed on " + mBaseStateDir);
        }

        mDataDir = dataDir;
        mDataDir = checkNotNull(dataDir, "dataDir cannot be null");

        mBackupPasswordManager = new BackupPasswordManager(mContext, mBaseStateDir, mRng);

@@ -451,7 +516,7 @@ public class UserBackupManagerService {
            addPackageParticipantsLocked(null);
        }

        mTransportManager = transportManager;
        mTransportManager = checkNotNull(transportManager, "transportManager cannot be null");
        mTransportManager.setOnTransportRegisteredListener(this::onTransportRegistered);
        mRegisterTransportsRequestedTime = SystemClock.elapsedRealtime();
        mBackupHandler.postDelayed(
@@ -465,7 +530,6 @@ public class UserBackupManagerService {
        mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*");
    }


    public BackupManagerConstants getConstants() {
        return mConstants;
    }
+170 −54

File changed.

Preview size limit exceeded, changes collapsed.

+5 −9
Original line number Diff line number Diff line
@@ -25,12 +25,9 @@ import static android.app.backup.BackupManager.SUCCESS;
import static android.app.backup.ForwardingBackupAgent.forward;

import static com.android.server.backup.testing.BackupManagerServiceTestUtils.createBackupWakeLock;
import static com.android.server.backup.testing.BackupManagerServiceTestUtils
        .createInitializedUserBackupManagerService;
import static com.android.server.backup.testing.BackupManagerServiceTestUtils
        .setUpBackupManagerServiceBasics;
import static com.android.server.backup.testing.BackupManagerServiceTestUtils
        .setUpBinderCallerAndApplicationAsSystem;
import static com.android.server.backup.testing.BackupManagerServiceTestUtils.createUserBackupManagerServiceAndRunTasks;
import static com.android.server.backup.testing.BackupManagerServiceTestUtils.setUpBackupManagerServiceBasics;
import static com.android.server.backup.testing.BackupManagerServiceTestUtils.setUpBinderCallerAndApplicationAsSystem;
import static com.android.server.backup.testing.PackageData.PM_PACKAGE;
import static com.android.server.backup.testing.PackageData.fullBackupPackage;
import static com.android.server.backup.testing.PackageData.keyValuePackage;
@@ -226,8 +223,7 @@ public class KeyValueBackupTaskTest {
        // Needed to be able to use a real BMS instead of a mock
        setUpBinderCallerAndApplicationAsSystem(mApplication);
        mBackupManagerService =
                spy(
                        createInitializedUserBackupManagerService(
                spy(createUserBackupManagerServiceAndRunTasks(
                        mContext, mBaseStateDir, mDataDir, mTransportManager));
        setUpBackupManagerServiceBasics(
                mBackupManagerService,
+19 −6
Original line number Diff line number Diff line
@@ -52,23 +52,36 @@ import java.util.concurrent.atomic.AtomicReference;
/** Test utils for {@link UserBackupManagerService} and friends. */
public class BackupManagerServiceTestUtils {
    /**
     * If the class-under-test is going to execute methods as the system, it's a good idea to also
     * call {@link #setUpBinderCallerAndApplicationAsSystem(Application)} before this method.
     * Creates an instance of {@link UserBackupManagerService} with a new backup thread and runs
     * tasks that were posted to it during instantiation.
     *
     * <p>If the class-under-test is going to execute methods as the system, it's a good idea to
     * also call {@link #setUpBinderCallerAndApplicationAsSystem(Application)} before this method.
     *
     * @see #createUserBackupManagerServiceAndRunTasks(Context, HandlerThread, File, File,
     *     TransportManager)
     */
    public static UserBackupManagerService createInitializedUserBackupManagerService(
    public static UserBackupManagerService createUserBackupManagerServiceAndRunTasks(
            Context context, File baseStateDir, File dataDir, TransportManager transportManager) {
        return createInitializedUserBackupManagerService(
        return createUserBackupManagerServiceAndRunTasks(
                context, startBackupThread(null), baseStateDir, dataDir, transportManager);
    }

    public static UserBackupManagerService createInitializedUserBackupManagerService(
    /**
     * Creates an instance of {@link UserBackupManagerService} with the supplied backup thread
     * {@code backupThread} and runs tasks that were posted to it during instantiation.
     *
     * <p>If the class-under-test is going to execute methods as the system, it's a good idea to
     * also call {@link #setUpBinderCallerAndApplicationAsSystem(Application)} before this method.
     */
    public static UserBackupManagerService createUserBackupManagerServiceAndRunTasks(
            Context context,
            HandlerThread backupThread,
            File baseStateDir,
            File dataDir,
            TransportManager transportManager) {
        UserBackupManagerService backupManagerService =
                new UserBackupManagerService(
                UserBackupManagerService.createAndInitializeService(
                        context,
                        new Trampoline(context),
                        backupThread,