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