Add a flag for whether non-system apps can be installed on internal.
This is for a feature in Android Auto Embedded. Cars have 10+ years of life and the eMMC has limit number of erase/write cycles. To protect the eMMC internal storage, we recommend car OEMs to adopt an SD card and install 3rd party apps to the adopted storage. We still respect the installLocation flag in AndroidManifest. If the developer request internalOnly and the OEM does not allow 3rd party apps on internal, the installation will fail. Test: Unit tests added Bug: 30980219 Change-Id: I9c40a099b40264a53b1d9d6ac7d5178bef478ed8
This commit is contained in:
@@ -16,8 +16,6 @@
|
||||
|
||||
package com.android.internal.content;
|
||||
|
||||
import static android.net.TrafficStats.MB_IN_BYTES;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
@@ -38,7 +36,7 @@ import android.provider.Settings;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
|
||||
import libcore.io.IoUtils;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
@@ -50,6 +48,11 @@ import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import libcore.io.IoUtils;
|
||||
|
||||
import static android.net.TrafficStats.MB_IN_BYTES;
|
||||
import static android.os.storage.VolumeInfo.ID_PRIVATE_INTERNAL;
|
||||
|
||||
/**
|
||||
* Constants used internally between the PackageManager
|
||||
* and media container service transports.
|
||||
@@ -74,6 +77,8 @@ public class PackageHelper {
|
||||
public static final int APP_INSTALL_INTERNAL = 1;
|
||||
public static final int APP_INSTALL_EXTERNAL = 2;
|
||||
|
||||
private static TestableInterface sDefaultTestableInterface = null;
|
||||
|
||||
public static IStorageManager getStorageManager() throws RemoteException {
|
||||
IBinder service = ServiceManager.getService("mount");
|
||||
if (service != null) {
|
||||
@@ -337,6 +342,65 @@ public class PackageHelper {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A group of external dependencies used in
|
||||
* {@link #resolveInstallVolume(Context, String, int, long)}. It can be backed by real values
|
||||
* from the system or mocked ones for testing purposes.
|
||||
*/
|
||||
public static abstract class TestableInterface {
|
||||
abstract public StorageManager getStorageManager(Context context);
|
||||
abstract public boolean getForceAllowOnExternalSetting(Context context);
|
||||
abstract public boolean getAllow3rdPartyOnInternalConfig(Context context);
|
||||
abstract public ApplicationInfo getExistingAppInfo(Context context, String packageName);
|
||||
abstract public File getDataDirectory();
|
||||
|
||||
public boolean fitsOnInternalStorage(Context context, long sizeBytes) {
|
||||
StorageManager storage = getStorageManager(context);
|
||||
File target = getDataDirectory();
|
||||
return (sizeBytes <= storage.getStorageBytesUntilLow(target));
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized static TestableInterface getDefaultTestableInterface() {
|
||||
if (sDefaultTestableInterface == null) {
|
||||
sDefaultTestableInterface = new TestableInterface() {
|
||||
@Override
|
||||
public StorageManager getStorageManager(Context context) {
|
||||
return context.getSystemService(StorageManager.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getForceAllowOnExternalSetting(Context context) {
|
||||
return Settings.Global.getInt(context.getContentResolver(),
|
||||
Settings.Global.FORCE_ALLOW_ON_EXTERNAL, 0) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getAllow3rdPartyOnInternalConfig(Context context) {
|
||||
return context.getResources().getBoolean(
|
||||
com.android.internal.R.bool.config_allow3rdPartyAppOnInternal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApplicationInfo getExistingAppInfo(Context context, String packageName) {
|
||||
ApplicationInfo existingInfo = null;
|
||||
try {
|
||||
existingInfo = context.getPackageManager().getApplicationInfo(packageName,
|
||||
PackageManager.MATCH_ANY_USER);
|
||||
} catch (NameNotFoundException ignored) {
|
||||
}
|
||||
return existingInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getDataDirectory() {
|
||||
return Environment.getDataDirectory();
|
||||
}
|
||||
};
|
||||
}
|
||||
return sDefaultTestableInterface;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a requested {@link PackageInfo#installLocation} and calculated
|
||||
* install size, pick the actual volume to install the app. Only considers
|
||||
@@ -348,25 +412,44 @@ public class PackageHelper {
|
||||
*/
|
||||
public static String resolveInstallVolume(Context context, String packageName,
|
||||
int installLocation, long sizeBytes) throws IOException {
|
||||
final boolean forceAllowOnExternal = Settings.Global.getInt(
|
||||
context.getContentResolver(), Settings.Global.FORCE_ALLOW_ON_EXTERNAL, 0) != 0;
|
||||
TestableInterface testableInterface = getDefaultTestableInterface();
|
||||
return resolveInstallVolume(context, packageName,
|
||||
installLocation, sizeBytes, testableInterface);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public static String resolveInstallVolume(Context context, String packageName,
|
||||
int installLocation, long sizeBytes, TestableInterface testInterface)
|
||||
throws IOException {
|
||||
final boolean forceAllowOnExternal = testInterface.getForceAllowOnExternalSetting(context);
|
||||
final boolean allow3rdPartyOnInternal =
|
||||
testInterface.getAllow3rdPartyOnInternalConfig(context);
|
||||
// TODO: handle existing apps installed in ASEC; currently assumes
|
||||
// they'll end up back on internal storage
|
||||
ApplicationInfo existingInfo = null;
|
||||
try {
|
||||
existingInfo = context.getPackageManager().getApplicationInfo(packageName,
|
||||
PackageManager.MATCH_ANY_USER);
|
||||
} catch (NameNotFoundException ignored) {
|
||||
ApplicationInfo existingInfo = testInterface.getExistingAppInfo(context, packageName);
|
||||
|
||||
final boolean fitsOnInternal = testInterface.fitsOnInternalStorage(context, sizeBytes);
|
||||
final StorageManager storageManager =
|
||||
testInterface.getStorageManager(context);
|
||||
|
||||
// System apps always forced to internal storage
|
||||
if (existingInfo != null && existingInfo.isSystemApp()) {
|
||||
if (fitsOnInternal) {
|
||||
return StorageManager.UUID_PRIVATE_INTERNAL;
|
||||
} else {
|
||||
throw new IOException("Not enough space on existing volume "
|
||||
+ existingInfo.volumeUuid + " for system app " + packageName + " upgrade");
|
||||
}
|
||||
}
|
||||
|
||||
final StorageManager storageManager = context.getSystemService(StorageManager.class);
|
||||
final boolean fitsOnInternal = fitsOnInternal(context, sizeBytes);
|
||||
|
||||
// Now deal with non-system apps.
|
||||
final ArraySet<String> allCandidates = new ArraySet<>();
|
||||
VolumeInfo bestCandidate = null;
|
||||
long bestCandidateAvailBytes = Long.MIN_VALUE;
|
||||
for (VolumeInfo vol : storageManager.getVolumes()) {
|
||||
if (vol.type == VolumeInfo.TYPE_PRIVATE && vol.isMountedWritable()) {
|
||||
boolean isInternalStorage = ID_PRIVATE_INTERNAL.equals(vol.id);
|
||||
if (vol.type == VolumeInfo.TYPE_PRIVATE && vol.isMountedWritable()
|
||||
&& (!isInternalStorage || allow3rdPartyOnInternal)) {
|
||||
final long availBytes = storageManager.getStorageBytesUntilLow(new File(vol.path));
|
||||
if (availBytes >= sizeBytes) {
|
||||
allCandidates.add(vol.fsUuid);
|
||||
@@ -378,11 +461,6 @@ public class PackageHelper {
|
||||
}
|
||||
}
|
||||
|
||||
// System apps always forced to internal storage
|
||||
if (existingInfo != null && existingInfo.isSystemApp()) {
|
||||
installLocation = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;
|
||||
}
|
||||
|
||||
// If app expresses strong desire for internal storage, honor it
|
||||
if (!forceAllowOnExternal
|
||||
&& installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) {
|
||||
@@ -391,6 +469,11 @@ public class PackageHelper {
|
||||
throw new IOException("Cannot automatically move " + packageName + " from "
|
||||
+ existingInfo.volumeUuid + " to internal storage");
|
||||
}
|
||||
|
||||
if (!allow3rdPartyOnInternal) {
|
||||
throw new IOException("Not allowed to install non-system apps on internal storage");
|
||||
}
|
||||
|
||||
if (fitsOnInternal) {
|
||||
return StorageManager.UUID_PRIVATE_INTERNAL;
|
||||
} else {
|
||||
@@ -411,14 +494,13 @@ public class PackageHelper {
|
||||
}
|
||||
}
|
||||
|
||||
// We're left with either preferring external or auto, so just pick
|
||||
// We're left with new installations with either preferring external or auto, so just pick
|
||||
// volume with most space
|
||||
if (bestCandidate != null) {
|
||||
return bestCandidate.fsUuid;
|
||||
} else if (fitsOnInternal) {
|
||||
return StorageManager.UUID_PRIVATE_INTERNAL;
|
||||
} else {
|
||||
throw new IOException("No special requests, but no room anywhere");
|
||||
throw new IOException("No special requests, but no room on allowed volumes. "
|
||||
+ " allow3rdPartyOnInternal? " + allow3rdPartyOnInternal);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2687,4 +2687,7 @@
|
||||
user-set value if toggled by settings so the "Transition animation scale" setting
|
||||
should also be hidden if intended to be permanent. -->
|
||||
<item name="config_appTransitionAnimationDurationScaleDefault" format="float" type="dimen">1.0</item>
|
||||
|
||||
<!-- Flag indicates that whether non-system apps can be installed on internal storage. -->
|
||||
<bool name="config_allow3rdPartyAppOnInternal">true</bool>
|
||||
</resources>
|
||||
|
||||
@@ -2753,6 +2753,9 @@
|
||||
|
||||
<java-symbol type="dimen" name="config_appTransitionAnimationDurationScaleDefault" />
|
||||
|
||||
<!-- Network Recommendation -->
|
||||
<!-- Network Recommendation -->
|
||||
<java-symbol type="array" name="config_networkRecommendationPackageNames" />
|
||||
|
||||
<!-- Whether allow 3rd party apps on internal storage. -->
|
||||
<java-symbol type="bool" name="config_allow3rdPartyAppOnInternal" />
|
||||
</resources>
|
||||
|
||||
@@ -16,17 +16,28 @@
|
||||
|
||||
package android.content.pm;
|
||||
|
||||
import static android.net.TrafficStats.MB_IN_BYTES;
|
||||
|
||||
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 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";
|
||||
@@ -35,6 +46,94 @@ public class PackageHelperTests extends AndroidTestCase {
|
||||
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 final StorageManager sStorageManager = createStorageManagerMock();
|
||||
|
||||
private static StorageManager createStorageManagerMock() {
|
||||
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);
|
||||
Mockito.when(storageManager.getStorageBytesUntilLow(internalFile)).thenReturn(sInternalSize);
|
||||
Mockito.when(storageManager.getStorageBytesUntilLow(adoptedFile)).thenReturn(sAdoptedSize);
|
||||
Mockito.when(storageManager.getStorageBytesUntilLow(publicFile)).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) {
|
||||
@@ -131,4 +230,328 @@ public class PackageHelperTests extends AndroidTestCase {
|
||||
};
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user