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 com.android.server.backup;
     18 
     19 import static com.android.server.backup.testing.BackupManagerServiceTestUtils.startBackupThread;
     20 import static com.android.server.backup.testing.TransportData.backupTransport;
     21 import static com.android.server.backup.testing.TransportData.d2dTransport;
     22 import static com.android.server.backup.testing.TransportData.localTransport;
     23 import static com.android.server.backup.testing.TransportTestUtils.setUpCurrentTransport;
     24 import static com.android.server.backup.testing.TransportTestUtils.setUpTransports;
     25 import static com.google.common.truth.Truth.assertThat;
     26 import static org.mockito.ArgumentMatchers.any;
     27 import static org.mockito.ArgumentMatchers.anyInt;
     28 import static org.mockito.ArgumentMatchers.eq;
     29 import static org.mockito.Mockito.mock;
     30 import static org.mockito.Mockito.never;
     31 import static org.mockito.Mockito.verify;
     32 import static org.mockito.Mockito.when;
     33 import static org.robolectric.Shadows.shadowOf;
     34 import static org.testng.Assert.expectThrows;
     35 
     36 import android.app.backup.BackupManager;
     37 import android.app.backup.ISelectBackupTransportCallback;
     38 import android.content.ComponentName;
     39 import android.content.Context;
     40 import android.content.ContextWrapper;
     41 import android.content.Intent;
     42 import android.os.HandlerThread;
     43 import android.platform.test.annotations.Presubmit;
     44 import android.provider.Settings;
     45 
     46 import com.android.server.testing.shadows.ShadowAppBackupUtils;
     47 import com.android.server.testing.shadows.ShadowBackupPolicyEnforcer;
     48 import com.android.server.backup.testing.TransportData;
     49 import com.android.server.backup.testing.TransportTestUtils.TransportMock;
     50 import com.android.server.backup.transport.TransportNotRegisteredException;
     51 import com.android.server.testing.FrameworkRobolectricTestRunner;
     52 import com.android.server.testing.SystemLoaderPackages;
     53 
     54 import java.io.File;
     55 import java.util.HashMap;
     56 import java.util.List;
     57 import java.util.Map;
     58 import org.junit.After;
     59 import org.junit.Before;
     60 import org.junit.Test;
     61 import org.junit.runner.RunWith;
     62 import org.mockito.Mock;
     63 import org.mockito.MockitoAnnotations;
     64 import org.robolectric.RuntimeEnvironment;
     65 import org.robolectric.annotation.Config;
     66 import org.robolectric.shadows.ShadowContextWrapper;
     67 import org.robolectric.shadows.ShadowLog;
     68 import org.robolectric.shadows.ShadowLooper;
     69 import org.robolectric.shadows.ShadowPackageManager;
     70 import org.robolectric.shadows.ShadowSettings;
     71 import org.robolectric.shadows.ShadowSystemClock;
     72 
     73 @RunWith(FrameworkRobolectricTestRunner.class)
     74 @Config(
     75     manifest = Config.NONE,
     76     sdk = 26,
     77     shadows = {ShadowAppBackupUtils.class, ShadowBackupPolicyEnforcer.class}
     78 )
     79 @SystemLoaderPackages({"com.android.server.backup"})
     80 @Presubmit
     81 public class BackupManagerServiceTest {
     82     private static final String TAG = "BMSTest";
     83 
     84     @Mock private TransportManager mTransportManager;
     85     private HandlerThread mBackupThread;
     86     private ShadowLooper mShadowBackupLooper;
     87     private File mBaseStateDir;
     88     private File mDataDir;
     89     private ShadowContextWrapper mShadowContext;
     90     private Context mContext;
     91     private TransportData mTransport;
     92     private String mTransportName;
     93 
     94     @Before
     95     public void setUp() throws Exception {
     96         MockitoAnnotations.initMocks(this);
     97 
     98         mTransport = backupTransport();
     99         mTransportName = mTransport.transportName;
    100 
    101         mBackupThread = startBackupThread(this::uncaughtException);
    102         mShadowBackupLooper = shadowOf(mBackupThread.getLooper());
    103 
    104         ContextWrapper context = RuntimeEnvironment.application;
    105         mContext = context;
    106         mShadowContext = shadowOf(context);
    107 
    108         File cacheDir = mContext.getCacheDir();
    109         mBaseStateDir = new File(cacheDir, "base_state_dir");
    110         mDataDir = new File(cacheDir, "data_dir");
    111 
    112         ShadowBackupPolicyEnforcer.setMandatoryBackupTransport(null);
    113     }
    114 
    115     @After
    116     public void tearDown() throws Exception {
    117         mBackupThread.quit();
    118         ShadowAppBackupUtils.reset();
    119         ShadowBackupPolicyEnforcer.setMandatoryBackupTransport(null);
    120     }
    121 
    122     private void uncaughtException(Thread thread, Throwable e) {
    123         // Unrelated exceptions are thrown in the backup thread. Until we mock everything properly
    124         // we should not fail tests because of this. This is not flakiness, the exceptions thrown
    125         // don't interfere with the tests.
    126         ShadowLog.e(TAG, "Uncaught exception in test thread " + thread.getName(), e);
    127     }
    128 
    129     /* Tests for destination string */
    130 
    131     @Test
    132     public void testDestinationString() throws Exception {
    133         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
    134         when(mTransportManager.getTransportCurrentDestinationString(eq(mTransportName)))
    135                 .thenReturn("destinationString");
    136         BackupManagerService backupManagerService = createInitializedBackupManagerService();
    137 
    138         String destination = backupManagerService.getDestinationString(mTransportName);
    139 
    140         assertThat(destination).isEqualTo("destinationString");
    141     }
    142 
    143     @Test
    144     public void testDestinationString_whenTransportNotRegistered() throws Exception {
    145         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
    146         when(mTransportManager.getTransportCurrentDestinationString(eq(mTransportName)))
    147                 .thenThrow(TransportNotRegisteredException.class);
    148         BackupManagerService backupManagerService = createInitializedBackupManagerService();
    149 
    150         String destination = backupManagerService.getDestinationString(mTransportName);
    151 
    152         assertThat(destination).isNull();
    153     }
    154 
    155     @Test
    156     public void testDestinationString_withoutPermission() throws Exception {
    157         mShadowContext.denyPermissions(android.Manifest.permission.BACKUP);
    158         when(mTransportManager.getTransportCurrentDestinationString(eq(mTransportName)))
    159                 .thenThrow(TransportNotRegisteredException.class);
    160         BackupManagerService backupManagerService = createInitializedBackupManagerService();
    161 
    162         expectThrows(
    163                 SecurityException.class,
    164                 () -> backupManagerService.getDestinationString(mTransportName));
    165     }
    166 
    167     /* Tests for app eligibility */
    168 
    169     @Test
    170     public void testIsAppEligibleForBackup_whenAppEligible() throws Exception {
    171         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
    172         TransportMock transportMock = setUpCurrentTransport(mTransportManager, backupTransport());
    173         ShadowAppBackupUtils.sAppIsRunningAndEligibleForBackupWithTransport = p -> true;
    174         BackupManagerService backupManagerService = createInitializedBackupManagerService();
    175 
    176         boolean result = backupManagerService.isAppEligibleForBackup("app.package");
    177 
    178         assertThat(result).isTrue();
    179 
    180         verify(mTransportManager)
    181                 .disposeOfTransportClient(eq(transportMock.transportClient), any());
    182     }
    183 
    184     @Test
    185     public void testIsAppEligibleForBackup_whenAppNotEligible() throws Exception {
    186         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
    187         setUpCurrentTransport(mTransportManager, mTransport);
    188         ShadowAppBackupUtils.sAppIsRunningAndEligibleForBackupWithTransport = p -> false;
    189         BackupManagerService backupManagerService = createInitializedBackupManagerService();
    190 
    191         boolean result = backupManagerService.isAppEligibleForBackup("app.package");
    192 
    193         assertThat(result).isFalse();
    194     }
    195 
    196     @Test
    197     public void testIsAppEligibleForBackup_withoutPermission() throws Exception {
    198         mShadowContext.denyPermissions(android.Manifest.permission.BACKUP);
    199         setUpCurrentTransport(mTransportManager, mTransport);
    200         BackupManagerService backupManagerService = createInitializedBackupManagerService();
    201 
    202         expectThrows(
    203                 SecurityException.class,
    204                 () -> backupManagerService.isAppEligibleForBackup("app.package"));
    205     }
    206 
    207     @Test
    208     public void testFilterAppsEligibleForBackup() throws Exception {
    209         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
    210         TransportMock transportMock = setUpCurrentTransport(mTransportManager, mTransport);
    211         Map<String, Boolean> packagesMap = new HashMap<>();
    212         packagesMap.put("package.a", true);
    213         packagesMap.put("package.b", false);
    214         ShadowAppBackupUtils.sAppIsRunningAndEligibleForBackupWithTransport = packagesMap::get;
    215         BackupManagerService backupManagerService = createInitializedBackupManagerService();
    216         String[] packages = packagesMap.keySet().toArray(new String[packagesMap.size()]);
    217 
    218         String[] filtered = backupManagerService.filterAppsEligibleForBackup(packages);
    219 
    220         assertThat(filtered).asList().containsExactly("package.a");
    221         verify(mTransportManager)
    222                 .disposeOfTransportClient(eq(transportMock.transportClient), any());
    223     }
    224 
    225     @Test
    226     public void testFilterAppsEligibleForBackup_whenNoneIsEligible() throws Exception {
    227         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
    228         ShadowAppBackupUtils.sAppIsRunningAndEligibleForBackupWithTransport = p -> false;
    229         BackupManagerService backupManagerService = createInitializedBackupManagerService();
    230 
    231         String[] filtered =
    232                 backupManagerService.filterAppsEligibleForBackup(
    233                         new String[] {"package.a", "package.b"});
    234 
    235         assertThat(filtered).isEmpty();
    236     }
    237 
    238     @Test
    239     public void testFilterAppsEligibleForBackup_withoutPermission() throws Exception {
    240         mShadowContext.denyPermissions(android.Manifest.permission.BACKUP);
    241         setUpCurrentTransport(mTransportManager, mTransport);
    242         BackupManagerService backupManagerService = createInitializedBackupManagerService();
    243 
    244         expectThrows(
    245                 SecurityException.class,
    246                 () ->
    247                         backupManagerService.filterAppsEligibleForBackup(
    248                                 new String[] {"package.a", "package.b"}));
    249     }
    250 
    251     /* Tests for select transport */
    252 
    253     private ComponentName mNewTransportComponent;
    254     private TransportData mNewTransport;
    255     private TransportMock mNewTransportMock;
    256     private ComponentName mOldTransportComponent;
    257     private TransportData mOldTransport;
    258     private TransportMock mOldTransportMock;
    259 
    260     private void setUpForSelectTransport() throws Exception {
    261         mNewTransport = backupTransport();
    262         mNewTransportComponent = mNewTransport.getTransportComponent();
    263         mOldTransport = d2dTransport();
    264         mOldTransportComponent = mOldTransport.getTransportComponent();
    265         List<TransportMock> transportMocks =
    266                 setUpTransports(mTransportManager, mNewTransport, mOldTransport, localTransport());
    267         mNewTransportMock = transportMocks.get(0);
    268         mOldTransportMock = transportMocks.get(1);
    269         when(mTransportManager.selectTransport(eq(mNewTransport.transportName)))
    270                 .thenReturn(mOldTransport.transportName);
    271     }
    272 
    273     @Test
    274     public void testSelectBackupTransport() throws Exception {
    275         setUpForSelectTransport();
    276         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
    277         BackupManagerService backupManagerService = createInitializedBackupManagerService();
    278 
    279         String oldTransport =
    280                 backupManagerService.selectBackupTransport(mNewTransport.transportName);
    281 
    282         assertThat(getSettingsTransport()).isEqualTo(mNewTransport.transportName);
    283         assertThat(oldTransport).isEqualTo(mOldTransport.transportName);
    284         verify(mTransportManager)
    285                 .disposeOfTransportClient(eq(mNewTransportMock.transportClient), any());
    286     }
    287 
    288     @Test
    289     public void testSelectBackupTransport_withoutPermission() throws Exception {
    290         setUpForSelectTransport();
    291         mShadowContext.denyPermissions(android.Manifest.permission.BACKUP);
    292         BackupManagerService backupManagerService = createInitializedBackupManagerService();
    293 
    294         expectThrows(
    295                 SecurityException.class,
    296                 () -> backupManagerService.selectBackupTransport(mNewTransport.transportName));
    297     }
    298 
    299     @Test
    300     public void testSelectBackupTransportAsync() throws Exception {
    301         setUpForSelectTransport();
    302         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
    303         when(mTransportManager.registerAndSelectTransport(eq(mNewTransportComponent)))
    304                 .thenReturn(BackupManager.SUCCESS);
    305         BackupManagerService backupManagerService = createInitializedBackupManagerService();
    306         ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class);
    307 
    308         backupManagerService.selectBackupTransportAsync(mNewTransportComponent, callback);
    309 
    310         mShadowBackupLooper.runToEndOfTasks();
    311         assertThat(getSettingsTransport()).isEqualTo(mNewTransport.transportName);
    312         verify(callback).onSuccess(eq(mNewTransport.transportName));
    313         verify(mTransportManager)
    314                 .disposeOfTransportClient(eq(mNewTransportMock.transportClient), any());
    315     }
    316 
    317     @Test
    318     public void testSelectBackupTransportAsync_whenMandatoryTransport() throws Exception {
    319         setUpForSelectTransport();
    320         ShadowBackupPolicyEnforcer.setMandatoryBackupTransport(mNewTransportComponent);
    321         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
    322         when(mTransportManager.registerAndSelectTransport(eq(mNewTransportComponent)))
    323                 .thenReturn(BackupManager.SUCCESS);
    324         ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class);
    325         BackupManagerService backupManagerService = createInitializedBackupManagerService();
    326 
    327         backupManagerService.selectBackupTransportAsync(mNewTransportComponent, callback);
    328 
    329         mShadowBackupLooper.runToEndOfTasks();
    330         assertThat(getSettingsTransport()).isEqualTo(mNewTransport.transportName);
    331         verify(callback).onSuccess(eq(mNewTransport.transportName));
    332         verify(mTransportManager)
    333                 .disposeOfTransportClient(eq(mNewTransportMock.transportClient), any());
    334     }
    335 
    336     @Test
    337     public void testSelectBackupTransportAsync_whenOtherThanMandatoryTransport() throws Exception {
    338         setUpForSelectTransport();
    339         ShadowBackupPolicyEnforcer.setMandatoryBackupTransport(mOldTransportComponent);
    340         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
    341         when(mTransportManager.registerAndSelectTransport(eq(mNewTransportComponent)))
    342                 .thenReturn(BackupManager.SUCCESS);
    343         ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class);
    344         BackupManagerService backupManagerService = createInitializedBackupManagerService();
    345 
    346         backupManagerService.selectBackupTransportAsync(mNewTransportComponent, callback);
    347 
    348         mShadowBackupLooper.runToEndOfTasks();
    349         assertThat(getSettingsTransport()).isNotEqualTo(mNewTransport.transportName);
    350         verify(callback).onFailure(eq(BackupManager.ERROR_BACKUP_NOT_ALLOWED));
    351     }
    352 
    353     @Test
    354     public void testSelectBackupTransportAsync_whenRegistrationFails() throws Exception {
    355         setUpForSelectTransport();
    356         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
    357         when(mTransportManager.registerAndSelectTransport(eq(mNewTransportComponent)))
    358                 .thenReturn(BackupManager.ERROR_TRANSPORT_UNAVAILABLE);
    359         BackupManagerService backupManagerService = createInitializedBackupManagerService();
    360         ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class);
    361 
    362         backupManagerService.selectBackupTransportAsync(mNewTransportComponent, callback);
    363 
    364         mShadowBackupLooper.runToEndOfTasks();
    365         assertThat(getSettingsTransport()).isNotEqualTo(mNewTransport.transportName);
    366         verify(callback).onFailure(anyInt());
    367     }
    368 
    369     @Test
    370     public void testSelectBackupTransportAsync_whenTransportGetsUnregistered() throws Exception {
    371         setUpTransports(mTransportManager, mTransport.unregistered());
    372         ComponentName newTransportComponent = mTransport.getTransportComponent();
    373         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
    374         when(mTransportManager.registerAndSelectTransport(eq(newTransportComponent)))
    375                 .thenReturn(BackupManager.SUCCESS);
    376         BackupManagerService backupManagerService = createInitializedBackupManagerService();
    377         ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class);
    378 
    379         backupManagerService.selectBackupTransportAsync(newTransportComponent, callback);
    380 
    381         mShadowBackupLooper.runToEndOfTasks();
    382         assertThat(getSettingsTransport()).isNotEqualTo(mTransportName);
    383         verify(callback).onFailure(anyInt());
    384     }
    385 
    386     @Test
    387     public void testSelectBackupTransportAsync_withoutPermission() throws Exception {
    388         setUpForSelectTransport();
    389         mShadowContext.denyPermissions(android.Manifest.permission.BACKUP);
    390         BackupManagerService backupManagerService = createInitializedBackupManagerService();
    391         ComponentName newTransportComponent = mNewTransport.getTransportComponent();
    392 
    393         expectThrows(
    394                 SecurityException.class,
    395                 () ->
    396                         backupManagerService.selectBackupTransportAsync(
    397                                 newTransportComponent, mock(ISelectBackupTransportCallback.class)));
    398     }
    399 
    400     private String getSettingsTransport() {
    401         return ShadowSettings.ShadowSecure.getString(
    402                 mContext.getContentResolver(), Settings.Secure.BACKUP_TRANSPORT);
    403     }
    404 
    405     /* Tests for updating transport attributes */
    406 
    407     private static final int PACKAGE_UID = 10;
    408     private ComponentName mTransportComponent;
    409     private int mTransportUid;
    410 
    411     private void setUpForUpdateTransportAttributes() throws Exception {
    412         mTransportComponent = mTransport.getTransportComponent();
    413         String transportPackage = mTransportComponent.getPackageName();
    414 
    415         ShadowPackageManager shadowPackageManager = shadowOf(mContext.getPackageManager());
    416         shadowPackageManager.addPackage(transportPackage);
    417         shadowPackageManager.setPackagesForUid(PACKAGE_UID, transportPackage);
    418 
    419         mTransportUid = mContext.getPackageManager().getPackageUid(transportPackage, 0);
    420     }
    421 
    422     @Test
    423     public void
    424             testUpdateTransportAttributes_whenTransportUidEqualsToCallingUid_callsThroughToTransportManager()
    425                     throws Exception {
    426         setUpForUpdateTransportAttributes();
    427         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
    428         Intent configurationIntent = new Intent();
    429         Intent dataManagementIntent = new Intent();
    430         BackupManagerService backupManagerService = createInitializedBackupManagerService();
    431 
    432         backupManagerService.updateTransportAttributes(
    433                 mTransportUid,
    434                 mTransportComponent,
    435                 mTransportName,
    436                 configurationIntent,
    437                 "currentDestinationString",
    438                 dataManagementIntent,
    439                 "dataManagementLabel");
    440 
    441         verify(mTransportManager)
    442                 .updateTransportAttributes(
    443                         eq(mTransportComponent),
    444                         eq(mTransportName),
    445                         eq(configurationIntent),
    446                         eq("currentDestinationString"),
    447                         eq(dataManagementIntent),
    448                         eq("dataManagementLabel"));
    449     }
    450 
    451     @Test
    452     public void testUpdateTransportAttributes_whenTransportUidNotEqualToCallingUid_throwsException()
    453             throws Exception {
    454         setUpForUpdateTransportAttributes();
    455         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
    456         BackupManagerService backupManagerService = createInitializedBackupManagerService();
    457 
    458         expectThrows(
    459                 SecurityException.class,
    460                 () ->
    461                         backupManagerService.updateTransportAttributes(
    462                                 mTransportUid + 1,
    463                                 mTransportComponent,
    464                                 mTransportName,
    465                                 new Intent(),
    466                                 "currentDestinationString",
    467                                 new Intent(),
    468                                 "dataManagementLabel"));
    469     }
    470 
    471     @Test
    472     public void testUpdateTransportAttributes_whenTransportComponentNull_throwsException()
    473             throws Exception {
    474         setUpForUpdateTransportAttributes();
    475         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
    476         BackupManagerService backupManagerService = createInitializedBackupManagerService();
    477 
    478         expectThrows(
    479                 RuntimeException.class,
    480                 () ->
    481                         backupManagerService.updateTransportAttributes(
    482                                 mTransportUid,
    483                                 null,
    484                                 mTransportName,
    485                                 new Intent(),
    486                                 "currentDestinationString",
    487                                 new Intent(),
    488                                 "dataManagementLabel"));
    489     }
    490 
    491     @Test
    492     public void testUpdateTransportAttributes_whenNameNull_throwsException() throws Exception {
    493         setUpForUpdateTransportAttributes();
    494         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
    495         BackupManagerService backupManagerService = createInitializedBackupManagerService();
    496 
    497         expectThrows(
    498                 RuntimeException.class,
    499                 () ->
    500                         backupManagerService.updateTransportAttributes(
    501                                 mTransportUid,
    502                                 mTransportComponent,
    503                                 null,
    504                                 new Intent(),
    505                                 "currentDestinationString",
    506                                 new Intent(),
    507                                 "dataManagementLabel"));
    508     }
    509 
    510     @Test
    511     public void testUpdateTransportAttributes_whenCurrentDestinationStringNull_throwsException()
    512             throws Exception {
    513         setUpForUpdateTransportAttributes();
    514         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
    515         BackupManagerService backupManagerService = createInitializedBackupManagerService();
    516 
    517         expectThrows(
    518                 RuntimeException.class,
    519                 () ->
    520                         backupManagerService.updateTransportAttributes(
    521                                 mTransportUid,
    522                                 mTransportComponent,
    523                                 mTransportName,
    524                                 new Intent(),
    525                                 null,
    526                                 new Intent(),
    527                                 "dataManagementLabel"));
    528     }
    529 
    530     @Test
    531     public void
    532             testUpdateTransportAttributes_whenDataManagementArgumentsNullityDontMatch_throwsException()
    533                     throws Exception {
    534         setUpForUpdateTransportAttributes();
    535         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
    536         BackupManagerService backupManagerService = createInitializedBackupManagerService();
    537 
    538         expectThrows(
    539                 RuntimeException.class,
    540                 () ->
    541                         backupManagerService.updateTransportAttributes(
    542                                 mTransportUid,
    543                                 mTransportComponent,
    544                                 mTransportName,
    545                                 new Intent(),
    546                                 "currentDestinationString",
    547                                 null,
    548                                 "dataManagementLabel"));
    549 
    550         expectThrows(
    551                 RuntimeException.class,
    552                 () ->
    553                         backupManagerService.updateTransportAttributes(
    554                                 mTransportUid,
    555                                 mTransportComponent,
    556                                 mTransportName,
    557                                 new Intent(),
    558                                 "currentDestinationString",
    559                                 new Intent(),
    560                                 null));
    561     }
    562 
    563     @Test
    564     public void testUpdateTransportAttributes_whenPermissionGranted_callsThroughToTransportManager()
    565             throws Exception {
    566         setUpForUpdateTransportAttributes();
    567         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
    568         Intent configurationIntent = new Intent();
    569         Intent dataManagementIntent = new Intent();
    570         BackupManagerService backupManagerService = createInitializedBackupManagerService();
    571 
    572         backupManagerService.updateTransportAttributes(
    573                 mTransportUid,
    574                 mTransportComponent,
    575                 mTransportName,
    576                 configurationIntent,
    577                 "currentDestinationString",
    578                 dataManagementIntent,
    579                 "dataManagementLabel");
    580 
    581         verify(mTransportManager)
    582                 .updateTransportAttributes(
    583                         eq(mTransportComponent),
    584                         eq(mTransportName),
    585                         eq(configurationIntent),
    586                         eq("currentDestinationString"),
    587                         eq(dataManagementIntent),
    588                         eq("dataManagementLabel"));
    589     }
    590 
    591     @Test
    592     public void testUpdateTransportAttributes_whenPermissionDenied_throwsSecurityException()
    593             throws Exception {
    594         setUpForUpdateTransportAttributes();
    595         mShadowContext.denyPermissions(android.Manifest.permission.BACKUP);
    596         BackupManagerService backupManagerService = createInitializedBackupManagerService();
    597 
    598         expectThrows(
    599                 SecurityException.class,
    600                 () ->
    601                         backupManagerService.updateTransportAttributes(
    602                                 mTransportUid,
    603                                 mTransportComponent,
    604                                 mTransportName,
    605                                 new Intent(),
    606                                 "currentDestinationString",
    607                                 new Intent(),
    608                                 "dataManagementLabel"));
    609     }
    610 
    611     /* Miscellaneous tests */
    612 
    613     @Test
    614     public void testConstructor_postRegisterTransports() {
    615         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
    616 
    617         createBackupManagerService();
    618 
    619         mShadowBackupLooper.runToEndOfTasks();
    620         verify(mTransportManager).registerTransports();
    621     }
    622 
    623     @Test
    624     public void testConstructor_doesNotRegisterTransportsSynchronously() {
    625         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
    626 
    627         createBackupManagerService();
    628 
    629         // Operations posted to mBackupThread only run with mShadowBackupLooper.runToEndOfTasks()
    630         verify(mTransportManager, never()).registerTransports();
    631     }
    632 
    633     private BackupManagerService createBackupManagerService() {
    634         return new BackupManagerService(
    635                 mContext,
    636                 new Trampoline(mContext),
    637                 mBackupThread,
    638                 mBaseStateDir,
    639                 mDataDir,
    640                 mTransportManager);
    641     }
    642 
    643     private BackupManagerService createInitializedBackupManagerService() {
    644         BackupManagerService backupManagerService =
    645                 new BackupManagerService(
    646                         mContext,
    647                         new Trampoline(mContext),
    648                         mBackupThread,
    649                         mBaseStateDir,
    650                         mDataDir,
    651                         mTransportManager);
    652         mShadowBackupLooper.runToEndOfTasks();
    653         // Handler instances have their own clock, so advancing looper (with runToEndOfTasks())
    654         // above does NOT advance the handlers' clock, hence whenever a handler post messages with
    655         // specific time to the looper the time of those messages will be before the looper's time.
    656         // To fix this we advance SystemClock as well since that is from where the handlers read
    657         // time.
    658         ShadowSystemClock.setCurrentTimeMillis(mShadowBackupLooper.getScheduler().getCurrentTime());
    659         return backupManagerService;
    660     }
    661 }
    662