Override package storage constraint
We want to be able to move arbitrary packages to external storage,
regardless what they specify in their manifest. This is a developer
option and should be used with care. Trouble may ensue if an
application is moved when it really doesn't want to be moved
Bug: 22282121
Change-Id: I7664816a7fd122e6cdf3070fe50ce5464f325380
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 0adce5d..0cd02dd 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -74,6 +74,7 @@
import android.os.UserManager;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
+import android.provider.Settings;
import android.util.ArrayMap;
import android.util.Log;
import android.view.Display;
@@ -1603,14 +1604,17 @@
final List<VolumeInfo> vols = storage.getVolumes();
final List<VolumeInfo> candidates = new ArrayList<>();
for (VolumeInfo vol : vols) {
- if (Objects.equals(vol, currentVol) || isPackageCandidateVolume(app, vol)) {
+ if (Objects.equals(vol, currentVol) || isPackageCandidateVolume(mContext, app, vol)) {
candidates.add(vol);
}
}
return candidates;
}
- private static boolean isPackageCandidateVolume(ApplicationInfo app, VolumeInfo vol) {
+ private static boolean isPackageCandidateVolume(
+ ContextImpl context, ApplicationInfo app, VolumeInfo vol) {
+ final boolean forceAllowOnExternal = Settings.Global.getInt(
+ context.getContentResolver(), Settings.Global.FORCE_ALLOW_ON_EXTERNAL, 0) != 0;
// Private internal is always an option
if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(vol.getId())) {
return true;
@@ -1618,8 +1622,11 @@
// System apps and apps demanding internal storage can't be moved
// anywhere else
- if (app.isSystemApp()
- || app.installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) {
+ if (app.isSystemApp()) {
+ return false;
+ }
+ if (!forceAllowOnExternal
+ && app.installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) {
return false;
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 3cd01d0..2d78d2b 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6226,6 +6226,14 @@
public static final String MDC_INITIAL_MAX_RETRY = "mdc_initial_max_retry";
/**
+ * Whether any package can be on external storage. When this is true, any
+ * package, regardless of manifest values, is a candidate for installing
+ * or moving onto external storage. (0 = false, 1 = true)
+ * @hide
+ */
+ public static final String FORCE_ALLOW_ON_EXTERNAL = "force_allow_on_external";
+
+ /**
* Whether user has enabled development settings.
*/
public static final String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled";
diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java
index b04ddf4..de29a96 100644
--- a/core/java/com/android/internal/content/PackageHelper.java
+++ b/core/java/com/android/internal/content/PackageHelper.java
@@ -34,8 +34,10 @@
import android.os.storage.StorageResultCode;
import android.os.storage.StorageVolume;
import android.os.storage.VolumeInfo;
+import android.provider.Settings;
import android.util.ArraySet;
import android.util.Log;
+import android.util.Slog;
import libcore.io.IoUtils;
@@ -345,6 +347,8 @@
*/
public static String resolveInstallVolume(Context context, String packageName,
int installLocation, long sizeBytes) throws IOException {
+ final boolean forceAllowOnExternal = Settings.Global.getInt(
+ context.getContentResolver(), Settings.Global.FORCE_ALLOW_ON_EXTERNAL, 0) != 0;
// TODO: handle existing apps installed in ASEC; currently assumes
// they'll end up back on internal storage
ApplicationInfo existingInfo = null;
@@ -379,7 +383,8 @@
}
// If app expresses strong desire for internal space, honor it
- if (installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) {
+ if (!forceAllowOnExternal
+ && installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) {
if (fitsOnInternal) {
return null;
} else {