From 14b6abda1309631d49d4bebbb0317a7e1dfc0a50 Mon Sep 17 00:00:00 2001 From: Suchi Amalapurapu Date: Wed, 17 Mar 2010 08:37:04 -0700 Subject: Add new install flag to install on internal flash only Change default install location policy for new flag. New error code for media unavailable. Change-Id: I5a5d0828b067692b2b94a15a2bcc7534f796c1a2 --- cmds/pm/src/com/android/commands/pm/Pm.java | 6 +- core/java/android/content/pm/PackageManager.java | 7 + .../internal/app/IMediaContainerService.aidl | 2 +- .../defcontainer/DefaultContainerService.java | 151 +++-- .../com/android/server/PackageManagerService.java | 26 +- .../android/unit_tests/PackageManagerTests.java | 676 +++++++++++++++++++-- 6 files changed, 743 insertions(+), 125 deletions(-) diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index fc5707d..cfc2e75 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -602,6 +602,9 @@ public final class Pm { } else if (opt.equals("-s")) { // Override if -s option is specified. installFlags |= PackageManager.INSTALL_EXTERNAL; + } else if (opt.equals("-f")) { + // Override if -s option is specified. + installFlags |= PackageManager.INSTALL_INTERNAL; } else { System.err.println("Error: Unknown option: " + opt); showUsage(); @@ -861,7 +864,7 @@ public final class Pm { System.err.println(" pm list instrumentation [-f] [TARGET-PACKAGE]"); System.err.println(" pm list features"); System.err.println(" pm path PACKAGE"); - System.err.println(" pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] PATH"); + System.err.println(" pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] [-f] PATH"); System.err.println(" pm uninstall [-k] PACKAGE"); System.err.println(" pm mountsd [-m true/false]"); System.err.println(" pm enable PACKAGE_OR_COMPONENT"); @@ -895,6 +898,7 @@ public final class Pm { System.err.println(" -t: allow test .apks to be installed."); System.err.println(" -i: specify the installer package name."); System.err.println(" -s: install package on sdcard."); + System.err.println(" -f: install package on internal flash."); System.err.println(""); System.err.println("The uninstall command removes a package from the system. Options:"); System.err.println(" -k: keep the data and cache directories around."); diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index e1fbe48..bbf4ca1 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -261,6 +261,13 @@ public abstract class PackageManager { public static final int INSTALL_EXTERNAL = 0x00000008; /** + * Flag parameter for {@link #installPackage} to indicate that this + * package has to be installed on the sdcard. + * @hide + */ + public static final int INSTALL_INTERNAL = 0x00000010; + + /** * Flag parameter for * {@link #setComponentEnabledSetting(android.content.ComponentName, int, int)} to indicate * that you don't want to kill the app containing the component. Be careful when you set this diff --git a/core/java/com/android/internal/app/IMediaContainerService.aidl b/core/java/com/android/internal/app/IMediaContainerService.aidl index badabb0..0f817b7 100755 --- a/core/java/com/android/internal/app/IMediaContainerService.aidl +++ b/core/java/com/android/internal/app/IMediaContainerService.aidl @@ -26,6 +26,6 @@ interface IMediaContainerService { String key, String resFileName); boolean copyResource(in Uri packageURI, in ParcelFileDescriptor outStream); - PackageInfoLite getMinimalPackageInfo(in Uri fileUri); + PackageInfoLite getMinimalPackageInfo(in Uri fileUri, int flags); boolean checkFreeStorage(boolean external, in Uri fileUri); } \ No newline at end of file diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java index 77d11cc..14c8806 100644 --- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java +++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java @@ -105,7 +105,7 @@ public class DefaultContainerService extends IntentService { * @return Returns PackageInfoLite object containing * the package info and recommended app location. */ - public PackageInfoLite getMinimalPackageInfo(final Uri fileUri) { + public PackageInfoLite getMinimalPackageInfo(final Uri fileUri, int flags) { PackageInfoLite ret = new PackageInfoLite(); if (fileUri == null) { Log.i(TAG, "Invalid package uri " + fileUri); @@ -136,7 +136,7 @@ public class DefaultContainerService extends IntentService { return ret; } ret.packageName = pkg.packageName; - ret.recommendedInstallLocation = recommendAppInstallLocation(pkg.installLocation, archiveFilePath); + ret.recommendedInstallLocation = recommendAppInstallLocation(pkg.installLocation, archiveFilePath, flags); return ret; } @@ -305,8 +305,65 @@ public class DefaultContainerService extends IntentService { private static final int ERR_LOC = -1; private int recommendAppInstallLocation(int installLocation, - String archiveFilePath) { - // Initial implementation: + String archiveFilePath, int flags) { + boolean checkInt = false; + boolean checkExt = false; + boolean checkBoth = false; + check_inner : { + // Check flags. + if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) { + // Check for forward locked app + checkInt = true; + break check_inner; + } else if ((flags & PackageManager.INSTALL_INTERNAL) != 0) { + // Explicit flag to install internally. + // Check internal storage and return + checkInt = true; + break check_inner; + } else if ((flags & PackageManager.INSTALL_EXTERNAL) != 0) { + // Explicit flag to install externally. + // Check external storage and return + checkExt = true; + break check_inner; + } + // Check for manifest option + if (installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) { + checkInt = true; + break check_inner; + } else if (installLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL) { + checkExt = true; + checkBoth = true; + break check_inner; + } else if (installLocation == PackageInfo.INSTALL_LOCATION_AUTO) { + checkInt = true; + checkBoth = true; + break check_inner; + } + // Check if user option is enabled + boolean setInstallLoc = Settings.System.getInt(getApplicationContext() + .getContentResolver(), + Settings.System.SET_INSTALL_LOCATION, 0) != 0; + if (setInstallLoc) { + // Pick user preference + int installPreference = Settings.System.getInt(getApplicationContext() + .getContentResolver(), + Settings.System.DEFAULT_INSTALL_LOCATION, + PackageHelper.APP_INSTALL_AUTO); + if (installPreference == PackageHelper.APP_INSTALL_INTERNAL) { + checkInt = true; + checkBoth = true; + break check_inner; + } else if (installPreference == PackageHelper.APP_INSTALL_EXTERNAL) { + checkExt = true; + checkBoth = true; + break check_inner; + } + } + // Fall back to default policy if nothing else is specified. + checkInt = true; + checkBoth = true; + } + // Package size = code size + cache size + data size // If code size > 1 MB, install on SD card. // Else install on internal NAND flash, unless space on NAND is less than 10% @@ -330,77 +387,47 @@ public class DefaultContainerService extends IntentService { File apkFile = new File(archiveFilePath); long pkgLen = apkFile.length(); - - boolean auto = true; + // To make final copy long reqInstallSize = pkgLen; // For dex files. Just ignore and fail when extracting. Max limit of 2Gig for now. long reqInternalSize = 0; boolean intThresholdOk = (pctNandFree >= LOW_NAND_FLASH_TRESHOLD); boolean intAvailOk = ((reqInstallSize + reqInternalSize) < availInternalSize); - boolean fitsOnSd = mediaAvailable && (reqInstallSize < availSDSize) - && intThresholdOk && - (reqInternalSize < availInternalSize); + boolean fitsOnSd = false; + if (mediaAvailable && (reqInstallSize < availSDSize)) { + // If we do not have an internal size requirement + // don't do a threshold check. + if (reqInternalSize == 0) { + fitsOnSd = true; + } else if ((reqInternalSize < availInternalSize) && intThresholdOk) { + fitsOnSd = true; + } + } boolean fitsOnInt = intThresholdOk && intAvailOk; - - // Consider application flags preferences as well... - boolean installOnlyOnSd = (installLocation == - PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL); - boolean installOnlyInternal = (installLocation == - PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY); - if (installOnlyInternal) { - // If set explicitly in manifest, - // let that override everything else - auto = false; - } else if (installOnlyOnSd){ - // Check if this can be accommodated on the sdcard - if (fitsOnSd) { - auto = false; + if (checkInt) { + // Check for internal memory availability + if (fitsOnInt) { + return PackageHelper.RECOMMEND_INSTALL_INTERNAL; } - } else { - // Check if user option is enabled - boolean setInstallLoc = Settings.System.getInt(getApplicationContext() - .getContentResolver(), - Settings.System.SET_INSTALL_LOCATION, 0) != 0; - if (setInstallLoc) { - // Pick user preference - int installPreference = Settings.System.getInt(getApplicationContext() - .getContentResolver(), - Settings.System.DEFAULT_INSTALL_LOCATION, - PackageHelper.APP_INSTALL_AUTO); - if (installPreference == PackageHelper.APP_INSTALL_INTERNAL) { - installOnlyInternal = true; - auto = false; - } else if (installPreference == PackageHelper.APP_INSTALL_EXTERNAL) { - installOnlyOnSd = true; - auto = false; - } + } else if (checkExt) { + if (fitsOnSd) { + return PackageHelper.RECOMMEND_INSTALL_EXTERNAL; } } - if (!auto) { - if (installOnlyOnSd) { - if (fitsOnSd) { - return PackageHelper.RECOMMEND_INSTALL_EXTERNAL; - } - if (!mediaAvailable) { - return PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE; - } - return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE; - } else if (installOnlyInternal){ - // Check on internal flash - return fitsOnInt ? PackageHelper.RECOMMEND_INSTALL_INTERNAL : - PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE; + if (checkBoth) { + // Check for internal first + if (fitsOnInt) { + return PackageHelper.RECOMMEND_INSTALL_INTERNAL; + } + // Check for external next + if (fitsOnSd) { + return PackageHelper.RECOMMEND_INSTALL_EXTERNAL; } } - // Try to install internally - if (fitsOnInt) { - return PackageHelper.RECOMMEND_INSTALL_INTERNAL; - } - // Try the sdcard now. - if (fitsOnSd) { - return PackageHelper.RECOMMEND_INSTALL_EXTERNAL; + if (checkExt || checkBoth && !mediaAvailable) { + return PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE; } - // Return error code return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE; } diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index 818e99e..55725bd 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -595,10 +595,13 @@ class PackageManagerService extends IPackageManager.Stub { static boolean installOnSd(int flags) { if (((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) || - ((flags & PackageManager.INSTALL_EXTERNAL) == 0)) { + ((flags & PackageManager.INSTALL_INTERNAL) != 0)) { return false; } - return true; + if ((flags & PackageManager.INSTALL_EXTERNAL) != 0) { + return true; + } + return false; } static boolean isFwdLocked(int flags) { @@ -4452,8 +4455,8 @@ class PackageManagerService extends IPackageManager.Stub { res.uid = -1; res.pkg = null; res.removedInfo = new PackageRemovedInfo(); - args.doPreInstall(res.returnCode); if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) { + args.doPreInstall(res.returnCode); synchronized (mInstallLock) { installPackageLI(args, true, res); } @@ -4623,13 +4626,18 @@ class PackageManagerService extends IPackageManager.Stub { int ret = PackageManager.INSTALL_SUCCEEDED; boolean fwdLocked = (flags & PackageManager.INSTALL_FORWARD_LOCK) != 0; boolean onSd = (flags & PackageManager.INSTALL_EXTERNAL) != 0; - // Dont need to invoke getInstallLocation for forward locked apps. - if (fwdLocked && onSd) { + boolean onInt = (flags & PackageManager.INSTALL_INTERNAL) != 0; + if (onInt && onSd) { + // Check if both bits are set. + Slog.w(TAG, "Conflicting flags specified for installing on both internal and external"); + ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION; + } else if (fwdLocked && onSd) { + // Check for forward locked apps Slog.w(TAG, "Cannot install fwd locked apps on sdcard"); ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION; } else { // Remote call to find out default install location - PackageInfoLite pkgLite = mContainerService.getMinimalPackageInfo(packageURI); + PackageInfoLite pkgLite = mContainerService.getMinimalPackageInfo(packageURI, flags); int loc = pkgLite.recommendedInstallLocation; if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION){ ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION; @@ -4644,14 +4652,16 @@ class PackageManagerService extends IPackageManager.Stub { } else { // Override with defaults if needed. loc = installLocationPolicy(pkgLite, flags); - // Override install location with flags - if ((flags & PackageManager.INSTALL_EXTERNAL) == 0){ + if (!onSd && !onInt) { + // Override install location with flags if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) { // Set the flag to install on external media. flags |= PackageManager.INSTALL_EXTERNAL; + flags &= ~PackageManager.INSTALL_INTERNAL; } else { // Make sure the flag for installing on external // media is unset + flags |= PackageManager.INSTALL_INTERNAL; flags &= ~PackageManager.INSTALL_EXTERNAL; } } diff --git a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java index a06a13b..b988920 100755 --- a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java +++ b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java @@ -78,6 +78,7 @@ public class PackageManagerTests extends AndroidTestCase { private static final int APP_INSTALL_AUTO = PackageHelper.APP_INSTALL_AUTO; private static final int APP_INSTALL_DEVICE = PackageHelper.APP_INSTALL_INTERNAL; private static final int APP_INSTALL_SDCARD = PackageHelper.APP_INSTALL_EXTERNAL; + private boolean mOrigState; void failStr(String errMsg) { Log.w(TAG, "errMsg="+errMsg); @@ -91,6 +92,21 @@ public class PackageManagerTests extends AndroidTestCase { @Override protected void setUp() throws Exception { super.setUp(); + mOrigState = getMediaState(); + } + + @Override + protected void tearDown() throws Exception { + // Restore media state. + boolean newState = getMediaState(); + if (newState != mOrigState) { + if (mOrigState) { + getMs().mountVolume(Environment.getExternalStorageDirectory().getPath()); + } else { + getMs().unmountVolume(Environment.getExternalStorageDirectory().getPath(), true); + } + } + super.tearDown(); } private class PackageInstallObserver extends IPackageInstallObserver.Stub { @@ -254,21 +270,70 @@ public class PackageManagerTests extends AndroidTestCase { packageParser = null; return pkg; } - private boolean getInstallLoc(int flags, int expInstallLocation) { + private boolean checkSd(long pkgLen) { + String status = Environment.getExternalStorageState(); + if (!status.equals(Environment.MEDIA_MOUNTED)) { + return false; + } + long sdSize = -1; + StatFs sdStats = new StatFs( + Environment.getExternalStorageDirectory().getPath()); + sdSize = (long)sdStats.getAvailableBlocks() * + (long)sdStats.getBlockSize(); + // TODO check for thesholds here + return pkgLen <= sdSize; + + } + private boolean checkInt(long pkgLen) { + StatFs intStats = new StatFs(Environment.getDataDirectory().getPath()); + long intSize = (long)intStats.getBlockCount() * + (long)intStats.getBlockSize(); + long iSize = (long)intStats.getAvailableBlocks() * + (long)intStats.getBlockSize(); + // TODO check for thresholds here? + return pkgLen <= iSize; + } + private static final int INSTALL_LOC_INT = 1; + private static final int INSTALL_LOC_SD = 2; + private static final int INSTALL_LOC_ERR = -1; + private int getInstallLoc(int flags, int expInstallLocation, long pkgLen) { // Flags explicitly over ride everything else. if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0 ) { - return false; + return INSTALL_LOC_INT; } else if ((flags & PackageManager.INSTALL_EXTERNAL) != 0 ) { - return true; + return INSTALL_LOC_SD; + } else if ((flags & PackageManager.INSTALL_INTERNAL) != 0) { + return INSTALL_LOC_INT; } // Manifest option takes precedence next if (expInstallLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL) { - return true; + // TODO fitsonSd check + if (checkSd(pkgLen)) { + return INSTALL_LOC_SD; + } + if (checkInt(pkgLen)) { + return INSTALL_LOC_INT; + } + return INSTALL_LOC_ERR; } if (expInstallLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) { - return false; + if (checkInt(pkgLen)) { + return INSTALL_LOC_INT; + } + return INSTALL_LOC_ERR; } - // TODO Out of memory checks here. + if (expInstallLocation == PackageInfo.INSTALL_LOCATION_AUTO) { + // Check for free memory internally + if (checkInt(pkgLen)) { + return INSTALL_LOC_INT; + } + // Check for free memory externally + if (checkSd(pkgLen)) { + return INSTALL_LOC_SD; + } + return INSTALL_LOC_ERR; + } + // Check for settings preference. boolean checkSd = false; int setLoc = 0; try { @@ -284,46 +349,63 @@ public class PackageManagerTests extends AndroidTestCase { failStr(e); } if (userPref == APP_INSTALL_DEVICE) { - checkSd = false; + if (checkInt(pkgLen)) { + return INSTALL_LOC_INT; + } + return INSTALL_LOC_ERR; } else if (userPref == APP_INSTALL_SDCARD) { - checkSd = true; + if (checkSd(pkgLen)) { + return INSTALL_LOC_SD; + } + return INSTALL_LOC_ERR; } else if (userPref == APP_INSTALL_AUTO) { - // Might be determined dynamically. TODO fix this - checkSd = false; + if (checkInt(pkgLen)) { + return INSTALL_LOC_INT; + } + // Check for free memory externally + if (checkSd(pkgLen)) { + return INSTALL_LOC_SD; + } + return INSTALL_LOC_ERR; + } - } - return checkSd; + } + return INSTALL_LOC_ERR; } private void assertInstall(PackageParser.Package pkg, int flags, int expInstallLocation) { try { String pkgName = pkg.packageName; - ApplicationInfo info = getPm().getApplicationInfo(pkgName, 0); - assertNotNull(info); - assertEquals(pkgName, info.packageName); - File dataDir = Environment.getDataDirectory(); - String appInstallPath = new File(dataDir, "app").getPath(); - String drmInstallPath = new File(dataDir, "app-private").getPath(); - File srcDir = new File(info.sourceDir); - String srcPath = srcDir.getParent(); - File publicSrcDir = new File(info.publicSourceDir); - String publicSrcPath = publicSrcDir.getParent(); - - if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) { - assertTrue((info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0); - assertEquals(srcPath, drmInstallPath); - assertEquals(publicSrcPath, appInstallPath); - } else { - assertFalse((info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0); - if (!getInstallLoc(flags, expInstallLocation)) { - assertEquals(srcPath, appInstallPath); + ApplicationInfo info = getPm().getApplicationInfo(pkgName, 0); + assertNotNull(info); + assertEquals(pkgName, info.packageName); + File dataDir = Environment.getDataDirectory(); + String appInstallPath = new File(dataDir, "app").getPath(); + String drmInstallPath = new File(dataDir, "app-private").getPath(); + File srcDir = new File(info.sourceDir); + String srcPath = srcDir.getParent(); + File publicSrcDir = new File(info.publicSourceDir); + String publicSrcPath = publicSrcDir.getParent(); + long pkgLen = new File(info.sourceDir).length(); + + if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) { + assertTrue((info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0); + assertEquals(srcPath, drmInstallPath); assertEquals(publicSrcPath, appInstallPath); - assertFalse((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0); } else { - assertTrue((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0); - assertTrue(srcPath.startsWith(SECURE_CONTAINERS_PREFIX)); - assertTrue(publicSrcPath.startsWith(SECURE_CONTAINERS_PREFIX)); + assertFalse((info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0); + int rLoc = getInstallLoc(flags, expInstallLocation, pkgLen); + if (rLoc == INSTALL_LOC_INT) { + assertEquals(srcPath, appInstallPath); + assertEquals(publicSrcPath, appInstallPath); + assertFalse((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0); + } else if (rLoc == INSTALL_LOC_SD){ + assertTrue((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0); + assertTrue(srcPath.startsWith(SECURE_CONTAINERS_PREFIX)); + assertTrue(publicSrcPath.startsWith(SECURE_CONTAINERS_PREFIX)); + } else { + // TODO handle error. Install should have failed. + } } - } } catch (NameNotFoundException e) { failStr("failed with exception : " + e); } @@ -396,8 +478,6 @@ public class PackageManagerTests extends AndroidTestCase { } catch (Exception e) { failStr(e); } - // Clean up the containers as well - clearSecureContainersForPkg(pkg.packageName); } InstallParams ip = null; try { @@ -1047,19 +1127,6 @@ public class PackageManagerTests extends AndroidTestCase { } } - public void xxxtestClearAllSecureContainers() { - IMountService ms = getMs(); - try { - String list[] = ms.getSecureContainerList(); - if (list != null) { - for (String cid : list) { - Log.i(TAG, "Destroying container " + cid); - ms.destroySecureContainer(cid, false); - } - } - } catch (RemoteException e) {} - } - class MoveReceiver extends GenericReceiver { String pkgName; final static int INVALID = -1; @@ -1185,7 +1252,7 @@ public class PackageManagerTests extends AndroidTestCase { public void moveFromRawResource(int installFlags, int moveFlags, int expRetCode) { int origDefaultLoc = getInstallLoc(); - setInstallLoc(PackageInfo.INSTALL_LOCATION_AUTO); + setInstallLoc(PackageHelper.APP_INSTALL_AUTO); // Install first InstallParams ip = sampleInstallFromRawResource(installFlags, false); ApplicationInfo oldAppInfo = null; @@ -1255,7 +1322,7 @@ public class PackageManagerTests extends AndroidTestCase { // Try to install and make sure an error code is returned. assertNull(installFromRawResource("install.apk", R.raw.install, PackageManager.INSTALL_EXTERNAL, false, - true, PackageManager.INSTALL_FAILED_CONTAINER_ERROR, + true, PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE, PackageInfo.INSTALL_LOCATION_AUTO)); } finally { // Restore original media state @@ -1292,6 +1359,509 @@ public class PackageManagerTests extends AndroidTestCase { } /*---------- Recommended install location tests ----*/ + /* Precedence: FlagManifestExistingUser + * PrecedenceSuffixes: + * Flag : FlagI, FlagE, FlagF + * I - internal, E - external, F - forward locked, Flag suffix absent if not using any option. + * Manifest: ManifestI, ManifestE, ManifestA, Manifest suffix absent if not using any option. + * Existing: Existing suffix absent if not existing. + * User: UserI, UserE, UserA, User suffix absent if not existing. + * + */ + /* + * Install an app on internal flash + */ + public void testFlagI() { + sampleInstallFromRawResource(PackageManager.INSTALL_INTERNAL, true); + } + /* + * Install an app on sdcard. + */ + public void testFlagE() { + sampleInstallFromRawResource(PackageManager.INSTALL_EXTERNAL, true); + } + + /* + * Install an app on sdcard. + */ + public void testFlagF() { + sampleInstallFromRawResource(PackageManager.INSTALL_FORWARD_LOCK, true); + } + /* + * Install an app with both internal and external flags set. should fail + */ + public void testFlagIE() { + installFromRawResource("install.apk", R.raw.install, + PackageManager.INSTALL_EXTERNAL | PackageManager.INSTALL_INTERNAL, + false, + true, PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION, + PackageInfo.INSTALL_LOCATION_AUTO); + } + + /* + * Install an app with both internal and external flags set. should fail + */ + public void testFlagIF() { + sampleInstallFromRawResource(PackageManager.INSTALL_FORWARD_LOCK | + PackageManager.INSTALL_INTERNAL, true); + } + /* + * Install an app with both internal and external flags set. should fail + */ + public void testFlagEF() { + installFromRawResource("install.apk", R.raw.install, + PackageManager.INSTALL_FORWARD_LOCK | PackageManager.INSTALL_EXTERNAL, + false, + true, PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION, + PackageInfo.INSTALL_LOCATION_AUTO); + } + /* + * Install an app with both internal and external flags set. should fail + */ + public void testFlagIEF() { + installFromRawResource("install.apk", R.raw.install, + PackageManager.INSTALL_FORWARD_LOCK | PackageManager.INSTALL_INTERNAL | + PackageManager.INSTALL_EXTERNAL, + false, + true, PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION, + PackageInfo.INSTALL_LOCATION_AUTO); + } + /* + * Install an app with both internal and manifest option set. + * should install on internal. + */ + public void testFlagIManifestI() { + installFromRawResource("install.apk", R.raw.install_loc_internal, + PackageManager.INSTALL_INTERNAL, + true, + false, -1, + PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY); + } + /* + * Install an app with both internal and manifest preference for + * preferExternal. Should install on internal. + */ + public void testFlagIManifestE() { + installFromRawResource("install.apk", R.raw.install_loc_sdcard, + PackageManager.INSTALL_INTERNAL, + true, + false, -1, + PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY); + } + /* + * Install an app with both internal and manifest preference for + * auto. should install internal. + */ + public void testFlagIManifestA() { + installFromRawResource("install.apk", R.raw.install_loc_auto, + PackageManager.INSTALL_INTERNAL, + true, + false, -1, + PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY); + } + /* + * Install an app with both external and manifest option set. + * should install externally. + */ + public void testFlagEManifestI() { + installFromRawResource("install.apk", R.raw.install_loc_internal, + PackageManager.INSTALL_EXTERNAL, + true, + false, -1, + PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL); + } + /* + * Install an app with both external and manifest preference for + * preferExternal. Should install externally. + */ + public void testFlagEManifestE() { + installFromRawResource("install.apk", R.raw.install_loc_sdcard, + PackageManager.INSTALL_EXTERNAL, + true, + false, -1, + PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL); + } + /* + * Install an app with both external and manifest preference for + * auto. should install on external media. + */ + public void testFlagEManifestA() { + installFromRawResource("install.apk", R.raw.install_loc_auto, + PackageManager.INSTALL_EXTERNAL, + true, + false, -1, + PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL); + } + /* + * Install an app with fwd locked flag set and install location set to + * internal. should install internally. + */ + public void testFlagFManifestI() { + installFromRawResource("install.apk", R.raw.install_loc_internal, + PackageManager.INSTALL_EXTERNAL, + true, + false, -1, + PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL); + } + /* + * Install an app with fwd locked flag set and install location set to + * preferExternal. should install internally. + */ + public void testFlagFManifestE() { + installFromRawResource("install.apk", R.raw.install_loc_sdcard, + PackageManager.INSTALL_EXTERNAL, + true, + false, -1, + PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL); + } + /* + * Install an app with fwd locked flag set and install location set to + * auto. should install internally. + */ + public void testFlagFManifestA() { + installFromRawResource("install.apk", R.raw.install_loc_auto, + PackageManager.INSTALL_EXTERNAL, + true, + false, -1, + PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL); + } + /* The following test functions verify install location for existing apps. + * ie existing app can be installed internally or externally. If install + * flag is explicitly set it should override current location. If manifest location + * is set, that should over ride current location too. if not the existing install + * location should be honoured. + * testFlagI/E/F/ExistingI/E - + */ + public void testFlagIExistingI() { + int iFlags = PackageManager.INSTALL_INTERNAL; + int rFlags = PackageManager.INSTALL_INTERNAL | PackageManager.INSTALL_REPLACE_EXISTING; + // First install. + installFromRawResource("install.apk", R.raw.install, + iFlags, + false, + false, -1, + -1); + // Replace now + installFromRawResource("install.apk", R.raw.install, + rFlags, + true, + false, -1, + -1); + } + public void testFlagIExistingE() { + int iFlags = PackageManager.INSTALL_EXTERNAL; + int rFlags = PackageManager.INSTALL_INTERNAL | PackageManager.INSTALL_REPLACE_EXISTING; + // First install. + installFromRawResource("install.apk", R.raw.install, + iFlags, + false, + false, -1, + -1); + // Replace now + installFromRawResource("install.apk", R.raw.install, + rFlags, + true, + false, -1, + -1); + } + public void testFlagEExistingI() { + int iFlags = PackageManager.INSTALL_INTERNAL; + int rFlags = PackageManager.INSTALL_EXTERNAL | PackageManager.INSTALL_REPLACE_EXISTING; + // First install. + installFromRawResource("install.apk", R.raw.install, + iFlags, + false, + false, -1, + -1); + // Replace now + installFromRawResource("install.apk", R.raw.install, + rFlags, + true, + false, -1, + -1); + } + public void testFlagEExistingE() { + int iFlags = PackageManager.INSTALL_EXTERNAL; + int rFlags = PackageManager.INSTALL_EXTERNAL | PackageManager.INSTALL_REPLACE_EXISTING; + // First install. + installFromRawResource("install.apk", R.raw.install, + iFlags, + false, + false, -1, + -1); + // Replace now + installFromRawResource("install.apk", R.raw.install, + rFlags, + true, + false, -1, + -1); + } + public void testFlagFExistingI() { + int iFlags = PackageManager.INSTALL_INTERNAL; + int rFlags = PackageManager.INSTALL_FORWARD_LOCK | PackageManager.INSTALL_REPLACE_EXISTING; + // First install. + installFromRawResource("install.apk", R.raw.install, + iFlags, + false, + false, -1, + -1); + // Replace now + installFromRawResource("install.apk", R.raw.install, + rFlags, + true, + false, -1, + -1); + } + public void testFlagFExistingE() { + int iFlags = PackageManager.INSTALL_EXTERNAL; + int rFlags = PackageManager.INSTALL_FORWARD_LOCK | PackageManager.INSTALL_REPLACE_EXISTING; + // First install. + installFromRawResource("install.apk", R.raw.install, + iFlags, + false, + false, -1, + -1); + // Replace now + installFromRawResource("install.apk", R.raw.install, + rFlags, + true, + false, -1, + -1); + } + /* + * The following set of tests verify the installation of apps with + * install location attribute set to internalOnly, preferExternal and auto. + * The manifest option should dictate the install location. + * public void testManifestI/E/A + * TODO out of memory fall back behaviour. + */ + public void testManifestI() { + installFromRawResource("install.apk", R.raw.install_loc_internal, + 0, + true, + false, -1, + PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY); + } + public void testManifestE() { + installFromRawResource("install.apk", R.raw.install_loc_sdcard, + 0, + true, + false, -1, + PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL); + } + public void testManifestA() { + installFromRawResource("install.apk", R.raw.install_loc_auto, + 0, + true, + false, -1, + PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY); + } + /* + * The following set of tests verify the installation of apps + * with install location attribute set to internalOnly, preferExternal and auto + * for already existing apps. The manifest option should take precedence. + * TODO add out of memory fall back behaviour. + * testManifestI/E/AExistingI/E + */ + public void testManifestIExistingI() { + int iFlags = PackageManager.INSTALL_INTERNAL; + int rFlags = PackageManager.INSTALL_REPLACE_EXISTING; + // First install. + installFromRawResource("install.apk", R.raw.install, + iFlags, + false, + false, -1, + -1); + // Replace now + installFromRawResource("install.apk", R.raw.install_loc_internal, + rFlags, + true, + false, -1, + PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY); + } + public void testManifestIExistingE() { + int iFlags = PackageManager.INSTALL_EXTERNAL; + int rFlags = PackageManager.INSTALL_REPLACE_EXISTING; + // First install. + installFromRawResource("install.apk", R.raw.install, + iFlags, + false, + false, -1, + -1); + // Replace now + installFromRawResource("install.apk", R.raw.install_loc_internal, + rFlags, + true, + false, -1, + PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY); + } + public void testManifestEExistingI() { + int iFlags = PackageManager.INSTALL_INTERNAL; + int rFlags = PackageManager.INSTALL_REPLACE_EXISTING; + // First install. + installFromRawResource("install.apk", R.raw.install, + iFlags, + false, + false, -1, + -1); + // Replace now + installFromRawResource("install.apk", R.raw.install_loc_sdcard, + rFlags, + true, + false, -1, + PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL); + } + public void testManifestEExistingE() { + int iFlags = PackageManager.INSTALL_EXTERNAL; + int rFlags = PackageManager.INSTALL_REPLACE_EXISTING; + // First install. + installFromRawResource("install.apk", R.raw.install, + iFlags, + false, + false, -1, + -1); + // Replace now + installFromRawResource("install.apk", R.raw.install_loc_sdcard, + rFlags, + true, + false, -1, + PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL); + } + public void testManifestAExistingI() { + int iFlags = PackageManager.INSTALL_INTERNAL; + int rFlags = PackageManager.INSTALL_REPLACE_EXISTING; + // First install. + installFromRawResource("install.apk", R.raw.install, + iFlags, + false, + false, -1, + -1); + // Replace now + installFromRawResource("install.apk", R.raw.install_loc_auto, + rFlags, + true, + false, -1, + PackageInfo.INSTALL_LOCATION_AUTO); + } + public void testManifestAExistingE() { + int iFlags = PackageManager.INSTALL_EXTERNAL; + int rFlags = PackageManager.INSTALL_REPLACE_EXISTING; + // First install. + installFromRawResource("install.apk", R.raw.install, + iFlags, + false, + false, -1, + -1); + // Replace now + installFromRawResource("install.apk", R.raw.install_loc_auto, + rFlags, + true, + false, -1, + PackageInfo.INSTALL_LOCATION_AUTO); + } + /* + * The following set of tests check install location for existing + * application based on user setting. + */ + private void setExistingXUserX(int userSetting, int iFlags) { + int rFlags = PackageManager.INSTALL_REPLACE_EXISTING; + // First install. + installFromRawResource("install.apk", R.raw.install, + iFlags, + false, + false, -1, + -1); + // Watch out for this. + int iloc = PackageInfo.INSTALL_LOCATION_AUTO; + if ((iFlags & PackageManager.INSTALL_INTERNAL) != 0) { + iloc = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY; + } else if ((iFlags & PackageManager.INSTALL_EXTERNAL) != 0) { + iloc = PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL; + } + int origSetting = getInstallLoc(); + try { + // Set user setting + setInstallLoc(userSetting); + // Replace now + installFromRawResource("install.apk", R.raw.install, + rFlags, + true, + false, -1, + iloc); + } finally { + setInstallLoc(origSetting); + } + } + public void testExistingIUserI() { + int userSetting = PackageHelper.APP_INSTALL_INTERNAL; + int iFlags = PackageManager.INSTALL_INTERNAL; + setExistingXUserX(userSetting, iFlags); + } + public void testExistingIUserE() { + int userSetting = PackageHelper.APP_INSTALL_EXTERNAL; + int iFlags = PackageManager.INSTALL_INTERNAL; + setExistingXUserX(userSetting, iFlags); + } + public void testExistingIUserA() { + int userSetting = PackageHelper.APP_INSTALL_AUTO; + int iFlags = PackageManager.INSTALL_INTERNAL; + setExistingXUserX(userSetting, iFlags); + } + public void testExistingEUserI() { + int userSetting = PackageHelper.APP_INSTALL_INTERNAL; + int iFlags = PackageManager.INSTALL_EXTERNAL; + setExistingXUserX(userSetting, iFlags); + } + public void testExistingEUserE() { + int userSetting = PackageHelper.APP_INSTALL_EXTERNAL; + int iFlags = PackageManager.INSTALL_EXTERNAL; + setExistingXUserX(userSetting, iFlags); + } + public void testExistingEUserA() { + int userSetting = PackageHelper.APP_INSTALL_AUTO; + int iFlags = PackageManager.INSTALL_EXTERNAL; + setExistingXUserX(userSetting, iFlags); + } + /* + * The following set of tests verify that the user setting defines + * the install location. + * + */ + private void setUserX(int userSetting) { + int origSetting = getInstallLoc(); + int iloc = PackageInfo.INSTALL_LOCATION_AUTO; + if (userSetting == PackageHelper.APP_INSTALL_AUTO) { + iloc = PackageInfo.INSTALL_LOCATION_AUTO; + } else if (userSetting == PackageHelper.APP_INSTALL_EXTERNAL) { + iloc = PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL; + } else if (userSetting == PackageHelper.APP_INSTALL_INTERNAL) { + iloc = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY; + } + try { + // Set user setting + setInstallLoc(userSetting); + // Replace now + installFromRawResource("install.apk", R.raw.install, + 0, + true, + false, -1, + iloc); + } finally { + setInstallLoc(origSetting); + } + } + public void testUserI() { + int userSetting = PackageHelper.APP_INSTALL_INTERNAL; + setUserX(userSetting); + } + public void testUserE() { + int userSetting = PackageHelper.APP_INSTALL_EXTERNAL; + setUserX(userSetting); + } + public void testUserA() { + int userSetting = PackageHelper.APP_INSTALL_AUTO; + setUserX(userSetting); + } /* * TODO's * check version numbers for upgrades -- cgit v1.1