1 /* 2 * Copyright (C) 2017 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 android.app; 18 19 import android.content.Context; 20 import android.content.pm.ApplicationInfo; 21 import android.content.pm.IPackageManager; 22 import android.content.pm.PackageInfo; 23 import android.os.storage.StorageManager; 24 import android.os.storage.VolumeInfo; 25 import android.support.test.filters.LargeTest; 26 27 import junit.framework.TestCase; 28 29 import org.mockito.Mockito; 30 31 import java.util.ArrayList; 32 import java.util.Arrays; 33 import java.util.List; 34 35 import static android.os.storage.VolumeInfo.STATE_MOUNTED; 36 import static android.os.storage.VolumeInfo.STATE_UNMOUNTED; 37 38 @LargeTest 39 public class ApplicationPackageManagerTest extends TestCase { 40 private static final String sInternalVolPath = "/data"; 41 private static final String sAdoptedVolPath = "/mnt/expand/123"; 42 private static final String sPublicVolPath = "/emulated"; 43 private static final String sPrivateUnmountedVolPath = "/private"; 44 45 private static final String sInternalVolUuid = null; //StorageManager.UUID_PRIVATE_INTERNAL 46 private static final String sAdoptedVolUuid = "adopted"; 47 private static final String sPublicVolUuid = "emulated"; 48 private static final String sPrivateUnmountedVolUuid = "private"; 49 50 private static final VolumeInfo sInternalVol = new VolumeInfo("private", 51 VolumeInfo.TYPE_PRIVATE, null /*DiskInfo*/, null /*partGuid*/); 52 53 private static final VolumeInfo sAdoptedVol = new VolumeInfo("adopted", 54 VolumeInfo.TYPE_PRIVATE, null /*DiskInfo*/, null /*partGuid*/); 55 56 private static final VolumeInfo sPublicVol = new VolumeInfo("public", 57 VolumeInfo.TYPE_PUBLIC, null /*DiskInfo*/, null /*partGuid*/); 58 59 private static final VolumeInfo sPrivateUnmountedVol = new VolumeInfo("private2", 60 VolumeInfo.TYPE_PRIVATE, null /*DiskInfo*/, null /*partGuid*/); 61 62 private static final List<VolumeInfo> sVolumes = new ArrayList<>(); 63 64 static { 65 sInternalVol.path = sInternalVolPath; 66 sInternalVol.state = STATE_MOUNTED; 67 sInternalVol.fsUuid = sInternalVolUuid; 68 69 sAdoptedVol.path = sAdoptedVolPath; 70 sAdoptedVol.state = STATE_MOUNTED; 71 sAdoptedVol.fsUuid = sAdoptedVolUuid; 72 73 sPublicVol.state = STATE_MOUNTED; 74 sPublicVol.path = sPublicVolPath; 75 sPublicVol.fsUuid = sPublicVolUuid; 76 77 sPrivateUnmountedVol.state = STATE_UNMOUNTED; 78 sPrivateUnmountedVol.path = sPrivateUnmountedVolPath; 79 sPrivateUnmountedVol.fsUuid = sPrivateUnmountedVolUuid; 80 81 sVolumes.add(sInternalVol); 82 sVolumes.add(sAdoptedVol); 83 sVolumes.add(sPublicVol); 84 sVolumes.add(sPrivateUnmountedVol); 85 } 86 87 private static final class MockedApplicationPackageManager extends ApplicationPackageManager { 88 private boolean mForceAllowOnExternal = false; 89 private boolean mAllow3rdPartyOnInternal = true; 90 91 public MockedApplicationPackageManager() { 92 super(null, null); 93 } 94 95 public void setForceAllowOnExternal(boolean forceAllowOnExternal) { 96 mForceAllowOnExternal = forceAllowOnExternal; 97 } 98 99 public void setAllow3rdPartyOnInternal(boolean allow3rdPartyOnInternal) { 100 mAllow3rdPartyOnInternal = allow3rdPartyOnInternal; 101 } 102 103 @Override 104 public boolean isForceAllowOnExternal(Context context) { 105 return mForceAllowOnExternal; 106 } 107 108 @Override 109 public boolean isAllow3rdPartyOnInternal(Context context) { 110 return mAllow3rdPartyOnInternal; 111 } 112 } 113 114 private StorageManager getMockedStorageManager() { 115 StorageManager storageManager = Mockito.mock(StorageManager.class); 116 Mockito.when(storageManager.getVolumes()).thenReturn(sVolumes); 117 Mockito.when(storageManager.findVolumeById(VolumeInfo.ID_PRIVATE_INTERNAL)) 118 .thenReturn(sInternalVol); 119 Mockito.when(storageManager.findVolumeByUuid(sAdoptedVolUuid)) 120 .thenReturn(sAdoptedVol); 121 Mockito.when(storageManager.findVolumeByUuid(sPublicVolUuid)) 122 .thenReturn(sPublicVol); 123 Mockito.when(storageManager.findVolumeByUuid(sPrivateUnmountedVolUuid)) 124 .thenReturn(sPrivateUnmountedVol); 125 return storageManager; 126 } 127 128 private void verifyReturnedVolumes(List<VolumeInfo> actualVols, VolumeInfo... exptectedVols) { 129 boolean failed = false; 130 if (actualVols.size() != exptectedVols.length) { 131 failed = true; 132 } else { 133 for (VolumeInfo vol : exptectedVols) { 134 if (!actualVols.contains(vol)) { 135 failed = true; 136 break; 137 } 138 } 139 } 140 141 if (failed) { 142 fail("Wrong volumes returned.\n Expected: " + Arrays.toString(exptectedVols) 143 + "\n Actual: " + Arrays.toString(actualVols.toArray())); 144 } 145 } 146 147 public void testGetCandidateVolumes_systemApp() throws Exception { 148 ApplicationInfo sysAppInfo = new ApplicationInfo(); 149 sysAppInfo.flags = ApplicationInfo.FLAG_SYSTEM; 150 151 StorageManager storageManager = getMockedStorageManager(); 152 IPackageManager pm = Mockito.mock(IPackageManager.class); 153 154 MockedApplicationPackageManager appPkgMgr = new MockedApplicationPackageManager(); 155 156 appPkgMgr.setAllow3rdPartyOnInternal(true); 157 appPkgMgr.setForceAllowOnExternal(true); 158 List<VolumeInfo> candidates = 159 appPkgMgr.getPackageCandidateVolumes(sysAppInfo, storageManager, pm); 160 verifyReturnedVolumes(candidates, sInternalVol); 161 162 appPkgMgr.setAllow3rdPartyOnInternal(true); 163 appPkgMgr.setForceAllowOnExternal(false); 164 candidates = appPkgMgr.getPackageCandidateVolumes(sysAppInfo, storageManager, pm); 165 verifyReturnedVolumes(candidates, sInternalVol); 166 167 appPkgMgr.setAllow3rdPartyOnInternal(false); 168 appPkgMgr.setForceAllowOnExternal(false); 169 candidates = appPkgMgr.getPackageCandidateVolumes(sysAppInfo, storageManager, pm); 170 verifyReturnedVolumes(candidates, sInternalVol); 171 172 appPkgMgr.setAllow3rdPartyOnInternal(false); 173 appPkgMgr.setForceAllowOnExternal(true); 174 candidates = appPkgMgr.getPackageCandidateVolumes(sysAppInfo, storageManager, pm); 175 verifyReturnedVolumes(candidates, sInternalVol); 176 } 177 178 public void testGetCandidateVolumes_3rdParty_internalOnly() throws Exception { 179 ApplicationInfo appInfo = new ApplicationInfo(); 180 StorageManager storageManager = getMockedStorageManager(); 181 182 IPackageManager pm = Mockito.mock(IPackageManager.class); 183 Mockito.when(pm.isPackageDeviceAdminOnAnyUser(Mockito.anyString())).thenReturn(false); 184 185 MockedApplicationPackageManager appPkgMgr = new MockedApplicationPackageManager(); 186 187 // must allow 3rd party on internal, otherwise the app wouldn't have been installed before. 188 appPkgMgr.setAllow3rdPartyOnInternal(true); 189 190 // INSTALL_LOCATION_INTERNAL_ONLY AND INSTALL_LOCATION_UNSPECIFIED are treated the same. 191 int[] locations = {PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY, 192 PackageInfo.INSTALL_LOCATION_UNSPECIFIED}; 193 194 for (int location : locations) { 195 appInfo.installLocation = location; 196 appPkgMgr.setForceAllowOnExternal(true); 197 List<VolumeInfo> candidates = appPkgMgr.getPackageCandidateVolumes( 198 appInfo, storageManager, pm); 199 verifyReturnedVolumes(candidates, sInternalVol, sAdoptedVol); 200 201 appPkgMgr.setForceAllowOnExternal(false); 202 candidates = appPkgMgr.getPackageCandidateVolumes(appInfo, storageManager, pm); 203 verifyReturnedVolumes(candidates, sInternalVol); 204 } 205 } 206 207 public void testGetCandidateVolumes_3rdParty_auto() throws Exception { 208 ApplicationInfo appInfo = new ApplicationInfo(); 209 StorageManager storageManager = getMockedStorageManager(); 210 211 IPackageManager pm = Mockito.mock(IPackageManager.class); 212 213 MockedApplicationPackageManager appPkgMgr = new MockedApplicationPackageManager(); 214 appPkgMgr.setForceAllowOnExternal(true); 215 216 // INSTALL_LOCATION_AUTO AND INSTALL_LOCATION_PREFER_EXTERNAL are treated the same. 217 int[] locations = {PackageInfo.INSTALL_LOCATION_AUTO, 218 PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL}; 219 220 for (int location : locations) { 221 appInfo.installLocation = location; 222 appInfo.flags = 0; 223 224 appInfo.volumeUuid = sInternalVolUuid; 225 Mockito.when(pm.isPackageDeviceAdminOnAnyUser(Mockito.anyString())).thenReturn(false); 226 appPkgMgr.setAllow3rdPartyOnInternal(true); 227 List<VolumeInfo> candidates = appPkgMgr.getPackageCandidateVolumes( 228 appInfo, storageManager, pm); 229 verifyReturnedVolumes(candidates, sInternalVol, sAdoptedVol); 230 231 appInfo.volumeUuid = sInternalVolUuid; 232 appPkgMgr.setAllow3rdPartyOnInternal(true); 233 Mockito.when(pm.isPackageDeviceAdminOnAnyUser(Mockito.anyString())).thenReturn(true); 234 candidates = appPkgMgr.getPackageCandidateVolumes(appInfo, storageManager, pm); 235 verifyReturnedVolumes(candidates, sInternalVol); 236 237 appInfo.flags = ApplicationInfo.FLAG_EXTERNAL_STORAGE; 238 appInfo.volumeUuid = sAdoptedVolUuid; 239 appPkgMgr.setAllow3rdPartyOnInternal(false); 240 candidates = appPkgMgr.getPackageCandidateVolumes(appInfo, storageManager, pm); 241 verifyReturnedVolumes(candidates, sAdoptedVol); 242 } 243 } 244 } 245