1 /* 2 * Copyright (C) 2019 Google Inc. 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.restoresessionapp; 18 19 import static androidx.test.InstrumentationRegistry.getInstrumentation; 20 import static androidx.test.InstrumentationRegistry.getTargetContext; 21 22 import static com.google.common.truth.Truth.assertThat; 23 24 import static junit.framework.Assert.assertEquals; 25 import static junit.framework.Assert.assertTrue; 26 27 import static org.junit.Assert.assertNotEquals; 28 29 import android.app.UiAutomation; 30 import android.app.backup.BackupManager; 31 import android.app.backup.BackupManagerMonitor; 32 import android.app.backup.RestoreObserver; 33 import android.app.backup.RestoreSession; 34 import android.app.backup.RestoreSet; 35 import android.content.Context; 36 import android.os.Bundle; 37 import android.platform.test.annotations.AppModeFull; 38 39 import androidx.annotation.Nullable; 40 import androidx.test.runner.AndroidJUnit4; 41 42 import org.junit.After; 43 import org.junit.Before; 44 import org.junit.Test; 45 import org.junit.runner.RunWith; 46 47 import java.util.Arrays; 48 import java.util.HashSet; 49 import java.util.List; 50 import java.util.Set; 51 import java.util.concurrent.CountDownLatch; 52 import java.util.concurrent.TimeUnit; 53 54 /** 55 * Device side routines to be invoked by the host side RestoreSessionHostSideTest. These are not 56 * designed to be called in any other way, as they rely on state set up by the host side test. 57 */ 58 @RunWith(AndroidJUnit4.class) 59 @AppModeFull 60 public class RestoreSessionTest { 61 private static final String[] PACKAGES = new String[] { 62 "android.cts.backup.restoresessionapp1", 63 "android.cts.backup.restoresessionapp2", 64 }; 65 66 private static final int PACKAGES_COUNT = 2; 67 private static final int RESTORE_TIMEOUT_SECONDS = 20; 68 69 private BackupManager mBackupManager; 70 private Set<String> mRestorePackages; 71 private Set<String> mNonRestorePackages; 72 private CountDownLatch mRestoreSetsLatch; 73 private CountDownLatch mRestoreObserverLatch; 74 private RestoreSession mRestoreSession; 75 private UiAutomation mUiAutomation; 76 private long mRestoreToken; 77 78 private final RestoreObserver mRestoreObserver = 79 new RestoreObserver() { 80 @Override 81 public void restoreSetsAvailable(RestoreSet[] result) { 82 super.restoreSetsAvailable(result); 83 84 long token = 0L; 85 86 for (RestoreSet restoreSet : result) { 87 long restoreToken = restoreSet.token; 88 if (doesRestoreSetContainAllPackages(restoreToken, mRestorePackages) 89 && doesRestoreSetContainAllPackages( 90 restoreToken, mNonRestorePackages)) { 91 token = restoreSet.token; 92 break; 93 } 94 } 95 96 mRestoreToken = token; 97 98 mRestoreSetsLatch.countDown(); 99 } 100 101 @Override 102 public void restoreStarting(int numPackages) { 103 super.restoreStarting(numPackages); 104 105 assertEquals( 106 "Wrong number of packages in the restore set", 107 mRestorePackages.size(), 108 numPackages); 109 mRestoreObserverLatch.countDown(); 110 } 111 112 @Override 113 public void onUpdate(int nowBeingRestored, String currentPackage) { 114 super.onUpdate(nowBeingRestored, currentPackage); 115 116 assertTrue( 117 "Restoring package that is not in mRestorePackages", 118 mRestorePackages.contains(currentPackage)); 119 mRestoreObserverLatch.countDown(); 120 } 121 122 @Override 123 public void restoreFinished(int error) { 124 super.restoreFinished(error); 125 126 assertEquals( 127 "Restore finished with error: " + error, BackupManager.SUCCESS, error); 128 mRestoreObserverLatch.countDown(); 129 } 130 }; 131 132 @Before setUp()133 public void setUp() throws InterruptedException { 134 Context context = getTargetContext(); 135 mBackupManager = new BackupManager(context); 136 137 mRestoreToken = 0L; 138 139 mUiAutomation = getInstrumentation().getUiAutomation(); 140 mUiAutomation.adoptShellPermissionIdentity(); 141 mRestoreSession = mBackupManager.beginRestoreSession(); 142 } 143 144 @After tearDown()145 public void tearDown() { 146 mUiAutomation.dropShellPermissionIdentity(); 147 mRestoreSession.endRestoreSession(); 148 } 149 150 /** 151 * Restore packages added to mRestorePackages and verify only those packages are restored. Use 152 * {@link RestoreSession#restorePackage(String, RestoreObserver)} 153 */ 154 @Test testRestorePackage()155 public void testRestorePackage() throws InterruptedException { 156 initPackagesToRestore(/* packagesCount */ 1); 157 testRestorePackagesInternal((BackupManagerMonitor monitor) -> { 158 mRestoreSession.restorePackage( 159 mRestorePackages.iterator().next(), 160 mRestoreObserver); 161 }, false); 162 } 163 164 /** 165 * Restore packages added to mRestorePackages and verify only those packages are restored. Use 166 * {@link RestoreSession#restorePackage(String, RestoreObserver, BackupManagerMonitor)} 167 */ 168 @Test testRestorePackageWithMonitorParam()169 public void testRestorePackageWithMonitorParam() throws InterruptedException { 170 initPackagesToRestore(/* packagesCount */ 1); 171 testRestorePackagesInternal((BackupManagerMonitor monitor) -> { 172 mRestoreSession.restorePackage( 173 mRestorePackages.iterator().next(), 174 mRestoreObserver, 175 monitor); 176 }, true); 177 } 178 179 /** 180 * Restore packages added to mRestorePackages and verify only those packages are restored. Use 181 * {@link RestoreSession#restorePackages(long, RestoreObserver, Set)} 182 */ 183 @Test testRestorePackages()184 public void testRestorePackages() throws InterruptedException { 185 initPackagesToRestore(/* packagesCount */ 1); 186 testRestorePackagesInternal((BackupManagerMonitor monitor) -> { 187 mRestoreSession.restorePackages( 188 mRestoreToken, 189 mRestoreObserver, 190 mRestorePackages); 191 }, false); 192 } 193 194 /** 195 * Restore packages added to mRestorePackages and verify only those packages are restored. Use 196 * {@link RestoreSession#restorePackages(long, RestoreObserver, Set, BackupManagerMonitor)} 197 */ 198 @Test testRestorePackagesWithMonitorParam()199 public void testRestorePackagesWithMonitorParam() throws InterruptedException { 200 initPackagesToRestore(/* packagesCount */ 1); 201 testRestorePackagesInternal((BackupManagerMonitor monitor) -> { 202 mRestoreSession.restorePackages( 203 mRestoreToken, 204 mRestoreObserver, 205 mRestorePackages, 206 monitor); 207 }, true); 208 } 209 testRestorePackagesInternal(RestoreRunner restoreRunner, boolean useMonitorParam)210 private void testRestorePackagesInternal(RestoreRunner restoreRunner, boolean useMonitorParam) 211 throws InterruptedException { 212 CountDownLatch backupMonitorLatch = null; 213 if (useMonitorParam) { 214 // Wait for the callbacks from BackupManagerMonitor: one for each package. 215 backupMonitorLatch = new CountDownLatch(mRestorePackages.size()); 216 BackupManagerMonitor backupMonitor = new TestBackupMonitor(backupMonitorLatch); 217 218 loadAvailableRestoreSets(backupMonitor); 219 220 restoreRunner.runRestore(backupMonitor); 221 } else { 222 loadAvailableRestoreSets(null); 223 restoreRunner.runRestore(null); 224 } 225 226 awaitResultAndAssertSuccess(mRestoreObserverLatch); 227 if (backupMonitorLatch != null) { 228 awaitResultAndAssertSuccess(backupMonitorLatch); 229 } 230 } 231 loadAvailableRestoreSets(@ullable BackupManagerMonitor monitor)232 private void loadAvailableRestoreSets(@Nullable BackupManagerMonitor monitor) 233 throws InterruptedException { 234 mRestoreSetsLatch = new CountDownLatch(1); 235 assertEquals( 236 BackupManager.SUCCESS, monitor == null 237 ? mRestoreSession.getAvailableRestoreSets(mRestoreObserver) 238 : mRestoreSession.getAvailableRestoreSets(mRestoreObserver, monitor)); 239 awaitResultAndAssertSuccess(mRestoreSetsLatch); 240 241 assertNotEquals("Restore set not found", 0L, mRestoreToken); 242 } 243 doesRestoreSetContainAllPackages(long restoreToken, Set<String> packages)244 private boolean doesRestoreSetContainAllPackages(long restoreToken, Set<String> packages) { 245 for (String restorePackage : packages) { 246 if (mBackupManager.getAvailableRestoreToken(restorePackage) != restoreToken) { 247 return false; 248 } 249 } 250 return true; 251 } 252 awaitResultAndAssertSuccess(CountDownLatch latch)253 private void awaitResultAndAssertSuccess(CountDownLatch latch) throws InterruptedException { 254 boolean waitResult = latch.await(RESTORE_TIMEOUT_SECONDS, TimeUnit.SECONDS); 255 assertTrue("Restore timed out", waitResult); 256 } 257 initPackagesToRestore(int packagesCount)258 private void initPackagesToRestore(int packagesCount) { 259 mRestorePackages = new HashSet<>(); 260 mNonRestorePackages = new HashSet<>(); 261 262 for (int i = 0; i < PACKAGES_COUNT; i++) { 263 if (i < packagesCount) { 264 mRestorePackages.add(PACKAGES[i]); 265 } else { 266 mNonRestorePackages.add(PACKAGES[i]); 267 } 268 } 269 270 // Wait for the callbacks from RestoreObserver: one for each package from 271 // mRestorePackages plus restoreStarting and restoreFinished. 272 mRestoreObserverLatch = new CountDownLatch(mRestorePackages.size() + 2); 273 } 274 275 private static class TestBackupMonitor extends BackupManagerMonitor { 276 private final CountDownLatch mLatch; 277 TestBackupMonitor(CountDownLatch latch)278 TestBackupMonitor(CountDownLatch latch) { 279 mLatch = latch; 280 } 281 282 @Override onEvent(Bundle event)283 public void onEvent(Bundle event) { 284 // Note: this logic will break if the test cases using TestBackupMonitor 285 // start restoring more than 1 package because the logic currently expects 286 // exactly 1 onEvent() call per package 287 super.onEvent(event); 288 mLatch.countDown(); 289 } 290 } 291 292 @FunctionalInterface 293 private interface RestoreRunner { runRestore(BackupManagerMonitor monitor)294 void runRestore(BackupManagerMonitor monitor) throws InterruptedException; 295 } 296 } 297