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

Commit 2d87f453 authored by Bernardo Rufino's avatar Bernardo Rufino
Browse files

[KV] State machine to linear task w/ RemoteCall

This is the first CL of key-value backup refactor.

* Method execute() that executed the state machine states is now empty
  and run() is created with the initial version of the linear task. It's
  basically composed of begin + loop + end. Although it still has the notion
  of state, it's more restricted than before (with private methods returning
  the next state). This is intentional to avoid making this CL too heavy to
  review and to avoid too much behavioral changes here. In the next CLs I
  intend to remove BackupState.

* Introduction of RemoteCall, which encapsulates an outbound call that
  leaves the system_server, with time-out and cancellation built-in.
  Agent calls are now triggered using this. As a result there is no more
  operationComplete() method either.

* Cancellation now is cleaner. We don't need a step lock anymore, only a
  (volatile) boolean that is checked in every queue iteration. If asked
  to cancel during an ongoing agent call we rely on RemoteCall.cancel()
  to return control of the task thread to us. We wait for the cancel
  acknowledgement to preserve the contract of no more transport calls.

* PFTBT instantiation moved from the constructor to the run() method,
  which makes more sense.

* No need for mFinished, mBackupData == null bookkeeping since time-outs,
  cancellation and legitimate agent responses won't step into one another
  anymore.

* Ternary (mQueue.isEmpty) ? BackupState.FINAL : BackupState.RUNNING_QUEUE gone
  because we check this in the beginning of invokeNextAgent() and now we
  don't pay the state-machine tick price associated with the handler.

* PerformBackupTask call sites now call static method start(), that
  spins up a new dedicated thread for the task. This new thread is
  assigned the same (process) priority as the backup thread
  (THREAD_PRIORITY_BACKGROUND).

Work left for future CLs:

* RemoteCall spins up a new thread for kicking off the call, this is for
  system agents that are executed inline. Old PBT also executed in the same
  thread (backup handler thread), so maintaining this to keep this CL at
  a reasonable size.

Test: atest PerformBackupTaskTest
Test: atest RunFrameworksServicesRoboTests
Test: atest frameworks/base/services/tests/servicestests/src/com/android/server/backup
Test: atest CtsBackupTestCases
Test: atest CtsBackupHostTestCases
Test: atest GtsBackupTestCases
Test: atest GtsBackupHostTestCases
Test: adb shell bmgr backupnow <kv_packages>
Test: 1. adb shell bmgr backup <p1> <p2>
      2. adb shell bmgr run
      A) 3. Cancel while sending <p1> data to transport
         4. Verify <p1> is backed-up and not pending
	    Verify <p2> is not backed-up and is pending
      B) 3. Cancel while waiting for <p1> agent
         4. Verify <p1> is not backed-up and is pending
	    Verify <p2> is not backed-up and is pending

Change-Id: Ia456c4e807de95d662c9e923245be07e8996f58a
parent 9a64ba26
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -94,6 +94,7 @@ java_library {
        "core/java/android/app/trust/IStrongAuthTracker.aidl",
        "core/java/android/app/trust/ITrustManager.aidl",
        "core/java/android/app/trust/ITrustListener.aidl",
        "core/java/android/app/backup/IBackupCallback.aidl",
        "core/java/android/app/backup/IBackupManager.aidl",
        "core/java/android/app/backup/IBackupObserver.aidl",
        "core/java/android/app/backup/IBackupManagerMonitor.aidl",
+2 −1
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.app;

import android.app.backup.IBackupCallback;
import android.app.backup.IBackupManager;
import android.os.ParcelFileDescriptor;
 
@@ -55,7 +56,7 @@ oneway interface IBackupAgent {
    void doBackup(in ParcelFileDescriptor oldState,
            in ParcelFileDescriptor data,
            in ParcelFileDescriptor newState,
            long quotaBytes, int token, IBackupManager callbackBinder, int transportFlags);
            long quotaBytes, IBackupCallback callbackBinder, int transportFlags);

    /**
     * Restore an entire data snapshot to the application.
+6 −4
Original line number Diff line number Diff line
@@ -941,11 +941,13 @@ public abstract class BackupAgent extends ContextWrapper {
        private static final String TAG = "BackupServiceBinder";

        @Override
        public void doBackup(ParcelFileDescriptor oldState,
        public void doBackup(
                ParcelFileDescriptor oldState,
                ParcelFileDescriptor data,
                ParcelFileDescriptor newState,
                long quotaBytes, int token, IBackupManager callbackBinder, int transportFlags)
                throws RemoteException {
                long quotaBytes,
                IBackupCallback callbackBinder,
                int transportFlags) throws RemoteException {
            // Ensure that we're running with the app's normal permission level
            long ident = Binder.clearCallingIdentity();

@@ -969,7 +971,7 @@ public abstract class BackupAgent extends ContextWrapper {

                Binder.restoreCallingIdentity(ident);
                try {
                    callbackBinder.opComplete(token, 0);
                    callbackBinder.operationComplete(0);
                } catch (RemoteException e) {
                    // we'll time out anyway, so we're safe
                }
+29 −0
Original line number Diff line number Diff line
/*
 * Copyright 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.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.app.backup;

import android.app.backup.IBackupManager;
import android.os.ParcelFileDescriptor;

/**
 * Callback interface made for responding to one-way calls from the system.
 *
 * @hide
 */
oneway interface IBackupCallback {
    void operationComplete(long result);
}
+11 −2
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@ import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP_WAIT

import android.app.ApplicationThreadConstants;
import android.app.IBackupAgent;
import android.app.backup.IBackupCallback;
import android.app.backup.FullBackup;
import android.app.backup.FullBackupDataOutput;
import android.content.pm.ApplicationInfo;
@@ -20,6 +21,7 @@ import android.os.SELinux;
import android.util.Slog;

import com.android.internal.util.Preconditions;
import com.android.server.backup.remote.ServiceBackupCallback;
import com.android.server.backup.utils.FullBackupUtils;

import libcore.io.IoUtils;
@@ -158,10 +160,17 @@ public class KeyValueAdbBackupEngine {
            mBackupManagerService.prepareOperationTimeout(token, kvBackupAgentTimeoutMillis, null,
                    OP_TYPE_BACKUP_WAIT);

            IBackupCallback callback =
                    new ServiceBackupCallback(
                            mBackupManagerService.getBackupManagerBinder(), token);
            // Start backup and wait for BackupManagerService to get callback for success or timeout
            agent.doBackup(
                    mSavedState, mBackupData, mNewState, Long.MAX_VALUE, token,
                    mBackupManagerService.getBackupManagerBinder(), /*transportFlags=*/ 0);
                    mSavedState,
                    mBackupData,
                    mNewState,
                    /* quotaBytes */ Long.MAX_VALUE,
                    callback,
                    /* transportFlags */ 0);
            if (!mBackupManagerService.waitUntilOperationComplete(token)) {
                Slog.e(TAG, "Key-value backup failed on package " + packageName);
                return false;
Loading