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

Commit 41349c02 authored by Bernardo Rufino's avatar Bernardo Rufino
Browse files

Binding on-demand #10: Remove permanent binding and add registration

This CL is the last of the P1 CLs for binding on-demand. During
transport-usage migration to binding on-demand the permanent-bound
code was still there and we piggybacked on it to register the
transports. Now that everything is migrated we removed the permanent
binding and used the registration code created in the CL #9
(selectTransport) for registering all the transports.

I put a 3s delay on registration after bring-up. Any operation that uses
the transport before that will gracefully fail.

The TransportBoundListener does not return a boolean anymore because it
can't fail anymore (we pass it the data it needs so that it doesn't need
to be exposed to TransportNotRegistered exceptions). It's now called
OnTransportRegisteredListener.

Eligible transports were a similar thing to valid transports from the
permanent binding code, whose only need came from rebinding from what I
could tell. I saw no need for it anymore and removed it. If I missed
something please shout :)

I shuffled methods a bit in TransportManager.

There were a lot of changes to robo test infra to bring together
TransportManager tests and the rest and re-use mocking infra.

Change-Id: If61268228dd0bb724b718abd3dcafdad50e8b3dc
Ref: http://go/br-binding-on-demand
Bug: 17140907
Test: m -j RunFrameworksServicesRoboTest
Test: runtest -p com.android.server.backup frameworks-services
Test: gts-tradefed run commandAndExit gts-dev -m GtsBackupTestCases
Test: gts-tradefed run commandAndExit gts-dev -m GtsBackupHostTestCases
Test: cts-tradefed run commandAndExit cts-dev -m CtsBackupTestCases
Test: adb shell bmgr enable true/false
Test: adb shell bmgr list transports [-c]
Test: adb shell bmgr transport <transport_name>/-c <transport_component>
Test: adb shell bmgr restore <token>/<token> <package>/<package>
Test: adb shell bmgr backup <pacakge>
Test: adb shell bmgr run
Test: adb shell bmgr wipe <transport> <package>
Test: adb shell bmgr fullbackup <package>
Test: adb shell bmgr backupnow --all/<packages>
Test: adb shell cmd jobscheduler run -f android <job_id>
Test: adb shell dumpsys backup
Test: D2D scenario
parent 02c0e986
Loading
Loading
Loading
Loading
+42 −40
Original line number Diff line number Diff line
@@ -207,6 +207,10 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
    public static final String BACKUP_FINISHED_ACTION = "android.intent.action.BACKUP_FINISHED";
    public static final String BACKUP_FINISHED_PACKAGE_EXTRA = "packageName";

    // Time delay for initialization operations that can be delayed so as not to consume too much CPU
    // on bring-up and increase time-to-UI.
    private static final long INITIALIZATION_DELAY_MILLIS = 3000;

    // Timeout interval for deciding that a bind or clear-data has taken too long
    private static final long TIMEOUT_INTERVAL = 10 * 1000;

@@ -282,6 +286,9 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter

    private final BackupPasswordManager mBackupPasswordManager;

    // Time when we post the transport registration operation
    private final long mRegisterTransportsRequestedTime;

    @GuardedBy("mPendingRestores")
    private boolean mIsRestoreInProgress;
    @GuardedBy("mPendingRestores")
@@ -735,6 +742,9 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
        // Set up our transport options and initialize the default transport
        SystemConfig systemConfig = SystemConfig.getInstance();
        Set<ComponentName> transportWhitelist = systemConfig.getBackupTransportWhitelist();
        if (transportWhitelist == null) {
            transportWhitelist = Collections.emptySet();
        }

        String transport =
                Settings.Secure.getString(
@@ -749,8 +759,7 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
                new TransportManager(
                        context,
                        transportWhitelist,
                        transport,
                        backupThread.getLooper());
                        transport);

        // If encrypted file systems is enabled or disabled, this call will return the
        // correct directory.
@@ -852,12 +861,14 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
        }

        mTransportManager = transportManager;
        mTransportManager.setTransportBoundListener(mTransportBoundListener);
        mTransportManager.registerAllTransports();
        mTransportManager.setOnTransportRegisteredListener(this::onTransportRegistered);
        mRegisterTransportsRequestedTime = SystemClock.elapsedRealtime();
        mBackupHandler.postDelayed(
                mTransportManager::registerTransports, INITIALIZATION_DELAY_MILLIS);

        // Now that we know about valid backup participants, parse any
        // leftover journal files into the pending backup set
        mBackupHandler.post(this::parseLeftoverJournals);
        // Now that we know about valid backup participants, parse any leftover journal files into
        // the pending backup set
        mBackupHandler.postDelayed(this::parseLeftoverJournals, INITIALIZATION_DELAY_MILLIS);

        // Power management
        mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*");
@@ -1151,24 +1162,20 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
        }
    }

    private TransportManager.TransportBoundListener mTransportBoundListener =
            new TransportManager.TransportBoundListener() {
                @Override
                public boolean onTransportBound(IBackupTransport transport) {
                    // If the init sentinel file exists, we need to be sure to perform the init
                    // as soon as practical.  We also create the state directory at registration
                    // time to ensure it's present from the outset.
                    String name = null;
                    try {
                        name = transport.name();
                        String transportDirName = transport.transportDirName();
    private void onTransportRegistered(String transportName, String transportDirName) {
        if (DEBUG) {
            long timeMs = SystemClock.elapsedRealtime() - mRegisterTransportsRequestedTime;
            Slog.d(TAG, "Transport " + transportName + " registered " + timeMs
                    + "ms after first request (delay = " + INITIALIZATION_DELAY_MILLIS + "ms)");
        }

        File stateDir = new File(mBaseStateDir, transportDirName);
        stateDir.mkdirs();

        File initSentinel = new File(stateDir, INIT_SENTINEL_FILE_NAME);
        if (initSentinel.exists()) {
            synchronized (mQueueLock) {
                                mPendingInits.add(name);
                mPendingInits.add(transportName);

                // TODO: pick a better starting time than now + 1 minute
                long delay = 1000 * 60; // one minute, in milliseconds
@@ -1176,14 +1183,7 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
                        System.currentTimeMillis() + delay, mRunInitIntent);
            }
        }
                        return true;
                    } catch (Exception e) {
                        // the transport threw when asked its file naming prefs; declare it invalid
                        Slog.w(TAG, "Failed to regiser transport: " + name);
                        return false;
    }
                }
            };

    // ----- Track installation/removal of packages -----
    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@@ -2891,14 +2891,14 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
                "listAllTransports");

        return mTransportManager.getBoundTransportNames();
        return mTransportManager.getRegisteredTransportNames();
    }

    @Override
    public ComponentName[] listAllTransportComponents() {
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
                "listAllTransportComponents");
        return mTransportManager.getAllTransportComponents();
        return mTransportManager.getRegisteredTransportComponents();
    }

    @Override
@@ -3003,6 +3003,8 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter

    /** Selects transport {@code transportName} and returns previous selected transport. */
    @Override
    @Deprecated
    @Nullable
    public String selectBackupTransport(String transportName) {
        mContext.enforceCallingOrSelfPermission(
                android.Manifest.permission.BACKUP, "selectBackupTransport");
+259 −560

File changed.

Preview size limit exceeded, changes collapsed.

+33 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 * 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.
@@ -14,51 +14,20 @@
 * limitations under the License
 */

package com.android.server.backup.testing;
package com.android.server.backup.transport;

import com.android.internal.backup.IBackupTransport;
import com.android.server.backup.TransportManager;

import java.util.HashSet;
import java.util.Set;

/**
 * Stub implementation of TransportBoundListener, which returns given result and can tell whether
 * it was called for given transport.
 * Listener called when a transport is registered with the {@link TransportManager}. Can be set
 * using {@link TransportManager#setOnTransportRegisteredListener(OnTransportRegisteredListener)}.
 */
public class TransportBoundListenerStub implements
        TransportManager.TransportBoundListener {
    private boolean mAlwaysReturnSuccess;
    private Set<IBackupTransport> mTransportsCalledFor = new HashSet<>();

    public TransportBoundListenerStub(boolean alwaysReturnSuccess) {
        this.mAlwaysReturnSuccess = alwaysReturnSuccess;
    }

    @Override
    public boolean onTransportBound(IBackupTransport binder) {
        mTransportsCalledFor.add(binder);
        return mAlwaysReturnSuccess;
    }

@FunctionalInterface
public interface OnTransportRegisteredListener {
    /**
     * Returns whether the listener was called for the specified transport at least once.
     * Called when a transport is successfully registered.
     * @param transportName The name of the transport.
     * @param transportDirName The dir name of the transport.
     */
    public boolean isCalledForTransport(IBackupTransport binder) {
        return mTransportsCalledFor.contains(binder);
    }

    /**
     * Returns whether the listener was called at least once.
     */
    public boolean isCalled() {
        return !mTransportsCalledFor.isEmpty();
    }

    /**
     * Resets listener calls.
     */
    public void resetState() {
        mTransportsCalledFor.clear();
    }
    public void onTransportRegistered(String transportName, String transportDirName);
}
+1 −1
Original line number Diff line number Diff line
@@ -236,7 +236,7 @@ public class TransportClient {
                                    mBindIntent,
                                    mConnection,
                                    Context.BIND_AUTO_CREATE,
                                    TransportManager.createSystemUserHandle());
                                    UserHandle.SYSTEM);
                    if (hasBound) {
                        // We don't need to set a time-out because we are guaranteed to get a call
                        // back in ServiceConnection, either an onServiceConnected() or
+129 −56

File changed.

Preview size limit exceeded, changes collapsed.

Loading