diff options
| author | 2017-09-01 12:06:16 +0000 | |
|---|---|---|
| committer | 2017-09-01 12:06:16 +0000 | |
| commit | a1f7fb9b5b7f090c0e070a878ae9b7c62733bced (patch) | |
| tree | 3e57ac0ebae31ffbcbf8e4f35e3a67a997623e0a | |
| parent | 4456a99918f00d6da50ffb98bfe6baf9e63c2bae (diff) | |
| parent | bd476eae4ba26389dc83402d0b0ae07d6d4e73c5 (diff) | |
Merge "Update TransportManager tests."
8 files changed, 481 insertions, 49 deletions
diff --git a/services/backup/java/com/android/server/backup/TransportManager.java b/services/backup/java/com/android/server/backup/TransportManager.java index 321ef2652514..098bc0778ac1 100644 --- a/services/backup/java/com/android/server/backup/TransportManager.java +++ b/services/backup/java/com/android/server/backup/TransportManager.java @@ -455,7 +455,7 @@ public class TransportManager { } } - interface TransportBoundListener { + public interface TransportBoundListener { /** Should return true if this is a valid transport. */ boolean onTransportBound(IBackupTransport binder); } diff --git a/services/robotests/Android.mk b/services/robotests/Android.mk index 3e82d3ee1d2f..717176247d36 100644 --- a/services/robotests/Android.mk +++ b/services/robotests/Android.mk @@ -73,4 +73,6 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ LOCAL_TEST_PACKAGE := FrameworksServicesLib +LOCAL_INSTRUMENT_SOURCE_DIRS := $(dir $(LOCAL_PATH))backup/java + include prebuilts/misc/common/robolectric/run_robotests.mk diff --git a/services/robotests/src/com/android/server/backup/TransportManagerTest.java b/services/robotests/src/com/android/server/backup/TransportManagerTest.java index 0f7a091a8315..510fdba5fdf2 100644 --- a/services/robotests/src/com/android/server/backup/TransportManagerTest.java +++ b/services/robotests/src/com/android/server/backup/TransportManagerTest.java @@ -18,32 +18,36 @@ package com.android.server.backup; import static com.google.common.truth.Truth.assertThat; -import android.annotation.RequiresPermission; import android.content.ComponentName; import android.content.Intent; -import android.content.ServiceConnection; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; -import android.os.UserHandle; +import android.os.IBinder; +import android.platform.test.annotations.Presubmit; + +import com.android.server.backup.testing.BackupTransportStub; +import com.android.server.backup.testing.DefaultPackageManagerWithQueryIntentServicesAsUser; +import com.android.server.backup.testing.ShadowBackupTransportStub; +import com.android.server.backup.testing.ShadowContextImplWithBindServiceAsUser; +import com.android.server.backup.testing.TransportBoundListenerStub; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; -import org.robolectric.res.ResourceLoader; -import org.robolectric.res.builder.DefaultPackageManager; import org.robolectric.res.builder.RobolectricPackageManager; -import org.robolectric.shadows.ShadowContextImpl; +import org.robolectric.shadows.ShadowLog; import org.robolectric.shadows.ShadowLooper; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -51,12 +55,18 @@ import java.util.List; @Config( manifest = Config.NONE, sdk = 23, - shadows = {TransportManagerTest.ShadowContextImplWithBindServiceAsUser.class} + shadows = { + ShadowContextImplWithBindServiceAsUser.class, + ShadowBackupTransportStub.class + } ) +@Presubmit public class TransportManagerTest { private static final String PACKAGE_NAME = "some.package.name"; private static final String TRANSPORT1_NAME = "transport1.name"; private static final String TRANSPORT2_NAME = "transport2.name"; + private static final List<String> TRANSPORTS_NAMES = Arrays.asList( + TRANSPORT1_NAME, TRANSPORT2_NAME); private static final ComponentName TRANSPORT1_COMPONENT_NAME = new ComponentName(PACKAGE_NAME, TRANSPORT1_NAME); private static final ComponentName TRANSPORT2_COMPONENT_NAME = new ComponentName(PACKAGE_NAME, @@ -66,72 +76,131 @@ public class TransportManagerTest { private RobolectricPackageManager mPackageManager; - @Mock private TransportManager.TransportBoundListener mTransportBoundListener; + @Mock private IBinder mTransport1BinderMock; + @Mock private IBinder mTransport2BinderMock; + + private final BackupTransportStub mTransport1Stub = new BackupTransportStub(TRANSPORT1_NAME); + private final BackupTransportStub mTransport2Stub = new BackupTransportStub(TRANSPORT2_NAME); + private final TransportBoundListenerStub mTransportBoundListenerStub = + new TransportBoundListenerStub(true); @Before - public void setUp() { + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + ShadowLog.stream = System.out; mPackageManager = new DefaultPackageManagerWithQueryIntentServicesAsUser( RuntimeEnvironment.getAppResourceLoader()); RuntimeEnvironment.setRobolectricPackageManager(mPackageManager); + + ShadowContextImplWithBindServiceAsUser.sComponentBinderMap.put(TRANSPORT1_COMPONENT_NAME, + mTransport1BinderMock); + ShadowContextImplWithBindServiceAsUser.sComponentBinderMap.put(TRANSPORT2_COMPONENT_NAME, + mTransport2BinderMock); + ShadowBackupTransportStub.sBinderTransportMap.put(mTransport1BinderMock, mTransport1Stub); + ShadowBackupTransportStub.sBinderTransportMap.put(mTransport2BinderMock, mTransport2Stub); } @Test - public void onPackageAdded_bindsToAllTransports() { - Intent intent = new Intent(TransportManager.SERVICE_ACTION_TRANSPORT_HOST); - intent.setPackage(PACKAGE_NAME); + public void onPackageAdded_bindsToAllTransports() throws Exception { + setUpPackageWithTransports(PACKAGE_NAME, TRANSPORTS_NAMES, + ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); - PackageInfo packageInfo = new PackageInfo(); - packageInfo.packageName = PACKAGE_NAME; - packageInfo.applicationInfo = new ApplicationInfo(); - packageInfo.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED; + TransportManager transportManager = new TransportManager( + RuntimeEnvironment.application.getApplicationContext(), + new HashSet<>(TRANSPORTS_COMPONENT_NAMES), + null /* defaultTransport */, + mTransportBoundListenerStub, + ShadowLooper.getMainLooper()); + transportManager.onPackageAdded(PACKAGE_NAME); - mPackageManager.addPackage(packageInfo); + assertThat(transportManager.getAllTransportComponents()).asList().containsExactlyElementsIn( + TRANSPORTS_COMPONENT_NAMES); + assertThat(transportManager.getBoundTransportNames()).asList().containsExactlyElementsIn( + TRANSPORTS_NAMES); + assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport1Stub)).isTrue(); + assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport2Stub)).isTrue(); + } - ResolveInfo transport1 = new ResolveInfo(); - transport1.serviceInfo = new ServiceInfo(); - transport1.serviceInfo.packageName = PACKAGE_NAME; - transport1.serviceInfo.name = TRANSPORT1_NAME; + @Test + public void onPackageAdded_whitelistIsNull_doesNotBindToTransports() throws Exception { + setUpPackageWithTransports(PACKAGE_NAME, TRANSPORTS_NAMES, + ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); - ResolveInfo transport2 = new ResolveInfo(); - transport2.serviceInfo = new ServiceInfo(); - transport2.serviceInfo.packageName = PACKAGE_NAME; - transport2.serviceInfo.name = TRANSPORT2_NAME; + TransportManager transportManager = new TransportManager( + RuntimeEnvironment.application.getApplicationContext(), + null /* whitelist */, + null /* defaultTransport */, + mTransportBoundListenerStub, + ShadowLooper.getMainLooper()); + transportManager.onPackageAdded(PACKAGE_NAME); - mPackageManager.addResolveInfoForIntent(intent, Arrays.asList(transport1, transport2)); + assertThat(transportManager.getAllTransportComponents()).isEmpty(); + assertThat(transportManager.getBoundTransportNames()).isEmpty(); + assertThat(mTransportBoundListenerStub.isCalled()).isFalse(); + } + + @Test + public void onPackageAdded_onlyOneTransportWhitelisted_onlyConnectsToWhitelistedTransport() + throws Exception { + setUpPackageWithTransports(PACKAGE_NAME, TRANSPORTS_NAMES, + ApplicationInfo.PRIVATE_FLAG_PRIVILEGED); TransportManager transportManager = new TransportManager( RuntimeEnvironment.application.getApplicationContext(), - new HashSet<>(TRANSPORTS_COMPONENT_NAMES), - null, - mTransportBoundListener, + new HashSet<>(Collections.singleton(TRANSPORT2_COMPONENT_NAME)), + null /* defaultTransport */, + mTransportBoundListenerStub, ShadowLooper.getMainLooper()); transportManager.onPackageAdded(PACKAGE_NAME); assertThat(transportManager.getAllTransportComponents()).asList().containsExactlyElementsIn( - TRANSPORTS_COMPONENT_NAMES); + Collections.singleton(TRANSPORT2_COMPONENT_NAME)); + assertThat(transportManager.getBoundTransportNames()).asList().containsExactlyElementsIn( + Collections.singleton(TRANSPORT2_NAME)); + assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport1Stub)).isFalse(); + assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport2Stub)).isTrue(); } - private static class DefaultPackageManagerWithQueryIntentServicesAsUser extends - DefaultPackageManager { + @Test + public void onPackageAdded_appIsNotPrivileged_doesNotBindToTransports() throws Exception { + setUpPackageWithTransports(PACKAGE_NAME, TRANSPORTS_NAMES, 0); - /* package */ DefaultPackageManagerWithQueryIntentServicesAsUser( - ResourceLoader appResourceLoader) { - super(appResourceLoader); - } + TransportManager transportManager = new TransportManager( + RuntimeEnvironment.application.getApplicationContext(), + new HashSet<>(TRANSPORTS_COMPONENT_NAMES), + null /* defaultTransport */, + mTransportBoundListenerStub, + ShadowLooper.getMainLooper()); + transportManager.onPackageAdded(PACKAGE_NAME); - @Override - public List<ResolveInfo> queryIntentServicesAsUser(Intent intent, int flags, int userId) { - return super.queryIntentServices(intent, flags); - } + assertThat(transportManager.getAllTransportComponents()).isEmpty(); + assertThat(transportManager.getBoundTransportNames()).isEmpty(); + assertThat(mTransportBoundListenerStub.isCalled()).isFalse(); } - @Implements(className = ShadowContextImpl.CLASS_NAME) - public static class ShadowContextImplWithBindServiceAsUser extends ShadowContextImpl { + private void setUpPackageWithTransports(String packageName, List<String> transportNames, + int flags) throws Exception { + PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = packageName; + packageInfo.applicationInfo = new ApplicationInfo(); + packageInfo.applicationInfo.privateFlags = flags; + + mPackageManager.addPackage(packageInfo); - @Implementation - public boolean bindServiceAsUser(@RequiresPermission Intent service, ServiceConnection conn, - int flags, UserHandle user) { - return true; + List<ResolveInfo> transportsInfo = new ArrayList<>(); + for (String transportName : transportNames) { + ResolveInfo info = new ResolveInfo(); + info.serviceInfo = new ServiceInfo(); + info.serviceInfo.packageName = packageName; + info.serviceInfo.name = transportName; + transportsInfo.add(info); } + + Intent intent = new Intent(TransportManager.SERVICE_ACTION_TRANSPORT_HOST); + intent.setPackage(packageName); + + mPackageManager.addResolveInfoForIntent(intent, transportsInfo); } + } diff --git a/services/robotests/src/com/android/server/backup/testing/BackupTransportStub.java b/services/robotests/src/com/android/server/backup/testing/BackupTransportStub.java new file mode 100644 index 000000000000..ec09f908c90d --- /dev/null +++ b/services/robotests/src/com/android/server/backup/testing/BackupTransportStub.java @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2017 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 com.android.server.backup.testing; + +import android.app.backup.RestoreDescription; +import android.app.backup.RestoreSet; +import android.content.Intent; +import android.content.pm.PackageInfo; +import android.os.IBinder; +import android.os.ParcelFileDescriptor; +import android.os.RemoteException; + +import com.android.internal.backup.IBackupTransport; + +/** + * Stub backup transport, doing nothing and returning default values. + */ +public class BackupTransportStub implements IBackupTransport { + + private final String mName; + + public BackupTransportStub(String name) { + mName = name; + } + + @Override + public IBinder asBinder() { + return null; + } + + @Override + public String name() throws RemoteException { + return mName; + } + + @Override + public Intent configurationIntent() throws RemoteException { + return null; + } + + @Override + public String currentDestinationString() throws RemoteException { + return null; + } + + @Override + public Intent dataManagementIntent() throws RemoteException { + return null; + } + + @Override + public String dataManagementLabel() throws RemoteException { + return null; + } + + @Override + public String transportDirName() throws RemoteException { + return null; + } + + @Override + public long requestBackupTime() throws RemoteException { + return 0; + } + + @Override + public int initializeDevice() throws RemoteException { + return 0; + } + + @Override + public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor inFd, int flags) + throws RemoteException { + return 0; + } + + @Override + public int clearBackupData(PackageInfo packageInfo) throws RemoteException { + return 0; + } + + @Override + public int finishBackup() throws RemoteException { + return 0; + } + + @Override + public RestoreSet[] getAvailableRestoreSets() throws RemoteException { + return new RestoreSet[0]; + } + + @Override + public long getCurrentRestoreSet() throws RemoteException { + return 0; + } + + @Override + public int startRestore(long token, PackageInfo[] packages) throws RemoteException { + return 0; + } + + @Override + public RestoreDescription nextRestorePackage() throws RemoteException { + return null; + } + + @Override + public int getRestoreData(ParcelFileDescriptor outFd) throws RemoteException { + return 0; + } + + @Override + public void finishRestore() throws RemoteException { + + } + + @Override + public long requestFullBackupTime() throws RemoteException { + return 0; + } + + @Override + public int performFullBackup(PackageInfo targetPackage, ParcelFileDescriptor socket, + int flags) + throws RemoteException { + return 0; + } + + @Override + public int checkFullBackupSize(long size) throws RemoteException { + return 0; + } + + @Override + public int sendBackupData(int numBytes) throws RemoteException { + return 0; + } + + @Override + public void cancelFullBackup() throws RemoteException { + + } + + @Override + public boolean isAppEligibleForBackup(PackageInfo targetPackage, boolean isFullBackup) + throws RemoteException { + return false; + } + + @Override + public long getBackupQuota(String packageName, boolean isFullBackup) + throws RemoteException { + return 0; + } + + @Override + public int getNextFullRestoreDataChunk(ParcelFileDescriptor socket) throws RemoteException { + return 0; + } + + @Override + public int abortFullRestore() throws RemoteException { + return 0; + } +} diff --git a/services/robotests/src/com/android/server/backup/testing/DefaultPackageManagerWithQueryIntentServicesAsUser.java b/services/robotests/src/com/android/server/backup/testing/DefaultPackageManagerWithQueryIntentServicesAsUser.java new file mode 100644 index 000000000000..5a0967ba2420 --- /dev/null +++ b/services/robotests/src/com/android/server/backup/testing/DefaultPackageManagerWithQueryIntentServicesAsUser.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2017 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 com.android.server.backup.testing; + +import android.content.Intent; +import android.content.pm.ResolveInfo; + +import org.robolectric.res.ResourceLoader; +import org.robolectric.res.builder.DefaultPackageManager; + +import java.util.List; + +/** + * Implementation of PackageManager for Robolectric which handles queryIntentServicesAsUser(). + */ +public class DefaultPackageManagerWithQueryIntentServicesAsUser extends + DefaultPackageManager { + + /* package */ + public DefaultPackageManagerWithQueryIntentServicesAsUser( + ResourceLoader appResourceLoader) { + super(appResourceLoader); + } + + @Override + public List<ResolveInfo> queryIntentServicesAsUser(Intent intent, int flags, int userId) { + return super.queryIntentServices(intent, flags); + } +} diff --git a/services/robotests/src/com/android/server/backup/testing/ShadowBackupTransportStub.java b/services/robotests/src/com/android/server/backup/testing/ShadowBackupTransportStub.java new file mode 100644 index 000000000000..48a12f0f5435 --- /dev/null +++ b/services/robotests/src/com/android/server/backup/testing/ShadowBackupTransportStub.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2017 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 com.android.server.backup.testing; + +import android.os.IBinder; + +import com.android.internal.backup.IBackupTransport; + +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; + +import java.util.HashMap; +import java.util.Map; + +/** + * Shadow IBackupTransport.Stub, returns a transport corresponding to the binder. + */ +@Implements(IBackupTransport.Stub.class) +public class ShadowBackupTransportStub { + public static Map<IBinder, IBackupTransport> sBinderTransportMap = new HashMap<>(); + + @Implementation + public static IBackupTransport asInterface(IBinder obj) { + return sBinderTransportMap.get(obj); + } +} diff --git a/services/robotests/src/com/android/server/backup/testing/ShadowContextImplWithBindServiceAsUser.java b/services/robotests/src/com/android/server/backup/testing/ShadowContextImplWithBindServiceAsUser.java new file mode 100644 index 000000000000..77424294b1e0 --- /dev/null +++ b/services/robotests/src/com/android/server/backup/testing/ShadowContextImplWithBindServiceAsUser.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2017 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 com.android.server.backup.testing; + +import android.annotation.RequiresPermission; +import android.content.ComponentName; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.IBinder; +import android.os.UserHandle; + +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; +import org.robolectric.shadows.ShadowApplication; +import org.robolectric.shadows.ShadowContextImpl; + +import java.util.HashMap; +import java.util.Map; + +/** + * Implementation of ContextImpl shadow, handling bindServiceAsUser(). + */ +@Implements(className = ShadowContextImpl.CLASS_NAME) +public class ShadowContextImplWithBindServiceAsUser extends ShadowContextImpl { + public static Map<ComponentName, IBinder> sComponentBinderMap = new HashMap<>(); + + @Implementation + public boolean bindServiceAsUser(@RequiresPermission Intent service, ServiceConnection conn, + int flags, UserHandle user) { + ShadowApplication.getInstance().setComponentNameAndServiceForBindService( + service.getComponent(), sComponentBinderMap.get(service.getComponent())); + return bindService(service, conn, flags); + } +} diff --git a/services/robotests/src/com/android/server/backup/testing/TransportBoundListenerStub.java b/services/robotests/src/com/android/server/backup/testing/TransportBoundListenerStub.java new file mode 100644 index 000000000000..e9f5978cc6d0 --- /dev/null +++ b/services/robotests/src/com/android/server/backup/testing/TransportBoundListenerStub.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2017 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 com.android.server.backup.testing; + +import com.android.internal.backup.IBackupTransport; +import com.android.server.backup.TransportManager; + +import java.util.HashSet; +import java.util.Set; + +/** + * Stub implementation of TransportBoundListener, which returns given result and can tell whether + * it was called for given transport. + */ +public class TransportBoundListenerStub implements + TransportManager.TransportBoundListener { + private boolean mAlwaysReturnSuccess; + private Set<IBackupTransport> mTransportsCalledFor = new HashSet<>(); + + public TransportBoundListenerStub(boolean alwaysReturnSuccess) { + this.mAlwaysReturnSuccess = alwaysReturnSuccess; + } + + @Override + public boolean onTransportBound(IBackupTransport binder) { + mTransportsCalledFor.add(binder); + return mAlwaysReturnSuccess; + } + + public boolean isCalledForTransport(IBackupTransport binder) { + return mTransportsCalledFor.contains(binder); + } + + public boolean isCalled() { + return !mTransportsCalledFor.isEmpty(); + } +} |