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

Commit 622b9681 authored by Ruslan Tkhakokhov's avatar Ruslan Tkhakokhov
Browse files

Wrap IBackupTransport usages with BackupTransportClient

Bug: 202716271
Change-Id: I4899fea3342f9e913fa1afa14ed7b67481f02908
parent 32cb668a
Loading
Loading
Loading
Loading
+4 −7
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.backup.IBackupTransport;
import com.android.internal.util.Preconditions;
import com.android.server.backup.transport.BackupTransportClient;
import com.android.server.backup.transport.OnTransportRegisteredListener;
import com.android.server.backup.transport.TransportConnection;
import com.android.server.backup.transport.TransportConnectionManager;
@@ -641,7 +642,7 @@ public class TransportManager {
        TransportConnection transportConnection =
                mTransportConnectionManager.getTransportClient(
                        transportComponent, extras, callerLogString);
        final IBackupTransport transport;
        final BackupTransportClient transport;
        try {
            transport = transportConnection.connectOrThrow(callerLogString);
        } catch (TransportNotAvailableException e) {
@@ -653,10 +654,6 @@ public class TransportManager {

        int result;
        try {
            // This is a temporary fix to allow blocking calls.
            // TODO: b/147702043. Redesign IBackupTransport so as to make the calls non-blocking.
            Binder.allowBlocking(transport.asBinder());

            String transportName = transport.name();
            String transportDirName = transport.transportDirName();
            registerTransport(transportComponent, transport);
@@ -674,8 +671,8 @@ public class TransportManager {
    }

    /** If {@link RemoteException} is thrown the transport is guaranteed to not be registered. */
    private void registerTransport(ComponentName transportComponent, IBackupTransport transport)
            throws RemoteException {
    private void registerTransport(ComponentName transportComponent,
            BackupTransportClient transport) throws RemoteException {
        checkCanUseTransport();

        TransportDescription description =
+5 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.app.backup.RestoreDescription;
import android.app.backup.RestoreSet;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.os.Binder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;

@@ -35,6 +36,10 @@ public class BackupTransportClient {

    BackupTransportClient(IBackupTransport transportBinder) {
        mTransportBinder = transportBinder;

        // This is a temporary fix to allow blocking calls.
        // TODO: b/147702043. Redesign IBackupTransport so as to make the calls non-blocking.
        Binder.allowBlocking(mTransportBinder.asBinder());
    }

    /**
+32 −28
Original line number Diff line number Diff line
@@ -59,7 +59,7 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

/**
 * A {@link TransportConnection} manages the connection to an {@link IBackupTransport} service,
 * A {@link TransportConnection} manages the connection to a {@link BackupTransportClient},
 * obtained via the {@param bindIntent} parameter provided in the constructor. A
 * {@link TransportConnection} is responsible for only one connection to the transport service,
 * not more.
@@ -67,9 +67,9 @@ import java.util.concurrent.ExecutionException;
 * <p>After retrieved using {@link TransportManager#getTransportClient(String, String)}, you can
 * call either {@link #connect(String)}, if you can block your thread, or {@link
 * #connectAsync(TransportConnectionListener, String)}, otherwise, to obtain a {@link
 * IBackupTransport} instance. It's meant to be passed around as a token to a connected transport.
 * When the connection is not needed anymore you should call {@link #unbind(String)} or indirectly
 * via {@link TransportManager#disposeOfTransportClient(TransportConnection, String)}.
 * BackupTransportClient} instance. It's meant to be passed around as a token to a connected
 * transport. When the connection is not needed anymore you should call {@link #unbind(String)} or
 * indirectly via {@link TransportManager#disposeOfTransportClient(TransportConnection, String)}.
 *
 * <p>DO NOT forget to unbind otherwise there will be dangling connections floating around.
 *
@@ -106,7 +106,7 @@ public class TransportConnection {
    private int mState = State.IDLE;

    @GuardedBy("mStateLock")
    private volatile IBackupTransport mTransport;
    private volatile BackupTransportClient mTransport;

    TransportConnection(
            @UserIdInt int userId,
@@ -174,10 +174,12 @@ public class TransportConnection {
     * trigger another one, just piggyback on the original request.
     *
     * <p>It's guaranteed that you are going to get a call back to {@param listener} after this
     * call. However, the {@param IBackupTransport} parameter, the transport binder, is not
     * guaranteed to be non-null, or if it's non-null it's not guaranteed to be usable - i.e. it can
     * throw {@link DeadObjectException}s on method calls. You should check for both in your code.
     * The reasons for a null transport binder are:
     * call. However, the {@link BackupTransportClient} parameter in
     * {@link TransportConnectionListener#onTransportConnectionResult(BackupTransportClient,
     * TransportConnection)}, the transport client, is not guaranteed to be non-null, or if it's
     * non-null it's not guaranteed to be usable - i.e. it can throw {@link DeadObjectException}s
     * on method calls. You should check for both in your code. The reasons for a null transport
     * client are:
     *
     * <ul>
     *   <li>Some code called {@link #unbind(String)} before you got a callback.
@@ -193,7 +195,7 @@ public class TransportConnection {
     * For unusable transport binders check {@link DeadObjectException}.
     *
     * @param listener The listener that will be called with the (possibly null or unusable) {@link
     *     IBackupTransport} instance and this {@link TransportConnection} object.
     *     BackupTransportClient} instance and this {@link TransportConnection} object.
     * @param caller A {@link String} identifying the caller for logging/debugging purposes. This
     *     should be a human-readable short string that is easily identifiable in the logs. Ideally
     *     TAG.methodName(), where TAG is the one used in logcat. In cases where this is is not very
@@ -293,8 +295,8 @@ public class TransportConnection {
     *
     * <p>Synchronous version of {@link #connectAsync(TransportConnectionListener, String)}. The
     * same observations about state are valid here. Also, what was said about the {@link
     * IBackupTransport} parameter of {@link TransportConnectionListener} now apply to the return
     * value of this method.
     * BackupTransportClient} parameter of {@link TransportConnectionListener} now apply to the
     * return value of this method.
     *
     * <p>This is a potentially blocking operation, so be sure to call this carefully on the correct
     * threads. You can't call this from the process main-thread (it throws an exception if you do
@@ -305,18 +307,18 @@ public class TransportConnection {
     *
     * @param caller A {@link String} identifying the caller for logging/debugging purposes. Check
     *     {@link #connectAsync(TransportConnectionListener, String)} for more details.
     * @return A {@link IBackupTransport} transport binder instance or null. If it's non-null it can
     *     still be unusable - throws {@link DeadObjectException} on method calls
     * @return A {@link BackupTransportClient} transport client instance or null. If it's non-null
     *     it can still be unusable - throws {@link DeadObjectException} on method calls
     */
    @WorkerThread
    @Nullable
    public IBackupTransport connect(String caller) {
    public BackupTransportClient connect(String caller) {
        // If called on the main-thread this could deadlock waiting because calls to
        // ServiceConnection are on the main-thread as well
        Preconditions.checkState(
                !Looper.getMainLooper().isCurrentThread(), "Can't call connect() on main thread");

        IBackupTransport transport = mTransport;
        BackupTransportClient transport = mTransport;
        if (transport != null) {
            log(Priority.DEBUG, caller, "Sync connect: reusing transport");
            return transport;
@@ -330,7 +332,7 @@ public class TransportConnection {
            }
        }

        CompletableFuture<IBackupTransport> transportFuture = new CompletableFuture<>();
        CompletableFuture<BackupTransportClient> transportFuture = new CompletableFuture<>();
        TransportConnectionListener requestListener =
                (requestedTransport, transportClient) ->
                        transportFuture.complete(requestedTransport);
@@ -359,13 +361,14 @@ public class TransportConnection {
     *
     * @param caller A {@link String} identifying the caller for logging/debugging purposes. Check
     *     {@link #connectAsync(TransportConnectionListener, String)} for more details.
     * @return A {@link IBackupTransport} transport binder instance.
     * @return A {@link BackupTransportClient} transport binder instance.
     * @see #connect(String)
     * @throws TransportNotAvailableException if connection attempt fails.
     */
    @WorkerThread
    public IBackupTransport connectOrThrow(String caller) throws TransportNotAvailableException {
        IBackupTransport transport = connect(caller);
    public BackupTransportClient connectOrThrow(String caller)
            throws TransportNotAvailableException {
        BackupTransportClient transport = connect(caller);
        if (transport == null) {
            log(Priority.ERROR, caller, "Transport connection failed");
            throw new TransportNotAvailableException();
@@ -379,12 +382,12 @@ public class TransportConnection {
     *
     * @param caller A {@link String} identifying the caller for logging/debugging purposes. Check
     *     {@link #connectAsync(TransportConnectionListener, String)} for more details.
     * @return A {@link IBackupTransport} transport binder instance.
     * @return A {@link BackupTransportClient} transport client instance.
     * @throws TransportNotAvailableException if not connected.
     */
    public IBackupTransport getConnectedTransport(String caller)
    public BackupTransportClient getConnectedTransport(String caller)
            throws TransportNotAvailableException {
        IBackupTransport transport = mTransport;
        BackupTransportClient transport = mTransport;
        if (transport == null) {
            log(Priority.ERROR, caller, "Transport not connected");
            throw new TransportNotAvailableException();
@@ -425,7 +428,8 @@ public class TransportConnection {
    }

    private void onServiceConnected(IBinder binder) {
        IBackupTransport transport = IBackupTransport.Stub.asInterface(binder);
        IBackupTransport transportBinder = IBackupTransport.Stub.asInterface(binder);
        BackupTransportClient transport = new BackupTransportClient(transportBinder);
        synchronized (mStateLock) {
            checkStateIntegrityLocked();

@@ -492,15 +496,15 @@ public class TransportConnection {

    private void notifyListener(
            TransportConnectionListener listener,
            @Nullable IBackupTransport transport,
            @Nullable BackupTransportClient transport,
            String caller) {
        String transportString = (transport != null) ? "IBackupTransport" : "null";
        String transportString = (transport != null) ? "BackupTransportClient" : "null";
        log(Priority.INFO, "Notifying [" + caller + "] transport = " + transportString);
        mListenerHandler.post(() -> listener.onTransportConnectionResult(transport, this));
    }

    @GuardedBy("mStateLock")
    private void notifyListenersAndClearLocked(@Nullable IBackupTransport transport) {
    private void notifyListenersAndClearLocked(@Nullable BackupTransportClient transport) {
        for (Map.Entry<TransportConnectionListener, String> entry : mListeners.entrySet()) {
            TransportConnectionListener listener = entry.getKey();
            String caller = entry.getValue();
@@ -510,7 +514,7 @@ public class TransportConnection {
    }

    @GuardedBy("mStateLock")
    private void setStateLocked(@State int state, @Nullable IBackupTransport transport) {
    private void setStateLocked(@State int state, @Nullable BackupTransportClient transport) {
        log(Priority.VERBOSE, "State: " + stateToString(mState) + " => " + stateToString(state));
        onStateTransition(mState, state);
        mState = state;
+6 −5
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@ package com.android.server.backup.transport;

import android.annotation.Nullable;

import com.android.internal.backup.IBackupTransport;
import com.android.server.backup.transport.BackupTransportClient;

/**
 * Listener to be called by {@link TransportConnection#connectAsync(TransportConnectionListener,
@@ -26,13 +26,14 @@ import com.android.internal.backup.IBackupTransport;
 */
public interface TransportConnectionListener {
    /**
     * Called when {@link TransportConnection} has a transport binder available or that it decided
     * Called when {@link TransportConnection} has a transport client available or that it decided
     * it couldn't obtain one, in which case {@param transport} is null.
     *
     * @param transport A {@link IBackupTransport} transport binder or null.
     * @param transportClient A {@link BackupTransportClient} transport or null.
     * @param transportConnection The {@link TransportConnection} used to retrieve this transport
     *                            binder.
     *                            client.
     */
    void onTransportConnectionResult(
            @Nullable IBackupTransport transport, TransportConnection transportConnection);
            @Nullable BackupTransportClient transportClient,
            TransportConnection transportConnection);
}
+4 −3
Original line number Diff line number Diff line
@@ -103,7 +103,6 @@ import android.util.SparseArray;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.backup.IBackupTransport;
import com.android.internal.util.Preconditions;
import com.android.server.AppWidgetBackupBridge;
import com.android.server.EventLogTags;
@@ -127,6 +126,7 @@ import com.android.server.backup.params.ClearRetryParams;
import com.android.server.backup.params.RestoreParams;
import com.android.server.backup.restore.ActiveRestoreSession;
import com.android.server.backup.restore.PerformUnifiedRestoreTask;
import com.android.server.backup.transport.BackupTransportClient;
import com.android.server.backup.transport.TransportConnection;
import com.android.server.backup.transport.TransportNotAvailableException;
import com.android.server.backup.transport.TransportNotRegisteredException;
@@ -3719,7 +3719,8 @@ public class UserBackupManagerService {
                mTransportManager.getTransportClient(newTransportName, callerLogString);
        if (transportConnection != null) {
            try {
                IBackupTransport transport = transportConnection.connectOrThrow(callerLogString);
                BackupTransportClient transport = transportConnection.connectOrThrow(
                        callerLogString);
                mCurrentToken = transport.getCurrentRestoreSet();
            } catch (Exception e) {
                // Oops.  We can't know the current dataset token, so reset and figure it out
@@ -4371,7 +4372,7 @@ public class UserBackupManagerService {

        final long oldCallingId = Binder.clearCallingIdentity();
        try {
            IBackupTransport transport = transportConnection.connectOrThrow(
            BackupTransportClient transport = transportConnection.connectOrThrow(
                    /* caller */ "BMS.getOperationTypeFromTransport");
            if ((transport.getTransportFlags() & BackupAgent.FLAG_DEVICE_TO_DEVICE_TRANSFER) != 0) {
                return OperationType.MIGRATION;
Loading