diff options
-rw-r--r-- | core/java/android/app/ApplicationContext.java | 72 | ||||
-rw-r--r-- | core/java/android/content/pm/PackageManager.java | 94 | ||||
-rw-r--r-- | test-runner/android/test/mock/MockPackageManager.java | 8 |
3 files changed, 97 insertions, 77 deletions
diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java index fe05393..6c65bd8 100644 --- a/core/java/android/app/ApplicationContext.java +++ b/core/java/android/app/ApplicationContext.java @@ -71,6 +71,7 @@ import android.net.wifi.WifiManager; import android.os.Binder; import android.os.Bundle; import android.os.DropBoxManager; +import android.os.Environment; import android.os.FileUtils; import android.os.Handler; import android.os.IBinder; @@ -80,6 +81,7 @@ import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.StatFs; import android.os.Vibrator; import android.os.FileUtils.FileStatus; import android.telephony.TelephonyManager; @@ -2537,6 +2539,76 @@ class ApplicationContext extends Context { return PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; } + // Constants related to app heuristics + // No-installation limit for internal flash: 10% or less space available + private static final double LOW_NAND_FLASH_TRESHOLD = 0.1; + + // SD-to-internal app size threshold: currently set to 1 MB + private static final long INSTALL_ON_SD_THRESHOLD = (1024 * 1024); + + @Override + public int recommendAppInstallLocation(ApplicationInfo appInfo, Uri packageURI) { + // Initial implementation: + // 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% + + if ((packageURI == null) || (appInfo == null)) { + return INSTALL_PARSE_FAILED_NOT_APK; + } + + StatFs internalFlashStats = new StatFs(Environment.getDataDirectory().getPath()); + StatFs sdcardStats = new StatFs(Environment.getExternalStorageDirectory().getPath()); + + long totalInternalFlashSize = (long)internalFlashStats.getBlockCount() * + (long)internalFlashStats.getBlockSize(); + long availInternalFlashSize = (long)internalFlashStats.getAvailableBlocks() * + (long)internalFlashStats.getBlockSize(); + long availSDSize = (long)sdcardStats.getAvailableBlocks() * + (long)sdcardStats.getBlockSize(); + + double pctNandFree = (double)availInternalFlashSize / (double)totalInternalFlashSize; + + final String archiveFilePath = packageURI.getPath(); + File apkFile = new File(archiveFilePath); + long pkgLen = apkFile.length(); + + // Consider application flags preferences as well... + boolean installOnlyOnSD = ((appInfo.flags & PackageManager.INSTALL_ON_SDCARD) != 0); + + // These are not very precise measures, but I guess it is hard to estimate sizes + // before installing the package. + // As a shortcut, I am assuming that the package fits on NAND flash if the available + // space is three times that of the APK size. For SD, we only worry about the APK size. + // Since packages are downloaded into SD, this might not even be necessary. + boolean fitsOnSD = (pkgLen < availSDSize) && ((2 * pkgLen) < availInternalFlashSize); + boolean fitsOnInternalFlash = ((pkgLen * 3) < availInternalFlashSize); + + // Does not fit, recommend no installation. + if (!fitsOnSD && !fitsOnInternalFlash) { + return INSTALL_FAILED_INSUFFICIENT_STORAGE; + } + + if (pkgLen < (INSTALL_ON_SD_THRESHOLD) && fitsOnInternalFlash && !(installOnlyOnSD)) { + // recommend internal NAND likely + if (pctNandFree < LOW_NAND_FLASH_TRESHOLD) { + // Low space on NAND (<10%) - install on SD + return INSTALL_ON_SDCARD; + } + return INSTALL_ON_INTERNAL_FLASH; + } else { + if (fitsOnSD) { + // Recommend SD card + return INSTALL_ON_SDCARD; + } else if (fitsOnInternalFlash && (pctNandFree >= LOW_NAND_FLASH_TRESHOLD) && + !(installOnlyOnSD)) { + return INSTALL_ON_INTERNAL_FLASH; + } else { + return INSTALL_FAILED_INSUFFICIENT_STORAGE; + } + } + } + private final ApplicationContext mContext; private final IPackageManager mPM; diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index d10c8f8..1e45f17 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_ON_SDCARD = 0x00000008; /** + * Convenience flag parameter to indicate that this package has to be installed + * on internal flash. + * @hide + */ + public static final int INSTALL_ON_INTERNAL_FLASH = 0x00000000; + + /** * 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 @@ -605,89 +612,22 @@ public abstract class PackageManager { @SdkConstant(SdkConstantType.FEATURE) public static final String FEATURE_LIVE_WALLPAPER = "android.software.live_wallpaper"; - // No-installation limit for internal flash: 10% or less space available - private static final double LOW_NAND_FLASH_TRESHOLD = 0.1; - - // SD-to-internal app size threshold: currently set to 1 MB - private static final long INSTALL_ON_SD_THRESHOLD = (1024 * 1024); - - private static final int INSTALL_ON_INTERNAL_FLASH = 0; - /** * Determines best place to install an application: either SD or internal FLASH. * Tweak the algorithm for best results. - * @param tmpPackageFile APK file containing the application to install. - * @return <code>PKG_INSTALL_INTERNAL</code> if it is best to install package on internal - * storage, <code>PKG_INSTALL_ON_SD</code> if it is best to install package on SD card, - * and <code>PKG_CANNOT_FIT</code> if insufficient space to safely install the app. - * This response does not take into account the package's own flags. + * @param appInfo ApplicationInfo object og the package to install. + * Call utility method to obtain. + * @param packageURI URI identifying the package's APK file. + * @return <code>INSTALL_ON_INTERNAL_FLASH</code> if it is best to install package on internal + * storage, <code>INSTALL_ON_SDCARD</code> if it is best to install package on SD card, + * and <code>INSTALL_FAILED_INSUFFICIENT_STORAGE</code> if insufficient space to safely install + * the application. <code>INSTALL_PARSE_FAILED_NOT_APK</code> Is returned if any input + * parameter is <code>null</code>. + * This recommendation does take into account the package's own flags. * @hide */ - public static int recommendAppInstallLocation(ApplicationInfo appInfo, Uri packageURI) { - // Initial implementation: - // 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 5% - // 0 = install on internal FLASH - // 1 = install on SD card - // (-1) = insufficient space - package cannot be installed. - - if ((packageURI == null) || (appInfo == null)) { - return (-1); - } - - StatFs internalFlashStats = new StatFs(Environment.getDataDirectory().getPath()); - StatFs sdcardStats = new StatFs(Environment.getExternalStorageDirectory().getPath()); - - long totalInternalFlashSize = (long)internalFlashStats.getBlockCount() * - (long)internalFlashStats.getBlockSize(); - long availInternalFlashSize = (long)internalFlashStats.getAvailableBlocks() * - (long)internalFlashStats.getBlockSize(); - long availSDSize = (long)sdcardStats.getAvailableBlocks() * - (long)sdcardStats.getBlockSize(); + public abstract int recommendAppInstallLocation(ApplicationInfo appInfo, Uri packageURI); - double pctNandFree = (double)availInternalFlashSize / (double)totalInternalFlashSize; - - final String archiveFilePath = packageURI.getPath(); - File apkFile = new File(archiveFilePath); - long pkgLen = apkFile.length(); - - // Consider application flags preferences as well... - boolean installOnlyOnSD = ((appInfo.flags & PackageManager.INSTALL_ON_SDCARD) != 0); - - // These are not very precise measures, but I guess it is hard to estimate sizes - // before installing the package. - // As a shortcut, I am assuming that the package fits on NAND flash if the available - // space is three times that of the APK size. For SD, we only worry about the APK size. - // Since packages are downloaded into SD, this might not even be necessary. - boolean fitsOnSD = (pkgLen < availSDSize) && ((2 * pkgLen) < availInternalFlashSize); - boolean fitsOnInternalFlash = ((pkgLen * 3) < availInternalFlashSize); - - // Does not fit, recommend no installation. - if (!fitsOnSD && !fitsOnInternalFlash) { - return (-1); - } - - if (pkgLen < (INSTALL_ON_SD_THRESHOLD) && fitsOnInternalFlash && !(installOnlyOnSD)) { - // recommend internal NAND likely - if (pctNandFree < LOW_NAND_FLASH_TRESHOLD) { - // Low space on NAND (<10%) - install on SD - return INSTALL_ON_SDCARD; - } - return INSTALL_ON_INTERNAL_FLASH; - } else { - if (fitsOnSD) { - // Recommend SD card - return INSTALL_ON_SDCARD; - } else if (fitsOnInternalFlash && (pctNandFree >= LOW_NAND_FLASH_TRESHOLD) && - !(installOnlyOnSD)) { - return INSTALL_ON_INTERNAL_FLASH; - } else { - return (-1); - } - } - } - /** * Retrieve overall information about an application package that is * installed on the system. diff --git a/test-runner/android/test/mock/MockPackageManager.java b/test-runner/android/test/mock/MockPackageManager.java index 2f313af..cbe0253 100644 --- a/test-runner/android/test/mock/MockPackageManager.java +++ b/test-runner/android/test/mock/MockPackageManager.java @@ -438,4 +438,12 @@ public class MockPackageManager extends PackageManager { public boolean isSafeMode() { throw new UnsupportedOperationException(); } + + /** + * @hide + */ + @Override + public int recommendAppInstallLocation(ApplicationInfo appInfo, Uri packageURI) { + throw new UnsupportedOperationException(); + } } |