| /* |
| * 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 android.support.test.filters.LargeTest; |
| |
| 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; |
| |
| @LargeTest |
| 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<VolumeInfo> 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<VolumeInfo> 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<VolumeInfo> 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<VolumeInfo> 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<VolumeInfo> 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); |
| } |
| } |
| } |