/* * 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 android.app; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.os.storage.StorageManager; import android.os.storage.VolumeInfo; import junit.framework.TestCase; import org.mockito.Mockito; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import static android.os.storage.VolumeInfo.STATE_MOUNTED; import static android.os.storage.VolumeInfo.STATE_UNMOUNTED; public class ApplicationPackageManagerTest extends TestCase { private static final String sInternalVolPath = "/data"; private static final String sAdoptedVolPath = "/mnt/expand/123"; private static final String sPublicVolPath = "/emulated"; private static final String sPrivateUnmountedVolPath = "/private"; private static final String sInternalVolUuid = null; //StorageManager.UUID_PRIVATE_INTERNAL private static final String sAdoptedVolUuid = "adopted"; private static final String sPublicVolUuid = "emulated"; private static final String sPrivateUnmountedVolUuid = "private"; private static final VolumeInfo sInternalVol = new VolumeInfo("private", VolumeInfo.TYPE_PRIVATE, null /*DiskInfo*/, null /*partGuid*/); private static final VolumeInfo sAdoptedVol = new VolumeInfo("adopted", VolumeInfo.TYPE_PRIVATE, null /*DiskInfo*/, null /*partGuid*/); private static final VolumeInfo sPublicVol = new VolumeInfo("public", VolumeInfo.TYPE_PUBLIC, null /*DiskInfo*/, null /*partGuid*/); private static final VolumeInfo sPrivateUnmountedVol = new VolumeInfo("private2", VolumeInfo.TYPE_PRIVATE, null /*DiskInfo*/, null /*partGuid*/); private static final List sVolumes = new ArrayList<>(); static { sInternalVol.path = sInternalVolPath; sInternalVol.state = STATE_MOUNTED; sInternalVol.fsUuid = sInternalVolUuid; sAdoptedVol.path = sAdoptedVolPath; sAdoptedVol.state = STATE_MOUNTED; sAdoptedVol.fsUuid = sAdoptedVolUuid; sPublicVol.state = STATE_MOUNTED; sPublicVol.path = sPublicVolPath; sPublicVol.fsUuid = sPublicVolUuid; sPrivateUnmountedVol.state = STATE_UNMOUNTED; sPrivateUnmountedVol.path = sPrivateUnmountedVolPath; sPrivateUnmountedVol.fsUuid = sPrivateUnmountedVolUuid; sVolumes.add(sInternalVol); sVolumes.add(sAdoptedVol); sVolumes.add(sPublicVol); sVolumes.add(sPrivateUnmountedVol); } private static final class MockedApplicationPackageManager extends ApplicationPackageManager { private boolean mForceAllowOnExternal = false; private boolean mAllow3rdPartyOnInternal = true; public MockedApplicationPackageManager() { super(null, null); } public void setForceAllowOnExternal(boolean forceAllowOnExternal) { mForceAllowOnExternal = forceAllowOnExternal; } public void setAllow3rdPartyOnInternal(boolean allow3rdPartyOnInternal) { mAllow3rdPartyOnInternal = allow3rdPartyOnInternal; } @Override public boolean isForceAllowOnExternal(Context context) { return mForceAllowOnExternal; } @Override public boolean isAllow3rdPartyOnInternal(Context context) { return mAllow3rdPartyOnInternal; } } private StorageManager getMockedStorageManager() { StorageManager storageManager = Mockito.mock(StorageManager.class); Mockito.when(storageManager.getVolumes()).thenReturn(sVolumes); Mockito.when(storageManager.findVolumeById(VolumeInfo.ID_PRIVATE_INTERNAL)) .thenReturn(sInternalVol); Mockito.when(storageManager.findVolumeByUuid(sAdoptedVolUuid)) .thenReturn(sAdoptedVol); Mockito.when(storageManager.findVolumeByUuid(sPublicVolUuid)) .thenReturn(sPublicVol); Mockito.when(storageManager.findVolumeByUuid(sPrivateUnmountedVolUuid)) .thenReturn(sPrivateUnmountedVol); return storageManager; } private void verifyReturnedVolumes(List actualVols, VolumeInfo... exptectedVols) { boolean failed = false; if (actualVols.size() != exptectedVols.length) { failed = true; } else { for (VolumeInfo vol : exptectedVols) { if (!actualVols.contains(vol)) { failed = true; break; } } } if (failed) { fail("Wrong volumes returned.\n Expected: " + Arrays.toString(exptectedVols) + "\n Actual: " + Arrays.toString(actualVols.toArray())); } } public void testGetCandidateVolumes_systemApp() throws Exception { ApplicationInfo sysAppInfo = new ApplicationInfo(); sysAppInfo.flags = ApplicationInfo.FLAG_SYSTEM; StorageManager storageManager = getMockedStorageManager(); IPackageManager pm = Mockito.mock(IPackageManager.class); MockedApplicationPackageManager appPkgMgr = new MockedApplicationPackageManager(); appPkgMgr.setAllow3rdPartyOnInternal(true); appPkgMgr.setForceAllowOnExternal(true); List candidates = appPkgMgr.getPackageCandidateVolumes(sysAppInfo, storageManager, pm); verifyReturnedVolumes(candidates, sInternalVol); appPkgMgr.setAllow3rdPartyOnInternal(true); appPkgMgr.setForceAllowOnExternal(false); candidates = appPkgMgr.getPackageCandidateVolumes(sysAppInfo, storageManager, pm); verifyReturnedVolumes(candidates, sInternalVol); appPkgMgr.setAllow3rdPartyOnInternal(false); appPkgMgr.setForceAllowOnExternal(false); candidates = appPkgMgr.getPackageCandidateVolumes(sysAppInfo, storageManager, pm); verifyReturnedVolumes(candidates, sInternalVol); appPkgMgr.setAllow3rdPartyOnInternal(false); appPkgMgr.setForceAllowOnExternal(true); candidates = appPkgMgr.getPackageCandidateVolumes(sysAppInfo, storageManager, pm); verifyReturnedVolumes(candidates, sInternalVol); } public void testGetCandidateVolumes_3rdParty_internalOnly() throws Exception { ApplicationInfo appInfo = new ApplicationInfo(); StorageManager storageManager = getMockedStorageManager(); IPackageManager pm = Mockito.mock(IPackageManager.class); Mockito.when(pm.isPackageDeviceAdminOnAnyUser(Mockito.anyString())).thenReturn(false); MockedApplicationPackageManager appPkgMgr = new MockedApplicationPackageManager(); // must allow 3rd party on internal, otherwise the app wouldn't have been installed before. appPkgMgr.setAllow3rdPartyOnInternal(true); // INSTALL_LOCATION_INTERNAL_ONLY AND INSTALL_LOCATION_UNSPECIFIED are treated the same. int[] locations = {PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY, PackageInfo.INSTALL_LOCATION_UNSPECIFIED}; for (int location : locations) { appInfo.installLocation = location; appPkgMgr.setForceAllowOnExternal(true); List candidates = appPkgMgr.getPackageCandidateVolumes( appInfo, storageManager, pm); verifyReturnedVolumes(candidates, sInternalVol, sAdoptedVol); appPkgMgr.setForceAllowOnExternal(false); candidates = appPkgMgr.getPackageCandidateVolumes(appInfo, storageManager, pm); verifyReturnedVolumes(candidates, sInternalVol); } } public void testGetCandidateVolumes_3rdParty_auto() throws Exception { ApplicationInfo appInfo = new ApplicationInfo(); StorageManager storageManager = getMockedStorageManager(); IPackageManager pm = Mockito.mock(IPackageManager.class); MockedApplicationPackageManager appPkgMgr = new MockedApplicationPackageManager(); appPkgMgr.setForceAllowOnExternal(true); // INSTALL_LOCATION_AUTO AND INSTALL_LOCATION_PREFER_EXTERNAL are treated the same. int[] locations = {PackageInfo.INSTALL_LOCATION_AUTO, PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL}; for (int location : locations) { appInfo.installLocation = location; appInfo.flags = 0; appInfo.volumeUuid = sInternalVolUuid; Mockito.when(pm.isPackageDeviceAdminOnAnyUser(Mockito.anyString())).thenReturn(false); appPkgMgr.setAllow3rdPartyOnInternal(true); List candidates = appPkgMgr.getPackageCandidateVolumes( appInfo, storageManager, pm); verifyReturnedVolumes(candidates, sInternalVol, sAdoptedVol); appInfo.volumeUuid = sInternalVolUuid; appPkgMgr.setAllow3rdPartyOnInternal(true); Mockito.when(pm.isPackageDeviceAdminOnAnyUser(Mockito.anyString())).thenReturn(true); candidates = appPkgMgr.getPackageCandidateVolumes(appInfo, storageManager, pm); verifyReturnedVolumes(candidates, sInternalVol); appInfo.flags = ApplicationInfo.FLAG_EXTERNAL_STORAGE; appInfo.volumeUuid = sAdoptedVolUuid; appPkgMgr.setAllow3rdPartyOnInternal(false); candidates = appPkgMgr.getPackageCandidateVolumes(appInfo, storageManager, pm); verifyReturnedVolumes(candidates, sAdoptedVol); } } }