Merge "Create a new mount mode for installer packages."
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index f928501..b42d53a 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -306,6 +306,6 @@
public abstract void setDebugFlagsForStartingActivity(ActivityInfo aInfo, int startFlags,
ProfilerInfo profilerInfo, Object wmLock);
- /** Checks if process running with given pid has access to full external storage or not */
- public abstract boolean isAppStorageSandboxed(int pid, int uid);
+ /** Returns mount mode for process running with given pid */
+ public abstract int getStorageMountMode(int pid, int uid);
}
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 7fd0a4b..f136cd6 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -398,6 +398,8 @@
argsForZygote.add("--mount-external-write");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_FULL) {
argsForZygote.add("--mount-external-full");
+ } else if (mountExternal == Zygote.MOUNT_EXTERNAL_INSTALLER) {
+ argsForZygote.add("--mount-external-installer");
}
argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 65213c0..65b9fad 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -81,6 +81,11 @@
public static final int MOUNT_EXTERNAL_READ = IVold.REMOUNT_MODE_READ;
/** Read-write external storage should be mounted. */
public static final int MOUNT_EXTERNAL_WRITE = IVold.REMOUNT_MODE_WRITE;
+ /**
+ * Mount mode for package installers which should give them access to
+ * all obb dirs in addition to their package sandboxes
+ */
+ public static final int MOUNT_EXTERNAL_INSTALLER = IVold.REMOUNT_MODE_INSTALLER;
/** Read-write external storage should be mounted instead of package sandbox */
public static final int MOUNT_EXTERNAL_FULL = IVold.REMOUNT_MODE_FULL;
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 4a94ec4..f182c4d 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -656,7 +656,9 @@
mountExternal = Zygote.MOUNT_EXTERNAL_WRITE;
} else if (arg.equals("--mount-external-full")) {
mountExternal = Zygote.MOUNT_EXTERNAL_FULL;
- } else if (arg.equals("--query-abi-list")) {
+ } else if (arg.equals("--mount-external-installer")) {
+ mountExternal = Zygote.MOUNT_EXTERNAL_INSTALLER;
+ } else if (arg.equals("--query-abi-list")) {
abiListQuery = true;
} else if (arg.equals("--get-pid")) {
pidQuery = true;
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 4aa88e7..7032081 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -99,7 +99,8 @@
MOUNT_EXTERNAL_DEFAULT = 1,
MOUNT_EXTERNAL_READ = 2,
MOUNT_EXTERNAL_WRITE = 3,
- MOUNT_EXTERNAL_FULL = 4,
+ MOUNT_EXTERNAL_INSTALLER = 4,
+ MOUNT_EXTERNAL_FULL = 5,
};
// Must match values in com.android.internal.os.Zygote.
@@ -446,6 +447,22 @@
return true;
}
+static bool bindMount(const std::string& sourceDir, const std::string& targetDir,
+ std::string* error_msg) {
+ if (TEMP_FAILURE_RETRY(mount(sourceDir.c_str(), targetDir.c_str(),
+ nullptr, MS_BIND | MS_REC, nullptr)) == -1) {
+ *error_msg = CREATE_ERROR("Failed to mount %s to %s: %s",
+ sourceDir.c_str(), targetDir.c_str(), strerror(errno));
+ return false;
+ }
+ if (TEMP_FAILURE_RETRY(mount(nullptr, targetDir.c_str(),
+ nullptr, MS_SLAVE | MS_REC, nullptr)) == -1) {
+ *error_msg = CREATE_ERROR("Failed to set MS_SLAVE for %s", targetDir.c_str());
+ return false;
+ }
+ return true;
+}
+
static bool mountPkgSpecificDir(const std::string& mntSourceRoot,
const std::string& mntTargetRoot, const std::string& packageName,
const char* dirName, std::string* error_msg) {
@@ -453,22 +470,12 @@
mntSourceRoot.c_str(), dirName, packageName.c_str());
std::string mntTargetDir = StringPrintf("%s/Android/%s/%s",
mntTargetRoot.c_str(), dirName, packageName.c_str());
- if (TEMP_FAILURE_RETRY(mount(mntSourceDir.c_str(), mntTargetDir.c_str(),
- nullptr, MS_BIND | MS_REC, nullptr)) == -1) {
- *error_msg = CREATE_ERROR("Failed to mount %s to %s: %s",
- mntSourceDir.c_str(), mntTargetDir.c_str(), strerror(errno));
- return false;
- }
- if (TEMP_FAILURE_RETRY(mount(nullptr, mntTargetDir.c_str(),
- nullptr, MS_SLAVE | MS_REC, nullptr)) == -1) {
- *error_msg = CREATE_ERROR("Failed to set MS_SLAVE for %s", mntTargetDir.c_str());
- return false;
- }
- return true;
+ return bindMount(mntSourceDir, mntTargetDir, error_msg);
}
static bool preparePkgSpecificDirs(const std::vector<std::string>& packageNames,
- const std::vector<std::string>& volumeLabels, userid_t userId, std::string* error_msg) {
+ const std::vector<std::string>& volumeLabels, bool mountAllObbs,
+ userid_t userId, std::string* error_msg) {
for (auto& label : volumeLabels) {
std::string mntSource = StringPrintf("/mnt/runtime/write/%s", label.c_str());
std::string mntTarget = StringPrintf("/storage/%s", label.c_str());
@@ -479,7 +486,14 @@
for (auto& package : packageNames) {
mountPkgSpecificDir(mntSource, mntTarget, package, "data", error_msg);
mountPkgSpecificDir(mntSource, mntTarget, package, "media", error_msg);
- mountPkgSpecificDir(mntSource, mntTarget, package, "obb", error_msg);
+ if (!mountAllObbs) {
+ mountPkgSpecificDir(mntSource, mntTarget, package, "obb", error_msg);
+ }
+ }
+ if (mountAllObbs) {
+ StringAppendF(&mntSource, "/Android/obb");
+ StringAppendF(&mntTarget, "/Android/obb");
+ bindMount(mntSource, mntTarget, error_msg);
}
}
return true;
@@ -500,7 +514,7 @@
storageSource = "/mnt/runtime/read";
} else if (mount_mode == MOUNT_EXTERNAL_WRITE) {
storageSource = "/mnt/runtime/write";
- } else if (mount_mode != MOUNT_EXTERNAL_FULL && !force_mount_namespace) {
+ } else if (mount_mode == MOUNT_EXTERNAL_NONE && !force_mount_namespace) {
// Sane default of no storage visible
return true;
}
@@ -568,12 +582,28 @@
pkgSandboxDir.c_str(), strerror(errno));
return false;
}
+ if (access("/storage/obb_mount", F_OK) == 0) {
+ if (mount_mode != MOUNT_EXTERNAL_INSTALLER) {
+ remove("/storage/obb_mount");
+ }
+ } else {
+ if (mount_mode == MOUNT_EXTERNAL_INSTALLER) {
+ int fd = TEMP_FAILURE_RETRY(open("/storage/obb_mount",
+ O_RDWR | O_CREAT, 0660));
+ if (fd == -1) {
+ *error_msg = CREATE_ERROR("Couldn't create /storage/obb_mount: %s",
+ strerror(errno));
+ return false;
+ }
+ close(fd);
+ }
+ }
// If the sandbox was already created by vold, only then set up the bind mounts for
// pkg specific directories. Otherwise, leave as is and bind mounts will be taken
// care of by vold later.
if (sandboxAlreadyCreated) {
if (!preparePkgSpecificDirs(packages_for_uid, visible_vol_ids,
- user_id, error_msg)) {
+ mount_mode == MOUNT_EXTERNAL_INSTALLER, user_id, error_msg)) {
return false;
}
}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 4b092b2..5901ece 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -16,6 +16,11 @@
package com.android.server;
+import static android.Manifest.permission.INSTALL_PACKAGES;
+import static android.Manifest.permission.WRITE_MEDIA_STORAGE;
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.OP_REQUEST_INSTALL_PACKAGES;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
import static android.os.storage.OnObbStateChangeListener.ERROR_ALREADY_MOUNTED;
@@ -51,6 +56,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
import android.content.pm.IPackageMoveObserver;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
@@ -116,6 +122,7 @@
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.app.IAppOpsService;
import com.android.internal.os.AppFuseMount;
import com.android.internal.os.BackgroundThread;
import com.android.internal.os.FuseUnavailableMountException;
@@ -453,6 +460,9 @@
private UserManagerInternal mUmInternal;
private ActivityManagerInternal mAmInternal;
+ private IPackageManager mIPackageManager;
+ private IAppOpsService mIAppOpsService;
+
private final Callbacks mCallbacks;
private final LockPatternUtils mLockPatternUtils;
@@ -1570,6 +1580,10 @@
.registerScreenObserver(this);
mSystemReady = true;
+ mIPackageManager = IPackageManager.Stub.asInterface(
+ ServiceManager.getService("package"));
+ mIAppOpsService = IAppOpsService.Stub.asInterface(
+ ServiceManager.getService(Context.APP_OPS_SERVICE));
mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget();
}
@@ -3117,7 +3131,8 @@
throw new SecurityException("Shady looking path " + path);
}
- if (!mAmInternal.isAppStorageSandboxed(pid, uid)) {
+ final int mountMode = mAmInternal.getStorageMountMode(pid, uid);
+ if (mountMode == Zygote.MOUNT_EXTERNAL_FULL) {
return path;
}
@@ -3126,6 +3141,11 @@
final String device = m.group(1);
final String devicePath = m.group(2);
+ if (mountMode == Zygote.MOUNT_EXTERNAL_INSTALLER
+ && devicePath.startsWith("Android/obb/")) {
+ return path;
+ }
+
// Does path belong to any packages belonging to this UID? If so,
// they get to go straight through to legacy paths.
final String[] pkgs = mContext.getPackageManager().getPackagesForUid(uid);
@@ -3477,6 +3497,27 @@
}
}
+ private int getMountMode(int uid, String packageName) {
+ try {
+ if (Process.isIsolated(uid)) {
+ return Zygote.MOUNT_EXTERNAL_NONE;
+ }
+ if (mIPackageManager.checkUidPermission(WRITE_MEDIA_STORAGE, uid)
+ == PERMISSION_GRANTED) {
+ return Zygote.MOUNT_EXTERNAL_FULL;
+ } else if (mIPackageManager.checkUidPermission(INSTALL_PACKAGES, uid)
+ == PERMISSION_GRANTED || mIAppOpsService.checkOperation(
+ OP_REQUEST_INSTALL_PACKAGES, uid, packageName) == MODE_ALLOWED) {
+ return Zygote.MOUNT_EXTERNAL_INSTALLER;
+ } else {
+ return Zygote.MOUNT_EXTERNAL_WRITE;
+ }
+ } catch (RemoteException e) {
+ // Should not happen
+ }
+ return Zygote.MOUNT_EXTERNAL_NONE;
+ }
+
private static class Callbacks extends Handler {
private static final int MSG_STORAGE_STATE_CHANGED = 1;
private static final int MSG_VOLUME_STATE_CHANGED = 2;
@@ -3718,6 +3759,9 @@
@Override
public int getExternalStorageMountMode(int uid, String packageName) {
+ if (ENABLE_ISOLATED_STORAGE) {
+ return getMountMode(uid, packageName);
+ }
// No locking - CopyOnWriteArrayList
int mountMode = Integer.MAX_VALUE;
for (ExternalStorageMountPolicy policy : mPolicies) {
@@ -3754,6 +3798,9 @@
if (uid == Process.SYSTEM_UID) {
return true;
}
+ if (ENABLE_ISOLATED_STORAGE) {
+ return getMountMode(uid, packageName) != Zygote.MOUNT_EXTERNAL_NONE;
+ }
// No locking - CopyOnWriteArrayList
for (ExternalStorageMountPolicy policy : mPolicies) {
final boolean policyHasStorage = policy.hasExternalStorage(uid, packageName);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 69cfcc2..8ce37a5 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -19441,16 +19441,13 @@
}
@Override
- public boolean isAppStorageSandboxed(int pid, int uid) {
- if (!StorageManager.hasIsolatedStorage()) {
- return false;
- }
+ public int getStorageMountMode(int pid, int uid) {
if (uid == SHELL_UID || uid == ROOT_UID) {
- return false;
+ return Zygote.MOUNT_EXTERNAL_FULL;
}
synchronized (mPidsSelfLocked) {
final ProcessRecord pr = mPidsSelfLocked.get(pid);
- return pr == null || pr.mountMode != Zygote.MOUNT_EXTERNAL_FULL;
+ return pr == null ? Zygote.MOUNT_EXTERNAL_NONE : pr.mountMode;
}
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 7d0f98c..6cfb846 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -24,7 +24,6 @@
import static android.Manifest.permission.REQUEST_DELETE_PACKAGES;
import static android.Manifest.permission.SET_HARMFUL_APP_WARNINGS;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
-import static android.Manifest.permission.WRITE_MEDIA_STORAGE;
import static android.content.Intent.ACTION_MAIN;
import static android.content.Intent.CATEGORY_DEFAULT;
import static android.content.Intent.CATEGORY_HOME;
@@ -20181,11 +20180,6 @@
if (Process.isIsolated(uid)) {
return Zygote.MOUNT_EXTERNAL_NONE;
}
- if (StorageManager.hasIsolatedStorage()) {
- return checkUidPermission(WRITE_MEDIA_STORAGE, uid) == PERMISSION_GRANTED
- ? Zygote.MOUNT_EXTERNAL_FULL
- : Zygote.MOUNT_EXTERNAL_WRITE;
- }
if (checkUidPermission(READ_EXTERNAL_STORAGE, uid) == PERMISSION_DENIED) {
return Zygote.MOUNT_EXTERNAL_DEFAULT;
}
diff --git a/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java
index e6b328a..ec5d93e 100644
--- a/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java
@@ -29,8 +29,7 @@
import android.os.UserManagerInternal;
import android.os.storage.StorageManagerInternal;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.os.Zygote;
import org.junit.Before;
import org.junit.Test;
@@ -38,6 +37,9 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
public class StorageManagerServiceTest {
@@ -97,15 +99,15 @@
when(mPm.getPackagesForUid(eq(UID_GREY))).thenReturn(new String[] { PKG_GREY });
when(mPm.getPackagesForUid(eq(UID_COLORS))).thenReturn(new String[] { PKG_RED, PKG_BLUE });
- setIsAppStorageSandboxed(PID_BLUE, UID_COLORS, true);
- setIsAppStorageSandboxed(PID_GREY, UID_GREY, true);
- setIsAppStorageSandboxed(PID_RED, UID_COLORS, true);
+ setStorageMountMode(PID_BLUE, UID_COLORS, Zygote.MOUNT_EXTERNAL_WRITE);
+ setStorageMountMode(PID_GREY, UID_GREY, Zygote.MOUNT_EXTERNAL_WRITE);
+ setStorageMountMode(PID_RED, UID_COLORS, Zygote.MOUNT_EXTERNAL_WRITE);
mService = new StorageManagerService(mContext);
}
- private void setIsAppStorageSandboxed(int pid, int uid, boolean sandboxed) {
- when(mAmi.isAppStorageSandboxed(pid, uid)).thenReturn(sandboxed);
+ private void setStorageMountMode(int pid, int uid, int mountMode) {
+ when(mAmi.getStorageMountMode(pid, uid)).thenReturn(mountMode);
}
@Test
@@ -210,7 +212,7 @@
@Test
public void testPackageNotSandboxed() throws Exception {
- setIsAppStorageSandboxed(PID_RED, UID_COLORS, false);
+ setStorageMountMode(PID_RED, UID_COLORS, Zygote.MOUNT_EXTERNAL_FULL);
// Both app and system have the same view
assertTranslation(
@@ -224,6 +226,29 @@
PID_RED, UID_COLORS);
}
+ @Test
+ public void testInstallerPackage() throws Exception {
+ setStorageMountMode(PID_GREY, UID_GREY, Zygote.MOUNT_EXTERNAL_INSTALLER);
+
+ assertTranslation(
+ "/storage/emulated/0/Android/obb/com.grey/foo.jpg",
+ "/storage/emulated/0/Android/obb/com.grey/foo.jpg",
+ PID_GREY, UID_GREY);
+ assertTranslation(
+ "/storage/emulated/0/Android/obb/com.blue/bar.jpg",
+ "/storage/emulated/0/Android/obb/com.blue/bar.jpg",
+ PID_GREY, UID_GREY);
+
+ assertTranslation(
+ "/storage/emulated/0/Android/data/com.grey/foo.jpg",
+ "/storage/emulated/0/Android/data/com.grey/foo.jpg",
+ PID_GREY, UID_GREY);
+ assertTranslation(
+ "/storage/emulated/0/Android/sandbox/com.grey/Android/data/com.blue/bar.jpg",
+ "/storage/emulated/0/Android/data/com.blue/bar.jpg",
+ PID_GREY, UID_GREY);
+ }
+
private void assertTranslation(String system, String sandbox,
int pid, int uid) throws Exception {
assertEquals(system,