blob: 55092fab5e4610677c7086917810decb92630d41 [file] [log] [blame]
/*
* Copyright (C) 2011 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.content.pm;
import android.content.Context;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
import android.test.AndroidTestCase;
import android.util.Log;
import com.android.internal.content.PackageHelper;
import org.mockito.Mockito;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import static android.net.TrafficStats.MB_IN_BYTES;
import static android.os.storage.VolumeInfo.STATE_MOUNTED;
public class PackageHelperTests extends AndroidTestCase {
private static final boolean localLOGV = true;
public static final String TAG = "PackageHelperTests";
protected final String PREFIX = "android.content.pm";
private IStorageManager mSm;
private String fullId;
private String fullId2;
private static final String sInternalVolPath = "/data";
private static final String sAdoptedVolPath = "/mnt/expand/123";
private static final String sPublicVolPath = "/emulated";
private static final String sInternalVolUuid = StorageManager.UUID_PRIVATE_INTERNAL;
private static final String sAdoptedVolUuid = "adopted";
private static final String sPublicVolUuid = "emulated";
private static final long sInternalSize = 20000;
private static final long sAdoptedSize = 10000;
private static final long sPublicSize = 1000000;
private static StorageManager sStorageManager;
private static StorageManager createStorageManagerMock() throws Exception {
VolumeInfo internalVol = new VolumeInfo("private",
VolumeInfo.TYPE_PRIVATE, null /*DiskInfo*/, null /*partGuid*/);
internalVol.path = sInternalVolPath;
internalVol.state = STATE_MOUNTED;
internalVol.fsUuid = sInternalVolUuid;
VolumeInfo adoptedVol = new VolumeInfo("adopted",
VolumeInfo.TYPE_PRIVATE, null /*DiskInfo*/, null /*partGuid*/);
adoptedVol.path = sAdoptedVolPath;
adoptedVol.state = STATE_MOUNTED;
adoptedVol.fsUuid = sAdoptedVolUuid;
VolumeInfo publicVol = new VolumeInfo("public",
VolumeInfo.TYPE_PUBLIC, null /*DiskInfo*/, null /*partGuid*/);
publicVol.state = STATE_MOUNTED;
publicVol.path = sPublicVolPath;
publicVol.fsUuid = sPublicVolUuid;
List<VolumeInfo> volumes = new ArrayList<>();
volumes.add(internalVol);
volumes.add(adoptedVol);
volumes.add(publicVol);
StorageManager storageManager = Mockito.mock(StorageManager.class);
Mockito.when(storageManager.getVolumes()).thenReturn(volumes);
File internalFile = new File(sInternalVolPath);
File adoptedFile = new File(sAdoptedVolPath);
File publicFile = new File(sPublicVolPath);
UUID internalUuid = UUID.randomUUID();
UUID adoptedUuid = UUID.randomUUID();
UUID publicUuid = UUID.randomUUID();
Mockito.when(storageManager.getStorageBytesUntilLow(internalFile)).thenReturn(sInternalSize);
Mockito.when(storageManager.getStorageBytesUntilLow(adoptedFile)).thenReturn(sAdoptedSize);
Mockito.when(storageManager.getStorageBytesUntilLow(publicFile)).thenReturn(sPublicSize);
Mockito.when(storageManager.getUuidForPath(Mockito.eq(internalFile))).thenReturn(internalUuid);
Mockito.when(storageManager.getUuidForPath(Mockito.eq(adoptedFile))).thenReturn(adoptedUuid);
Mockito.when(storageManager.getUuidForPath(Mockito.eq(publicFile))).thenReturn(publicUuid);
Mockito.when(storageManager.getAllocatableBytes(Mockito.eq(internalUuid), Mockito.anyInt()))
.thenReturn(sInternalSize);
Mockito.when(storageManager.getAllocatableBytes(Mockito.eq(adoptedUuid), Mockito.anyInt()))
.thenReturn(sAdoptedSize);
Mockito.when(storageManager.getAllocatableBytes(Mockito.eq(publicUuid), Mockito.anyInt()))
.thenReturn(sPublicSize);
return storageManager;
}
private static final class MockedInterface extends PackageHelper.TestableInterface {
private boolean mForceAllowOnExternal = false;
private boolean mAllow3rdPartyOnInternal = true;
private ApplicationInfo mApplicationInfo = null;
public void setMockValues(ApplicationInfo applicationInfo,
boolean forceAllowOnExternal, boolean allow3rdPartyOnInternal) {
mForceAllowOnExternal = forceAllowOnExternal;
mAllow3rdPartyOnInternal = allow3rdPartyOnInternal;
mApplicationInfo = applicationInfo;
}
@Override
public StorageManager getStorageManager(Context context) {
return sStorageManager;
}
@Override
public boolean getForceAllowOnExternalSetting(Context context) {
return mForceAllowOnExternal;
}
@Override
public boolean getAllow3rdPartyOnInternalConfig(Context context) {
return mAllow3rdPartyOnInternal;
}
@Override
public ApplicationInfo getExistingAppInfo(Context context, String packagename) {
return mApplicationInfo;
}
@Override
public File getDataDirectory() {
return new File(sInternalVolPath);
}
}
private IStorageManager getSm() {
IBinder service = ServiceManager.getService("mount");
if (service != null) {
return IStorageManager.Stub.asInterface(service);
} else {
Log.e(TAG, "Can't get mount service");
}
return null;
}
private void cleanupContainers() throws RemoteException {
Log.d(TAG,"cleanUp");
IStorageManager sm = getSm();
String[] containers = sm.getSecureContainerList();
for (int i = 0; i < containers.length; i++) {
if (containers[i].startsWith(PREFIX)) {
Log.d(TAG,"cleaing up "+containers[i]);
sm.destroySecureContainer(containers[i], true);
}
}
}
@Override
protected void setUp() throws Exception {
super.setUp();
sStorageManager = createStorageManagerMock();
if (localLOGV) Log.i(TAG, "Cleaning out old test containers");
cleanupContainers();
}
@Override
protected void tearDown() throws Exception {
super.tearDown();
sStorageManager = null;
if (localLOGV) Log.i(TAG, "Cleaning out old test containers");
cleanupContainers();
}
public void testMountAndPullSdCard() throws Exception {
fullId = PREFIX;
fullId2 = PackageHelper.createSdDir(1024 * MB_IN_BYTES, fullId, "none",
android.os.Process.myUid(), true);
Log.d(TAG, "getSdDir=" + PackageHelper.getSdDir(fullId));
PackageHelper.unMountSdDir(fullId);
Runnable r1 = getMountRunnable();
Runnable r2 = getDestroyRunnable();
Thread thread = new Thread(r1);
Thread thread2 = new Thread(r2);
thread2.start();
thread.start();
}
public Runnable getMountRunnable() {
Runnable r = new Runnable () {
public void run () {
try {
Thread.sleep(5);
String path = PackageHelper.mountSdDir(fullId, "none",
android.os.Process.myUid());
Log.e(TAG, "mount done " + path);
} catch (IllegalArgumentException iae) {
throw iae;
} catch (Throwable t) {
Log.e(TAG, "mount failed", t);
}
}
};
return r;
}
public Runnable getDestroyRunnable() {
Runnable r = new Runnable () {
public void run () {
try {
PackageHelper.destroySdDir(fullId);
Log.e(TAG, "destroy done: " + fullId);
} catch (Throwable t) {
Log.e(TAG, "destroy failed", t);
}
}
};
return r;
}
public void testResolveInstallVolumeInternal_SystemApp() throws IOException {
ApplicationInfo systemAppInfo = new ApplicationInfo();
systemAppInfo.flags = ApplicationInfo.FLAG_SYSTEM;
// All test cases for when the system app fits on internal.
MockedInterface mockedInterface = new MockedInterface();
mockedInterface.setMockValues(systemAppInfo, false /*force allow on external*/,
true /*allow 3rd party on internal*/);
String volume = null;
volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
1 /*install location*/, 1000 /*size bytes*/, mockedInterface);
assertEquals(StorageManager.UUID_PRIVATE_INTERNAL, volume);
mockedInterface.setMockValues(systemAppInfo, true /*force allow on external*/,
true /*allow 3rd party on internal*/);
volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
1 /*install location*/, 1000 /*size bytes*/, mockedInterface);
assertEquals(StorageManager.UUID_PRIVATE_INTERNAL, volume);
mockedInterface.setMockValues(systemAppInfo, false /*force allow on external*/,
false /*allow 3rd party on internal*/);
volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
1 /*install location*/, 1000 /*size bytes*/, mockedInterface);
assertEquals(StorageManager.UUID_PRIVATE_INTERNAL, volume);
mockedInterface.setMockValues(systemAppInfo, true /*force allow on external*/,
false /*allow 3rd party on internal*/);
volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
1 /*install location*/, 1000 /*size bytes*/, mockedInterface);
assertEquals(StorageManager.UUID_PRIVATE_INTERNAL, volume);
// All test cases for when the system app does not fit on internal.
// Exception should be thrown.
mockedInterface.setMockValues(systemAppInfo, true /*force allow on external*/,
true /*allow 3rd party on internal*/);
try {
PackageHelper.resolveInstallVolume(getContext(), "package.name",
1 /*install location*/, 1000000 /*size bytes*/, mockedInterface);
fail("Expected exception in resolveInstallVolume was not thrown");
} catch(IOException e) {
// expected
}
mockedInterface.setMockValues(systemAppInfo, false /*force allow on external*/,
true /*allow 3rd party on internal*/);
try {
PackageHelper.resolveInstallVolume(getContext(), "package.name",
1 /*install location*/, 1000000 /*size bytes*/, mockedInterface);
fail("Expected exception in resolveInstallVolume was not thrown");
} catch(IOException e) {
// expected
}
mockedInterface.setMockValues(systemAppInfo, false /*force allow on external*/,
false /*allow 3rd party on internal*/);
try {
PackageHelper.resolveInstallVolume(getContext(), "package.name",
1 /*install location*/, 1000000 /*size bytes*/, mockedInterface);
fail("Expected exception in resolveInstallVolume was not thrown");
} catch(IOException e) {
// expected
}
mockedInterface.setMockValues(systemAppInfo, true /*force allow on external*/,
false /*allow 3rd party on internal*/);
try {
PackageHelper.resolveInstallVolume(getContext(), "package.name",
1 /*install location*/, 1000000 /*size bytes*/, mockedInterface);
fail("Expected exception in resolveInstallVolume was not thrown");
} catch(IOException e) {
// expected
}
}
public void testResolveInstallVolumeInternal_3rdParty_existing_not_too_big()
throws IOException {
// Existing apps always stay on the same volume.
// Test cases for existing app on internal.
ApplicationInfo appInfo = new ApplicationInfo();
appInfo.volumeUuid = sInternalVolUuid;
MockedInterface mockedInterface = new MockedInterface();
mockedInterface.setMockValues(appInfo, false /*force allow on external*/,
true /*allow 3rd party on internal*/);
String volume = null;
volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
0 /*install location*/, 1000 /*size bytes*/, mockedInterface);
assertEquals(sInternalVolUuid, volume);
mockedInterface.setMockValues(appInfo, true /*force allow on external*/,
true /*allow 3rd party on internal*/);
volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
0 /*install location*/, 1000 /*size bytes*/, mockedInterface);
assertEquals(sInternalVolUuid, volume);
}
public void testResolveInstallVolumeInternal_3rdParty_existing_not_too_big_adopted()
throws IOException {
// Test cases for existing app on the adopted media.
ApplicationInfo appInfo = new ApplicationInfo();
MockedInterface mockedInterface = new MockedInterface();
String volume;
appInfo.volumeUuid = sAdoptedVolUuid;
mockedInterface.setMockValues(appInfo, false /*force allow on external*/,
true /*allow 3rd party on internal*/);
volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
0 /*install location*/, 1000 /*size bytes*/, mockedInterface);
assertEquals(sAdoptedVolUuid, volume);
mockedInterface.setMockValues(appInfo, true /*force allow on external*/,
true /*allow 3rd party on internal*/);
volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
0 /*install location*/, 1000 /*size bytes*/, mockedInterface);
assertEquals(sAdoptedVolUuid, volume);
mockedInterface.setMockValues(appInfo, false /*force allow on external*/,
false /*allow 3rd party on internal*/);
volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
0 /*install location*/, 1000 /*size bytes*/, mockedInterface);
assertEquals(sAdoptedVolUuid, volume);
mockedInterface.setMockValues(appInfo, true /*force allow on external*/,
false /*allow 3rd party on internal*/);
volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
0 /*install location*/, 1000 /*size bytes*/, mockedInterface);
assertEquals(sAdoptedVolUuid, volume);
}
public void testResolveInstallVolumeAdopted_3rdParty_existing_too_big() {
// Test: update size too big, will throw exception.
ApplicationInfo appInfo = new ApplicationInfo();
appInfo.volumeUuid = sAdoptedVolUuid;
MockedInterface mockedInterface = new MockedInterface();
mockedInterface.setMockValues(appInfo, false /*force allow on external*/,
true /*allow 3rd party on internal*/);
try {
PackageHelper.resolveInstallVolume(getContext(), "package.name",
0 /*install location*/, 10000001 /*BIG size, won't fit*/, mockedInterface);
fail("Expected exception was not thrown " + appInfo.volumeUuid);
} catch (IOException e) {
//expected
}
mockedInterface.setMockValues(appInfo, false /*force allow on external*/,
false /*allow 3rd party on internal*/);
try {
PackageHelper.resolveInstallVolume(getContext(), "package.name",
0 /*install location*/, 10000001 /*BIG size, won't fit*/, mockedInterface);
fail("Expected exception was not thrown " + appInfo.volumeUuid);
} catch (IOException e) {
//expected
}
mockedInterface.setMockValues(appInfo, true /*force allow on external*/,
false /*allow 3rd party on internal*/);
try {
PackageHelper.resolveInstallVolume(getContext(), "package.name",
0 /*install location*/, 10000001 /*BIG size, won't fit*/, mockedInterface);
fail("Expected exception was not thrown " + appInfo.volumeUuid);
} catch (IOException e) {
//expected
}
mockedInterface.setMockValues(appInfo, true /*force allow on external*/,
true /*allow 3rd party on internal*/);
try {
PackageHelper.resolveInstallVolume(getContext(), "package.name",
0 /*install location*/, 10000001 /*BIG size, won't fit*/, mockedInterface);
fail("Expected exception was not thrown " + appInfo.volumeUuid);
} catch (IOException e) {
//expected
}
}
public void testResolveInstallVolumeInternal_3rdParty_auto() throws IOException {
ApplicationInfo appInfo = null;
MockedInterface mockedInterface = new MockedInterface();
mockedInterface.setMockValues(appInfo, false /*force allow on external*/,
true /*allow 3rd party on internal*/);
String volume = null;
volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
0 /*install location auto*/, 1000 /*size bytes*/, mockedInterface);
// Should return the volume with bigger available space.
assertEquals(sInternalVolUuid, volume);
mockedInterface.setMockValues(appInfo, true /*force allow on external*/,
true /*allow 3rd party on internal*/);
volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
0 /*install location auto*/, 1000 /*size bytes*/, mockedInterface);
// Should return the volume with bigger available space.
assertEquals(sInternalVolUuid, volume);
mockedInterface.setMockValues(appInfo, true /*force allow on external*/,
false /*allow 3rd party on internal*/);
volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
0 /*install location auto*/, 1000 /*size bytes*/, mockedInterface);
// Should return the volume with bigger available space.
assertEquals(sAdoptedVolUuid, volume);
mockedInterface.setMockValues(appInfo, false /*force allow on external*/,
false /*allow 3rd party on internal*/);
volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
0 /*install location auto*/, 1000 /*size bytes*/, mockedInterface);
// Should return the volume with bigger available space.
assertEquals(sAdoptedVolUuid, volume);
}
public void testResolveInstallVolumeInternal_3rdParty_internal_only() throws IOException {
ApplicationInfo appInfo = null;
MockedInterface mockedInterface = new MockedInterface();
mockedInterface.setMockValues(appInfo, false /*force allow on external*/,
true /*allow 3rd party on internal*/);
String volume = null;
volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
1 /*install location internal ONLY*/, 1000 /*size bytes*/, mockedInterface);
assertEquals(sInternalVolUuid, volume);
mockedInterface.setMockValues(appInfo, true /*force allow on external*/,
true /*allow 3rd party on internal*/);
volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
1 /*install location internal ONLY*/, 1000 /*size bytes*/, mockedInterface);
assertEquals(sInternalVolUuid, volume);
mockedInterface.setMockValues(appInfo, false /*force allow on external*/,
false /*allow 3rd party on internal*/);
try {
volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
1 /*install location internal only*/, 1000 /*size bytes*/, mockedInterface);
fail("Expected exception in resolveInstallVolume was not thrown");
} catch (IOException e) {
//expected
}
appInfo = null;
mockedInterface.setMockValues(appInfo, true /*force allow on external*/,
false /*allow 3rd party on internal*/);
volume = null;
volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
1 /*install location internal only*/, 1000 /*size bytes*/, mockedInterface);
assertEquals(sAdoptedVolUuid, volume);
}
public void testResolveInstallVolumeInternal_3rdParty_not_allowed_on_internal()
throws IOException {
ApplicationInfo appInfo = null;
MockedInterface mockedInterface = new MockedInterface();
mockedInterface.setMockValues(appInfo, false /*force allow on external*/,
false /*allow 3rd party on internal*/);
String volume = null;
volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
0 /*install location auto*/, 1000 /*size bytes*/, mockedInterface);
// Should return the non-internal volume.
assertEquals(sAdoptedVolUuid, volume);
appInfo = null;
mockedInterface.setMockValues(appInfo, true /*force allow on external*/,
false /*allow 3rd party on internal*/);
volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
0 /*install location auto*/, 1000 /*size bytes*/, mockedInterface);
// Should return the non-internal volume.
assertEquals(sAdoptedVolUuid, volume);
}
public void testResolveInstallVolumeInternal_3rdParty_internal_only_too_big() {
ApplicationInfo appInfo = null;
MockedInterface mockedInterface = new MockedInterface();
mockedInterface.setMockValues(appInfo, false /*force allow on external*/,
true /*allow 3rd party on internal*/);
String volume = null;
try {
volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
1 /*install location internal ONLY*/,
1000000 /*size too big*/, mockedInterface);
fail("Expected exception in resolveInstallVolume was not thrown");
} catch (IOException e) {
//expected
}
}
public void testResolveInstallVolumeInternal_3rdParty_internal_only_not_allowed()
throws IOException {
ApplicationInfo appInfo = null;
MockedInterface mockedInterface = new MockedInterface();
mockedInterface.setMockValues(appInfo, false /*force allow on external*/,
false /*allow 3rd party on internal*/);
String volume = null;
try {
volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
1 /*install location internal only*/, 1000 /*size bytes*/, mockedInterface);
fail("Expected exception in resolveInstallVolume was not thrown");
} catch (IOException e) {
//expected
}
appInfo = null;
mockedInterface.setMockValues(appInfo, true /*force allow on external*/,
false /*allow 3rd party on internal*/);
volume = null;
volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
1 /*install location internal only*/, 1000 /*size bytes*/, mockedInterface);
assertEquals(sAdoptedVolUuid, volume);
}
public void testResolveInstallVolumeInternal_3rdParty_internal_only_forced_to_external()
throws IOException {
// New/existing installation: New
// app request location: Internal Only
// 3rd party allowed on internal: False
// Force allow external in setting: True
// Size fit? Yes
ApplicationInfo appInfo = null;
MockedInterface mockedInterface = new MockedInterface();
mockedInterface.setMockValues(appInfo, true /*force allow on external*/,
false /*allow 3rd party on internal*/);
String volume = null;
volume = PackageHelper.resolveInstallVolume(getContext(), "package.name",
1 /*install location internal only*/, 1000 /*size bytes*/, mockedInterface);
assertEquals(sAdoptedVolUuid, volume);
}
}