Home | History | Annotate | Download | only in backup
      1 /*
      2  * Copyright (C) 2018 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 static org.junit.Assert.assertNull;
     20 
     21 import com.android.tradefed.device.DeviceNotAvailableException;
     22 import com.android.tradefed.log.LogUtil.CLog;
     23 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
     24 
     25 import org.junit.After;
     26 import org.junit.Before;
     27 import org.junit.Test;
     28 import org.junit.runner.RunWith;
     29 
     30 import java.util.ArrayList;
     31 import java.util.Arrays;
     32 import java.util.List;
     33 
     34 /**
     35  * Tests for checking that an observer app is notified by a broadcast Intent whenever a backup
     36  * succeeds.
     37  *
     38  * NB: The tests use "bmgr backupnow" for backup, which works on N+ devices.
     39  */
     40 @RunWith(DeviceJUnit4ClassRunner.class)
     41 public class SuccessNotificationHostSideTest extends BaseBackupHostSideTest {
     42 
     43     /** The name of the package that a key/value backup will be run for */
     44     private static final String KEY_VALUE_BACKUP_APP_PACKAGE =
     45             "android.cts.backup.keyvaluerestoreapp";
     46 
     47     /** The name of the package that a full backup will be run for */
     48     private static final String FULL_BACKUP_APP_PACKAGE = "android.cts.backup.fullbackuponlyapp";
     49 
     50     /** The name of the package that observes backup results. */
     51     private static final String SUCCESS_NOTIFICATION_APP_PACKAGE =
     52             "android.cts.backup.successnotificationapp";
     53 
     54     /** The name of the device side test class in the APK that a key/value backup will be run for */
     55     private static final String KEY_VALUE_BACKUP_DEVICE_TEST_NAME =
     56             KEY_VALUE_BACKUP_APP_PACKAGE + ".KeyValueBackupRestoreTest";
     57 
     58     /** The name of the device side test class in the APK that a full backup will be run for */
     59     private static final String FULL_BACKUP_DEVICE_TEST_CLASS_NAME =
     60             FULL_BACKUP_APP_PACKAGE + ".FullBackupOnlyTest";
     61 
     62     /** The name of the device side test class in the APK that observes backup results */
     63     private static final String SUCCESS_NOTIFICATION_DEVICE_TEST_NAME =
     64             SUCCESS_NOTIFICATION_APP_PACKAGE + ".SuccessNotificationTest";
     65 
     66     /** The name of the APK that a key/value backup will be run for */
     67     private static final String KEY_VALUE_BACKUP_APP_APK = "CtsKeyValueBackupRestoreApp.apk";
     68 
     69     /** The name of the APK that a full backup will be run for */
     70     private static final String FULL_BACKUP_APP_APK = "FullBackupOnlyFalseWithAgentApp.apk";
     71 
     72     /** The name of the APK that observes backup results */
     73     private static final String SUCCESS_NOTIFICATION_APP_APK =
     74             "CtsBackupSuccessNotificationApp.apk";
     75 
     76     /** Secure setting that holds the backup manager configuration as key-value pairs */
     77     private static final String BACKUP_MANAGER_CONSTANTS_PREF = "backup_manager_constants";
     78 
     79     /** Key for specifying the apps that the backup manager should notify of successful backups */
     80     private static final String BACKUP_FINISHED_NOTIFICATION_RECEIVERS =
     81             "backup_finished_notification_receivers";
     82 
     83     /** The original backup manager configuration */
     84     private String mOriginalBackupManagerConstants = null;
     85 
     86     @Before
     87     @Override
     88     public void setUp() throws Exception {
     89         super.setUp();
     90 
     91         if (!mIsBackupSupported) {
     92             CLog.i("android.software.backup feature is not supported on this device");
     93             return;
     94         }
     95 
     96         installPackage(KEY_VALUE_BACKUP_APP_APK);
     97         installPackage(FULL_BACKUP_APP_APK);
     98 
     99         installPackage(SUCCESS_NOTIFICATION_APP_APK);
    100         checkDeviceTest("clearBackupSuccessNotificationsReceived");
    101         addBackupFinishedNotificationReceiver();
    102     }
    103 
    104     @After
    105     @Override
    106     public void tearDown() throws Exception {
    107         super.tearDown();
    108 
    109         if (!mIsBackupSupported) {
    110             return;
    111         }
    112 
    113         restoreBackupFinishedNotificationReceivers();
    114         assertNull(uninstallPackage(SUCCESS_NOTIFICATION_APP_PACKAGE));
    115 
    116         // Clear backup data and uninstall the package (in that order!)
    117         clearBackupDataInLocalTransport(KEY_VALUE_BACKUP_APP_PACKAGE);
    118         assertNull(uninstallPackage(KEY_VALUE_BACKUP_APP_PACKAGE));
    119 
    120         clearBackupDataInLocalTransport(FULL_BACKUP_APP_PACKAGE);
    121         assertNull(uninstallPackage(FULL_BACKUP_APP_PACKAGE));
    122     }
    123 
    124     /**
    125      * Test that the observer app is notified when a key/value backup succeeds.
    126      *
    127      * Test logic:
    128      *   1. Change a test app's data, trigger a key/value backup and wait for it to complete.
    129      *   2. Verify that the observer app was informed about the backup.
    130      */
    131     @Test
    132     public void testSuccessNotificationForKeyValueBackup() throws Exception {
    133         if (!mIsBackupSupported) {
    134             return;
    135         }
    136 
    137         checkDeviceTest(KEY_VALUE_BACKUP_APP_PACKAGE, KEY_VALUE_BACKUP_DEVICE_TEST_NAME,
    138                 "saveSharedPreferencesAndNotifyBackupManager");
    139         backupNowAndAssertSuccess(KEY_VALUE_BACKUP_APP_PACKAGE);
    140 
    141         checkDeviceTest("verifyBackupSuccessNotificationReceivedForKeyValueApp");
    142     }
    143 
    144     /**
    145      * Test that the observer app is notified when a full backup succeeds.
    146      *
    147      * Test logic:
    148      *   1. Change a test app's data, trigger a full backup and wait for it to complete.
    149      *   2. Verify that the observer app was informed about the backup.
    150      */
    151     @Test
    152     public void testSuccessNotificationForFullBackup() throws Exception {
    153         if (!mIsBackupSupported) {
    154             return;
    155         }
    156 
    157         checkDeviceTest(FULL_BACKUP_APP_PACKAGE, FULL_BACKUP_DEVICE_TEST_CLASS_NAME, "createFiles");
    158         backupNowAndAssertSuccess(FULL_BACKUP_APP_PACKAGE);
    159 
    160         checkDeviceTest("verifyBackupSuccessNotificationReceivedForFullBackupApp");
    161     }
    162 
    163     /**
    164      * Instructs the backup manager to notify the observer app whenever a backup succeeds. The old
    165      * backup manager configuration is stored in a member variable and can be restored by calling
    166      * {@link restoreBackupFinishedNotificationReceivers}.
    167      */
    168     private void addBackupFinishedNotificationReceiver()
    169             throws DeviceNotAvailableException {
    170         mOriginalBackupManagerConstants = getDevice().executeShellCommand(String.format(
    171                 "settings get secure %s", BACKUP_MANAGER_CONSTANTS_PREF)).trim();
    172         if ("null".equals(mOriginalBackupManagerConstants)) {
    173             mOriginalBackupManagerConstants = null;
    174         }
    175         String backupManagerConstants = null;
    176 
    177         if (mOriginalBackupManagerConstants == null || mOriginalBackupManagerConstants.isEmpty()) {
    178             backupManagerConstants =
    179                     BACKUP_FINISHED_NOTIFICATION_RECEIVERS + "=" + SUCCESS_NOTIFICATION_APP_PACKAGE;
    180         } else {
    181             final List<String> keyValuePairs =
    182                     new ArrayList<>(Arrays.asList(mOriginalBackupManagerConstants.split(",")));
    183             boolean present = false;
    184             for (int i = 0; i < keyValuePairs.size(); ++i) {
    185                 final String keyValuePair = keyValuePairs.get(i);
    186                 final String[] fields = keyValuePair.split("=");
    187                 final String key = fields[0].trim();
    188                 if (BACKUP_FINISHED_NOTIFICATION_RECEIVERS.equals(key)) {
    189                     if (fields.length == 1 || fields[1].trim().isEmpty()) {
    190                         keyValuePairs.set(i, key + "=" + SUCCESS_NOTIFICATION_APP_PACKAGE);
    191                     } else {
    192                         final String[] values = fields[1].split(":");
    193                         for (int j = 0; j < values.length; ++j) {
    194                             if (SUCCESS_NOTIFICATION_APP_PACKAGE.equals(values[j].trim())) {
    195                                 present = true;
    196                                 break;
    197                             }
    198                         }
    199                         if (!present) {
    200                             keyValuePairs.set(i,
    201                                     keyValuePair + ":" + SUCCESS_NOTIFICATION_APP_PACKAGE);
    202                         }
    203                     }
    204                     present = true;
    205                     break;
    206                 }
    207             }
    208             if (!present) {
    209                 keyValuePairs.add(BACKUP_FINISHED_NOTIFICATION_RECEIVERS + "=" +
    210                         SUCCESS_NOTIFICATION_APP_PACKAGE);
    211             }
    212             backupManagerConstants = String.join(",", keyValuePairs);
    213         }
    214         setBackupManagerConstants(backupManagerConstants);
    215     }
    216 
    217     /**
    218      * Restores the backup manager configuration stored by a previous call to
    219      * {@link addBackupFinishedNotificationReceiver}.
    220      */
    221     private void restoreBackupFinishedNotificationReceivers() throws DeviceNotAvailableException {
    222         setBackupManagerConstants(mOriginalBackupManagerConstants);
    223     }
    224 
    225     private void setBackupManagerConstants(String backupManagerConstants)
    226             throws DeviceNotAvailableException {
    227         getDevice().executeShellCommand(String.format("settings put secure %s %s",
    228                 BACKUP_MANAGER_CONSTANTS_PREF, backupManagerConstants));
    229     }
    230 
    231     private void checkDeviceTest(String methodName) throws DeviceNotAvailableException {
    232         checkDeviceTest(SUCCESS_NOTIFICATION_APP_PACKAGE, SUCCESS_NOTIFICATION_DEVICE_TEST_NAME,
    233                 methodName);
    234     }
    235 }
    236