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

Commit d9d25bc7 authored by Xiaogang Cui's avatar Xiaogang Cui Committed by jianzhou
Browse files

Storage: Add secondary storage support for app installation

Add secondary external storage APIs for app installation. And
change the logic to allow app to be installed into external
storage.

Change-Id: If2f67af7508d020c1d041bb955e3d55136a34acc
parent 0856c09c
Loading
Loading
Loading
Loading
+42 −0
Original line number Diff line number Diff line
@@ -70,6 +70,7 @@ public class Environment {

    @GuardedBy("sLock")
    private static volatile StorageVolume sPrimaryVolume;
    private static volatile StorageVolume sNoEmulatedVolume;

    private static StorageVolume getPrimaryVolume() {
        if (SystemProperties.getBoolean("config.disable_storage", false)) {
@@ -93,6 +94,24 @@ public class Environment {
        return sPrimaryVolume;
    }

    private static StorageVolume getNoEmulatedVolume() {
        if (sNoEmulatedVolume == null) {
            synchronized (sLock) {
                if (sNoEmulatedVolume == null) {
                    try {
                        IMountService mountService = IMountService.Stub.asInterface(ServiceManager
                                .getService("mount"));
                        final StorageVolume[] volumes = mountService.getVolumeList();
                        sNoEmulatedVolume = StorageManager.getNoEmulatedVolume(volumes);
                    } catch (Exception e) {
                        Log.e(TAG, "couldn't talk to MountService", e);
                    }
                }
            }
        }
        return sNoEmulatedVolume;
    }

    static {
        initForCurrentUser();
    }
@@ -178,6 +197,11 @@ public class Environment {
            return mExternalDirsForApp[0];
        }

        /** {@hide} */
        public File getSecondaryStorageDirectory() {
            return mExternalDirsForApp[1];
        }

        @Deprecated
        public File getExternalStoragePublicDirectory(String type) {
            return buildExternalStoragePublicDirs(type)[0];
@@ -389,6 +413,12 @@ public class Environment {
        return sCurrentUser.getExternalDirsForApp()[0];
    }

    /** {@hide} */
    public static File getSecondaryStorageDirectory() {
        throwIfUserRequired();
        return sCurrentUser.getExternalDirsForApp()[1];
    }

    /** {@hide} */
    public static File getLegacyExternalStorageDirectory() {
        return new File(System.getenv(ENV_EXTERNAL_STORAGE));
@@ -709,6 +739,12 @@ public class Environment {
        return getStorageState(externalDir);
    }

    /** {@hide} */
    public static String getSecondaryStorageState() {
        final File externalDir = sCurrentUser.getExternalDirsForApp()[1];
        return getStorageState(externalDir);
    }

    /**
     * Returns the current state of the storage device that provides the given
     * path.
@@ -756,6 +792,12 @@ public class Environment {
        return (primary != null && primary.isRemovable());
    }

    /** {@hide} */
    public static boolean isNoEmulatedStorageExist() {
        final StorageVolume volume = getNoEmulatedVolume();
        return (volume != null);
    }

    /**
     * Returns whether the device has an external storage device which is
     * emulated. If true, the device does not have real external storage, and the directory
+10 −0
Original line number Diff line number Diff line
@@ -632,6 +632,16 @@ public class StorageManager {
        return null;
    }

    /**{@hide} */
    public static StorageVolume getNoEmulatedVolume(StorageVolume[] volumes) {
        for (StorageVolume volume : volumes) {
            if (!volume.isEmulated()) {
                return volume;
            }
        }
        return null;
    }

    private static final int DEFAULT_THRESHOLD_PERCENTAGE = 10;
    private static final long DEFAULT_THRESHOLD_MAX_BYTES = 500 * MB_IN_BYTES;
    private static final long DEFAULT_FULL_THRESHOLD_BYTES = MB_IN_BYTES;
+10 −10
Original line number Diff line number Diff line
@@ -717,7 +717,7 @@ public class DefaultContainerService extends IntentService {
            prefer = PREFER_INTERNAL;
        }

        final boolean emulated = Environment.isExternalStorageEmulated();
        final boolean noemulated = Environment.isNoEmulatedStorageExist();

        final File apkFile = new File(archiveFilePath);

@@ -731,7 +731,7 @@ public class DefaultContainerService extends IntentService {
        }

        boolean fitsOnSd = false;
        if (!emulated && (checkBoth || prefer == PREFER_EXTERNAL)) {
        if (noemulated && (checkBoth || prefer == PREFER_EXTERNAL)) {
            try {
                fitsOnSd = isUnderExternalThreshold(apkFile, isForwardLocked);
            } catch (IOException e) {
@@ -743,7 +743,7 @@ public class DefaultContainerService extends IntentService {
            if (fitsOnInternal) {
                return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
            }
        } else if (!emulated && prefer == PREFER_EXTERNAL) {
        } else if (noemulated && prefer == PREFER_EXTERNAL) {
            if (fitsOnSd) {
                return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
            }
@@ -752,7 +752,7 @@ public class DefaultContainerService extends IntentService {
        if (checkBoth) {
            if (fitsOnInternal) {
                return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
            } else if (!emulated && fitsOnSd) {
            } else if (noemulated && fitsOnSd) {
                return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
            }
        }
@@ -762,8 +762,8 @@ public class DefaultContainerService extends IntentService {
         * the media was unavailable. Otherwise, indicate there was insufficient
         * storage space available.
         */
        if (!emulated && (checkBoth || prefer == PREFER_EXTERNAL)
                && !Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
        if (noemulated && (checkBoth || prefer == PREFER_EXTERNAL)
                && !Environment.MEDIA_MOUNTED.equals(Environment.getSecondaryStorageState())) {
            return PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE;
        } else {
            return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
@@ -806,17 +806,17 @@ public class DefaultContainerService extends IntentService {
     */
    private boolean isUnderExternalThreshold(File apkFile, boolean isForwardLocked)
            throws IOException {
        if (Environment.isExternalStorageEmulated()) {
        if (!Environment.isNoEmulatedStorageExist()) {
            return false;
        }

        final int sizeMb = calculateContainerSize(apkFile, isForwardLocked);

        final int availSdMb;
        if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
            final StatFs sdStats = new StatFs(Environment.getExternalStorageDirectory().getPath());
        if (Environment.MEDIA_MOUNTED.equals(Environment.getSecondaryStorageState())) {
            final StatFs sdStats = new StatFs(Environment.getSecondaryStorageDirectory().getPath());
            final int blocksToMb = (1 << 20) / sdStats.getBlockSize();
            availSdMb = sdStats.getAvailableBlocks() * blocksToMb;
            availSdMb = sdStats.getAvailableBlocks() / blocksToMb;
        } else {
            availSdMb = -1;
        }
+3 −3
Original line number Diff line number Diff line
@@ -678,9 +678,9 @@ class MountService extends IMountService.Stub

        Slog.d(TAG, "volume state changed for " + path + " (" + oldState + " -> " + state + ")");

        // Tell PackageManager about changes to primary volume state, but only
        // when not emulated.
        if (volume.isPrimary() && !volume.isEmulated()) {
        // Tell PackageManager about changes, not only to primary volume,
        // to all the non-emulated storage volumes
        if (!volume.isEmulated()) {
            if (Environment.MEDIA_UNMOUNTED.equals(state)) {
                mPms.updateExternalMediaStatus(false, false);

+14 −2
Original line number Diff line number Diff line
@@ -6605,8 +6605,20 @@ public class PackageManagerService extends IPackageManager.Stub {

        verificationParams.setInstallerUid(uid);

        final int userFilteredFlags;

        if (getInstallLocation() == PackageHelper.APP_INSTALL_INTERNAL) {
            Slog.w(TAG, "PackageManager.INSTALL_INTERNAL"  );
            userFilteredFlags = flags | PackageManager.INSTALL_INTERNAL;
        } else if (getInstallLocation() == PackageHelper.APP_INSTALL_EXTERNAL) {
            Slog.w(TAG, "PackageManager.INSTALL_EXTERNAL"  );
            userFilteredFlags = flags | PackageManager.INSTALL_EXTERNAL;
        } else{
            userFilteredFlags = filteredFlags;
        }

        final Message msg = mHandler.obtainMessage(INIT_COPY);
        msg.obj = new InstallParams(packageURI, observer, filteredFlags, installerPackageName,
        msg.obj = new InstallParams(packageURI, observer, userFilteredFlags, installerPackageName,
                verificationParams, encryptionParams, user);
        mHandler.sendMessage(msg);
    }
@@ -7233,7 +7245,7 @@ public class PackageManagerService extends IPackageManager.Stub {
            if (Environment.isExternalStorageEmulated()) {
                mounted = true;
            } else {
                final String status = Environment.getExternalStorageState();
                final String status = Environment.getSecondaryStorageState();
                mounted = (Environment.MEDIA_MOUNTED.equals(status)
                        || Environment.MEDIA_MOUNTED_READ_ONLY.equals(status));
            }