Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 117818e4 authored by Suchi Amalapurapu's avatar Suchi Amalapurapu
Browse files

Add new manifest option for install location

Change recommendAppInstallLocation api
add code to parse new attribute.
Define flags in PackageInfo
Add new settings attributes for enabling setting and value for install location
Some tests
The policy for install location: if explicitly set in manifest as internal only we try to install the app only on internal storage. if set to preferExternal, we try to install it on sdcard if possible. If not we fall back to internal.
If the user enables setting SET_INSTALL_LOCATION(which will always
be set to false in final release builds) and sets a prefered location, we try
to honour it.
parent 596ce7fb
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -4585,6 +4585,17 @@
 visibility="public"
>
</field>
<field name="installLocation"
 type="int"
 transient="false"
 volatile="false"
 value="16843448"
 static="true"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</field>
<field name="interpolator"
 type="int"
 transient="false"
+61 −33
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@ import android.content.pm.PermissionInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.PackageParser.Package;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
@@ -85,6 +86,7 @@ import android.os.StatFs;
import android.os.Vibrator;
import android.os.FileUtils.FileStatus;
import android.os.storage.StorageManager;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.text.ClipboardManager;
import android.util.AndroidRuntimeException;
@@ -2646,14 +2648,13 @@ class ContextImpl extends Context {
        // 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) {
        public int recommendAppInstallLocation(Package pkg) {
            // 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)) {
            if (pkg == null) {
                return INSTALL_PARSE_FAILED_NOT_APK;
            }

@@ -2669,44 +2670,71 @@ class ContextImpl extends Context {

            double pctNandFree = (double)availInternalFlashSize / (double)totalInternalFlashSize;

            final String archiveFilePath = packageURI.getPath();
            final String archiveFilePath = pkg.mScanPath;
            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;
            }
            boolean auto = true;
            // To make final copy
            long reqInstallSize = pkgLen;
            // For dex files
            long reqInternalSize = 1 * pkgLen;
            boolean intThresholdOk = (pctNandFree >= LOW_NAND_FLASH_TRESHOLD);
            boolean intAvailOk = ((reqInstallSize + reqInternalSize) < availInternalFlashSize);
            boolean fitsOnSd = (reqInstallSize < availSDSize) && intThresholdOk &&
                    (reqInternalSize < availInternalFlashSize);
            boolean fitsOnInt = intThresholdOk && intAvailOk;

            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;
            // Consider application flags preferences as well...
            boolean installOnlyOnSd = (pkg.installLocation ==
                    PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL);
            boolean installOnlyInternal = (pkg.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;
                }
                return INSTALL_ON_INTERNAL_FLASH;
            } else {
                if (fitsOnSD) {
                    // Recommend SD card
                    return INSTALL_ON_SDCARD;
                } else if (fitsOnInternalFlash && (pctNandFree >= LOW_NAND_FLASH_TRESHOLD) &&
                        !(installOnlyOnSD)) {
                // Check if user option is enabled
                boolean setInstallLoc = Settings.System.getInt(mContext.getContentResolver(),
                        Settings.System.SET_INSTALL_LOCATION, 0) != 0;
                if (setInstallLoc) {
                    // Pick user preference
                    int installPreference = Settings.System.getInt(mContext.getContentResolver(),
                            Settings.System.DEFAULT_INSTALL_LOCATION,
                            PackageInfo.INSTALL_LOCATION_AUTO);
                    if (installPreference == 1) {
                        installOnlyInternal = true;
                        auto = false;
                    } else if (installPreference == 2) {
                        installOnlyOnSd = true;
                        auto = false;
                    }
                }
            }
            if (!auto) {
                if (installOnlyOnSd) {
                    return fitsOnSd ? INSTALL_ON_SDCARD : INSTALL_FAILED_INSUFFICIENT_STORAGE;
                } else if (installOnlyInternal){
                    // Check on internal flash
                    return fitsOnInt ? INSTALL_ON_INTERNAL_FLASH : INSTALL_FAILED_INSUFFICIENT_STORAGE;
                }
            }
            // Try to install internally
            if (fitsOnInt) {
                return INSTALL_ON_INTERNAL_FLASH;
                } else {
                    return INSTALL_FAILED_INSUFFICIENT_STORAGE;
            }
            // Try the sdcard now.
            if (fitsOnSd) {
                return INSTALL_ON_SDCARD;
            }
            // Return error code
            return INSTALL_FAILED_INSUFFICIENT_STORAGE;
        }

        private final ContextImpl mContext;
+30 −0
Original line number Diff line number Diff line
@@ -132,6 +132,34 @@ public class PackageInfo implements Parcelable {
     */
    public FeatureInfo[] reqFeatures;

    /**
     * Constant corresponding to <code>auto</code> in
     * the {@link android.R.attr#installLocation} attribute.
     * @hide
     */
    public static final int INSTALL_LOCATION_AUTO = 0;
    /**
     * Constant corresponding to <code>internalOnly</code> in
     * the {@link android.R.attr#installLocation} attribute.
     * @hide
     */
    public static final int INSTALL_LOCATION_INTERNAL_ONLY = 1;
    /**
     * Constant corresponding to <code>preferExternal</code> in
     * the {@link android.R.attr#installLocation} attribute.
     * @hide
     */
    public static final int INSTALL_LOCATION_PREFER_EXTERNAL = 2;
    /**
     * The launch mode style requested by the activity.  From the
     * {@link android.R.attr#installLocation} attribute, one of
     * {@link #INSTALL_LOCATION_AUTO},
     * {@link #INSTALL_LOCATION_INTERNAL_ONLY},
     * {@link #INSTALL_LOCATION_PREFER_EXTERNAL}
     * @hide
     */
    public int installLocation = INSTALL_LOCATION_INTERNAL_ONLY;
    
    public PackageInfo() {
    }

@@ -168,6 +196,7 @@ public class PackageInfo implements Parcelable {
        dest.writeTypedArray(signatures, parcelableFlags);
        dest.writeTypedArray(configPreferences, parcelableFlags);
        dest.writeTypedArray(reqFeatures, parcelableFlags);
        dest.writeInt(installLocation);
    }

    public static final Parcelable.Creator<PackageInfo> CREATOR
@@ -202,5 +231,6 @@ public class PackageInfo implements Parcelable {
        signatures = source.createTypedArray(Signature.CREATOR);
        configPreferences = source.createTypedArray(ConfigurationInfo.CREATOR);
        reqFeatures = source.createTypedArray(FeatureInfo.CREATOR);
        installLocation = source.readInt();
    }
}
+5 −4
Original line number Diff line number Diff line
@@ -630,10 +630,11 @@ public abstract class PackageManager {
    
    /**
     * Determines best place to install an application: either SD or internal FLASH.
     * Tweak the algorithm for best results.
     * @param appInfo ApplicationInfo object of the package to install.
     * If applications explicitly set installLocation in their manifest, that
     * preference takes precedence. If not a recommended location is returned
     * based on current available storage on internal flash or sdcard.
     * @param pkgInfo PackageParser.Package of the package that is to be installed.
     * Call utility method to obtain.
     * @param packageURI URI identifying the package's APK file.
     * @return {@link INSTALL_ON_INTERNAL_FLASH} if it is best to install package on internal
     * storage, {@link INSTALL_ON_SDCARD} if it is best to install package on SD card,
     * and {@link INSTALL_FAILED_INSUFFICIENT_STORAGE} if insufficient space to safely install
@@ -642,7 +643,7 @@ public abstract class PackageManager {
     * This recommendation does take into account the package's own flags.
     * @hide
     */
    public abstract int recommendAppInstallLocation(ApplicationInfo appInfo, Uri packageURI);
    public abstract int recommendAppInstallLocation(PackageParser.Package pkg);

    /**
     * Retrieve overall information about an application package that is
+6 −0
Original line number Diff line number Diff line
@@ -177,6 +177,7 @@ public class PackageParser {
        pi.sharedUserId = p.mSharedUserId;
        pi.sharedUserLabel = p.mSharedUserLabel;
        pi.applicationInfo = p.applicationInfo;
        pi.installLocation = p.installLocation;
        if ((flags&PackageManager.GET_GIDS) != 0) {
            pi.gids = gids;
        }
@@ -709,6 +710,9 @@ public class PackageParser {
                    com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0);
        }
        sa.recycle();
        pkg.installLocation = sa.getInteger(
                com.android.internal.R.styleable.AndroidManifest_installLocation,
                PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);

        // Resource boolean are -1, so 1 means we don't know the value.
        int supportsSmallScreens = 1;
@@ -2610,6 +2614,8 @@ public class PackageParser {
         */
        public ArrayList<FeatureInfo> reqFeatures = null;

        public int installLocation;

        public Package(String _name) {
            packageName = _name;
            applicationInfo.packageName = _name;
Loading