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

Commit 8a9ab24a authored by Suchi Amalapurapu's avatar Suchi Amalapurapu
Browse files

Do storage checks before initiating a move.

Add new remote method to check for insufficient error conditions.
Some fixes in MountService when updating media status on PackageManagerService
Fix size calculation condition in installd.

Add new error code if media is unavailable.
New tests for testing error codes.
Some additional debugging statements in MountService.

Change-Id: Ibfe90d5ed6c71d57f9c1c67806f38b5ae9ecdfbf
parent 50fdbef2
Loading
Loading
Loading
Loading
+3 −13
Original line number Diff line number Diff line
@@ -389,9 +389,10 @@ int get_size(const char *pkgname, const char *apkpath,
    int cachesize = 0;

        /* count the source apk as code -- but only if it's not
         * on the /system partition
         * on the /system partition and its not on the sdcard.
         */
    if (strncmp(apkpath, "/system", 7) != 0) {
    if (strncmp(apkpath, "/system", 7) != 0 &&
            strncmp(apkpath, SDCARD_DIR_PREFIX, 7) != 0) {
        if (stat(apkpath, &s) == 0) {
            codesize += stat_size(&s);
        }
@@ -403,17 +404,6 @@ int get_size(const char *pkgname, const char *apkpath,
            codesize += stat_size(&s);
        }
    }

        /* count the source apk as code -- but only if it's not
         * installed on the sdcard
         */
    if (strncmp(apkpath, SDCARD_DIR_PREFIX, 7) != 0) {
        if (stat(apkpath, &s) == 0) {
            codesize += stat_size(&s);
        }
    }


        /* count the cached dexfile as code */
    if (!create_cache_path(path, apkpath)) {
        if (stat(path, &s) == 0) {
+17 −0
Original line number Diff line number Diff line
@@ -438,6 +438,15 @@ public abstract class PackageManager {
     */
    public static final int INSTALL_FAILED_INVALID_INSTALL_LOCATION = -19;

    /**
     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
     * the new package couldn't be installed in the specified install
     * location because the media is not available.
     * @hide
     */
    public static final int INSTALL_FAILED_MEDIA_UNAVAILABLE = -20;

    /**
     * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
@@ -585,6 +594,14 @@ public abstract class PackageManager {
     */
    public static final int MOVE_FAILED_INVALID_LOCATION = -5;

    /**
     * Error code that is passed to the {@link IPackageMoveObserver} by
     * {@link #movePackage(android.net.Uri, IPackageMoveObserver)}
     * if the specified package cannot be moved to the specified location.
     * @hide
     */
    public static final int MOVE_FAILED_INTERNAL_ERROR = -6;

    /**
     * Flag parameter for {@link #movePackage} to indicate that
     * the package should be moved to internal storage if its
+1 −0
Original line number Diff line number Diff line
@@ -27,4 +27,5 @@ interface IMediaContainerService {
    boolean copyResource(in Uri packageURI,
                in ParcelFileDescriptor outStream);
    PackageInfoLite getMinimalPackageInfo(in Uri fileUri);
    boolean checkFreeStorage(boolean external, in Uri fileUri);
}
 No newline at end of file
+2 −1
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ public class PackageHelper {
    public static final int RECOMMEND_FAILED_INVALID_APK = -2;
    public static final int RECOMMEND_FAILED_INVALID_LOCATION = -3;
    public static final int RECOMMEND_FAILED_ALREADY_EXISTS = -4;
    public static final int RECOMMEND_MEDIA_UNAVAILABLE = -5;
    private static final boolean localLOGV = true;
    private static final String TAG = "PackageHelper";
    // App installation location settings values
@@ -70,7 +71,7 @@ public class PackageHelper {

        try {
            int rc = mountService.createSecureContainer(
                    cid, mbLen, "vfat", sdEncKey, uid);
                    cid, mbLen, "fat", sdEncKey, uid);
            if (rc != StorageResultCode.OperationSucceeded) {
                Log.e(TAG, "Failed to create secure container " + cid);
                return null;
+58 −19
Original line number Diff line number Diff line
@@ -24,7 +24,6 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageInfoLite;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
import android.content.pm.PackageParser.Package;
import android.net.Uri;
import android.os.Environment;
import android.os.IBinder;
@@ -45,7 +44,6 @@ import java.io.IOException;
import java.io.InputStream;

import android.os.FileUtils;
import android.os.storage.IMountService;
import android.provider.Settings;

/*
@@ -130,26 +128,21 @@ public class DefaultContainerService extends IntentService {
            ret.packageName = pkg.packageName;
            ret.installLocation = pkg.installLocation;
            // Nuke the parser reference right away and force a gc
            Runtime.getRuntime().gc();
            packageParser = null;
            Runtime.getRuntime().gc();
            if (pkg == null) {
                Log.w(TAG, "Failed to parse package");
                ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK;
                return ret;
            }
            ret.packageName = pkg.packageName;
            int loc = recommendAppInstallLocation(pkg.installLocation, archiveFilePath);
            if (loc == PackageManager.INSTALL_EXTERNAL) {
                ret.recommendedInstallLocation =  PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
            } else if (loc == ERR_LOC) {
                Log.i(TAG, "Failed to install insufficient storage");
                ret.recommendedInstallLocation =  PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
            } else {
                // Implies install on internal storage.
                ret.recommendedInstallLocation =  PackageHelper.RECOMMEND_INSTALL_INTERNAL;
            }
            ret.recommendedInstallLocation = recommendAppInstallLocation(pkg.installLocation, archiveFilePath);
            return ret;
        }

        public boolean checkFreeStorage(boolean external, Uri fileUri) {
            return checkFreeStorageInner(external, fileUri);
        }
    };

    public DefaultContainerService() {
@@ -190,6 +183,12 @@ public class DefaultContainerService extends IntentService {
    }

    private String copyResourceInner(Uri packageURI, String newCid, String key, String resFileName) {
        // Make sure the sdcard is mounted.
        String status = Environment.getExternalStorageState();
        if (!status.equals(Environment.MEDIA_MOUNTED)) {
            Log.w(TAG, "Make sure sdcard is mounted.");
            return null;
        }
        // Create new container at newCachePath
        String codePath = packageURI.getPath();
        File codeFile = new File(codePath);
@@ -313,11 +312,13 @@ public class DefaultContainerService extends IntentService {
        // Else install on internal NAND flash, unless space on NAND is less than 10%
        String status = Environment.getExternalStorageState();
        long availSDSize = -1;
        boolean mediaAvailable = false;
        if (status.equals(Environment.MEDIA_MOUNTED)) {
            StatFs sdStats = new StatFs(
                    Environment.getExternalStorageDirectory().getPath());
            availSDSize = (long)sdStats.getAvailableBlocks() *
                    (long)sdStats.getBlockSize();
            mediaAvailable = true;
        }
        StatFs internalStats = new StatFs(Environment.getDataDirectory().getPath());
        long totalInternalSize = (long)internalStats.getBlockCount() *
@@ -337,7 +338,8 @@ public class DefaultContainerService extends IntentService {
        long reqInternalSize = 0;
        boolean intThresholdOk = (pctNandFree >= LOW_NAND_FLASH_TRESHOLD);
        boolean intAvailOk = ((reqInstallSize + reqInternalSize) < availInternalSize);
        boolean fitsOnSd = (reqInstallSize < availSDSize) && intThresholdOk &&
        boolean fitsOnSd = mediaAvailable && (reqInstallSize < availSDSize)
                 && intThresholdOk &&
                (reqInternalSize < availInternalSize);
        boolean fitsOnInt = intThresholdOk && intAvailOk;

@@ -377,21 +379,58 @@ public class DefaultContainerService extends IntentService {
        }
        if (!auto) {
            if (installOnlyOnSd) {
                return fitsOnSd ? PackageManager.INSTALL_EXTERNAL : ERR_LOC;
                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 ? 0 : ERR_LOC;
                return fitsOnInt ?  PackageHelper.RECOMMEND_INSTALL_INTERNAL :
                    PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
            }
        }
        // Try to install internally
        if (fitsOnInt) {
            return 0;
            return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
        }
        // Try the sdcard now.
        if (fitsOnSd) {
            return PackageManager.INSTALL_EXTERNAL;
            return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
        }
        // Return error code
        return ERR_LOC;
        return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
    }

    private boolean checkFreeStorageInner(boolean external, Uri packageURI) {
        File apkFile = new File(packageURI.getPath());
        long size = apkFile.length();
        if (external) {
            String status = Environment.getExternalStorageState();
            long availSDSize = -1;
            if (status.equals(Environment.MEDIA_MOUNTED)) {
                StatFs sdStats = new StatFs(
                        Environment.getExternalStorageDirectory().getPath());
                availSDSize = (long)sdStats.getAvailableBlocks() *
                (long)sdStats.getBlockSize();
            }
            return availSDSize > size;
        }
        StatFs internalStats = new StatFs(Environment.getDataDirectory().getPath());
        long totalInternalSize = (long)internalStats.getBlockCount() *
        (long)internalStats.getBlockSize();
        long availInternalSize = (long)internalStats.getAvailableBlocks() *
        (long)internalStats.getBlockSize();

        double pctNandFree = (double)availInternalSize / (double)totalInternalSize;
        // To make final copy
        long reqInstallSize = size;
        // 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);
        return intThresholdOk && intAvailOk;
    }
}
Loading