Home | History | Annotate | Download | only in backup
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License
     15  */
     16 
     17 package android.cts.backup;
     18 
     19 import com.android.tradefed.build.IBuildInfo;
     20 import com.android.tradefed.config.Option;
     21 import com.android.tradefed.config.OptionClass;
     22 import com.android.tradefed.device.CollectingOutputReceiver;
     23 import com.android.tradefed.device.DeviceNotAvailableException;
     24 import com.android.tradefed.device.ITestDevice;
     25 import com.android.tradefed.log.LogUtil.CLog;
     26 import com.android.tradefed.targetprep.BuildError;
     27 import com.android.tradefed.targetprep.ITargetCleaner;
     28 import com.android.tradefed.targetprep.TargetSetupError;
     29 
     30 import java.util.concurrent.TimeUnit;
     31 import java.util.regex.Matcher;
     32 import java.util.regex.Pattern;
     33 
     34 /**
     35  * Tradedfed target preparer for the backup tests.
     36  * Enables backup before all the tests and selects local transport.
     37  * Reverts to the original state after all the tests are executed.
     38  */
     39 @OptionClass(alias = "backup-preparer")
     40 public class BackupPreparer implements ITargetCleaner {
     41     @Option(name="enable-backup-if-needed", description=
     42             "Enable backup before all the tests and return to the original state after.")
     43     private boolean mEnableBackup = true;
     44 
     45     @Option(name="select-local-transport", description=
     46             "Select local transport before all the tests and return to the original transport "
     47                     + "after.")
     48     private boolean mSelectLocalTransport = true;
     49 
     50     /** Value of PackageManager.FEATURE_BACKUP */
     51     private static final String FEATURE_BACKUP = "android.software.backup";
     52 
     53     private static final String LOCAL_TRANSPORT =
     54             "android/com.android.internal.backup.LocalTransport";
     55 
     56     private static final int BACKUP_PROVISIONING_TIMEOUT_SECONDS = 30;
     57     private static final int BACKUP_PROVISIONING_POLL_INTERVAL_SECONDS = 1;
     58 
     59     private boolean mIsBackupSupported;
     60     private boolean mWasBackupEnabled;
     61     private String mOldTransport;
     62     private ITestDevice mDevice;
     63 
     64     @Override
     65     public void setUp(ITestDevice device, IBuildInfo buildInfo)
     66             throws TargetSetupError, BuildError, DeviceNotAvailableException {
     67         mDevice = device;
     68 
     69         mIsBackupSupported = mDevice.hasFeature("feature:" + FEATURE_BACKUP);
     70 
     71         // In case the device was just rebooted, wait for the broadcast queue to get idle to avoid
     72         // any interference from services doing backup clean up on reboot.
     73         waitForBroadcastIdle();
     74 
     75         if (mIsBackupSupported) {
     76             // Enable backup and select local backup transport
     77             if (!hasBackupTransport(LOCAL_TRANSPORT)) {
     78                 throw new TargetSetupError("Device should have LocalTransport available",
     79                         device.getDeviceDescriptor());
     80             }
     81             if (mEnableBackup) {
     82                 CLog.i("Enabling backup on %s", mDevice.getSerialNumber());
     83                 mWasBackupEnabled = enableBackup(true);
     84                 CLog.d("Backup was enabled? : %s", mWasBackupEnabled);
     85                 if (mSelectLocalTransport) {
     86                     CLog.i("Selecting local transport on %s", mDevice.getSerialNumber());
     87                     mOldTransport = setBackupTransport(LOCAL_TRANSPORT);
     88                     CLog.d("Old transport : %s", mOldTransport);
     89                 }
     90                 waitForBackupInitialization();
     91             }
     92         }
     93     }
     94 
     95     @Override
     96     public void tearDown(ITestDevice device, IBuildInfo buildInfo, Throwable e)
     97             throws DeviceNotAvailableException {
     98         mDevice = device;
     99 
    100         if (mIsBackupSupported) {
    101             if (mEnableBackup) {
    102                 CLog.i("Returning backup to it's previous state on %s", mDevice.getSerialNumber());
    103                 enableBackup(mWasBackupEnabled);
    104                 if (mSelectLocalTransport) {
    105                     CLog.i("Returning selected transport to it's previous value on %s",
    106                             mDevice.getSerialNumber());
    107                     setBackupTransport(mOldTransport);
    108                 }
    109             }
    110         }
    111     }
    112 
    113     // Copied over from BackupQuotaTest
    114     private boolean hasBackupTransport(String transport) throws DeviceNotAvailableException {
    115         String output = mDevice.executeShellCommand("bmgr list transports");
    116         for (String t : output.split(" ")) {
    117             if (transport.equals(t.trim())) {
    118                 return true;
    119             }
    120         }
    121         return false;
    122     }
    123 
    124     // Copied over from BackupQuotaTest
    125     private boolean enableBackup(boolean enable) throws DeviceNotAvailableException {
    126         boolean previouslyEnabled;
    127         String output = mDevice.executeShellCommand("bmgr enabled");
    128         Pattern pattern = Pattern.compile("^Backup Manager currently (enabled|disabled)$");
    129         Matcher matcher = pattern.matcher(output.trim());
    130         if (matcher.find()) {
    131             previouslyEnabled = "enabled".equals(matcher.group(1));
    132         } else {
    133             throw new RuntimeException("non-parsable output setting bmgr enabled: " + output);
    134         }
    135 
    136         mDevice.executeShellCommand("bmgr enable " + enable);
    137         return previouslyEnabled;
    138     }
    139 
    140     // Copied over from BackupQuotaTest
    141     private String setBackupTransport(String transport) throws DeviceNotAvailableException {
    142         String output = mDevice.executeShellCommand("bmgr transport " + transport);
    143         Pattern pattern = Pattern.compile("\\(formerly (.*)\\)$");
    144         Matcher matcher = pattern.matcher(output);
    145         if (matcher.find()) {
    146             return matcher.group(1);
    147         } else {
    148             throw new RuntimeException("non-parsable output setting bmgr transport: " + output);
    149         }
    150     }
    151 
    152     private void waitForBackupInitialization()
    153         throws TargetSetupError, DeviceNotAvailableException {
    154         long tryUntilNanos = System.nanoTime()
    155             + TimeUnit.SECONDS.toNanos(BACKUP_PROVISIONING_TIMEOUT_SECONDS);
    156         while (System.nanoTime() < tryUntilNanos) {
    157             String output = mDevice.executeShellCommand("dumpsys backup");
    158             if (output.matches("(?s)"  // DOTALL
    159                 + "^Backup Manager is .* not pending init.*")) {
    160                 return;
    161             }
    162             try {
    163                 Thread.sleep(TimeUnit.SECONDS.toMillis(BACKUP_PROVISIONING_POLL_INTERVAL_SECONDS));
    164             } catch (InterruptedException e) {
    165                 Thread.currentThread().interrupt();
    166                 break;
    167             }
    168         }
    169         throw new TargetSetupError("Timed out waiting for backup initialization",
    170             mDevice.getDeviceDescriptor());
    171     }
    172 
    173     // Copied over from BaseDevicePolicyTest
    174     private void waitForBroadcastIdle() throws DeviceNotAvailableException, TargetSetupError {
    175         CollectingOutputReceiver receiver = new CollectingOutputReceiver();
    176         try {
    177             // we allow 20 min for the command to complete and 10 min for the command to start to
    178             // output something
    179             mDevice.executeShellCommand(
    180                     "am wait-for-broadcast-idle", receiver, 20, 10, TimeUnit.MINUTES, 0);
    181         } finally {
    182             String output = receiver.getOutput();
    183             CLog.d("Output from 'am wait-for-broadcast-idle': %s", output);
    184             if (!output.contains("All broadcast queues are idle!")) {
    185                 // the call most likely failed we should fail the test
    186                 throw new TargetSetupError("'am wait-for-broadcase-idle' did not complete.",
    187                         mDevice.getDeviceDescriptor());
    188                 // TODO: consider adding a reboot or recovery before failing if necessary
    189             }
    190         }
    191     }
    192 
    193 }
    194