diff options
author | Svet Ganov <svetoslavganov@google.com> | 2015-07-10 14:29:33 -0700 |
---|---|---|
committer | Svetoslav <svetoslavganov@google.com> | 2015-07-13 18:22:30 -0700 |
commit | 6ee871e59812fea4525c50231f677c4bd10c74b8 (patch) | |
tree | 6392027a89ad7aa8ba5bd2d0ff5398364433c2dd /services | |
parent | c09544bb88ada53494d4a955d0450a22985b4799 (diff) | |
download | frameworks_base-6ee871e59812fea4525c50231f677c4bd10c74b8.zip frameworks_base-6ee871e59812fea4525c50231f677c4bd10c74b8.tar.gz frameworks_base-6ee871e59812fea4525c50231f677c4bd10c74b8.tar.bz2 |
Teach storage appops.
For modern apps targeting M SDK and up the external storage state
is deterined by granted permissions. For apps targeting older SDK
the storage access is determined by app ops correspning to the
storage permissions as the latter are always granted.
When app ops change we do not remount as we kill the app process
in both cases enabling and disabling an app op since legacy code
is not prepared for dynamic behavior where an operation that failed
may next succeed. Hence, we remount when we start the app.
For modern apps we don't kill the app process on a permission
grant, therefore we synchronously remount the app storage.
bug:22104923
Change-Id: I601c19c764a74c2d15bea6630d0f5fdc52bf6a5a
Diffstat (limited to 'services')
4 files changed, 149 insertions, 49 deletions
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java index f0fc399..417f18d 100644 --- a/services/core/java/com/android/server/AppOpsService.java +++ b/services/core/java/com/android/server/AppOpsService.java @@ -48,6 +48,7 @@ import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; +import android.os.storage.MountServiceInternal; import android.util.ArrayMap; import android.util.ArraySet; import android.util.AtomicFile; @@ -60,6 +61,7 @@ import android.util.Xml; import com.android.internal.app.IAppOpsService; import com.android.internal.app.IAppOpsCallback; +import com.android.internal.os.Zygote; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.XmlUtils; @@ -245,6 +247,34 @@ public class AppOpsService extends IAppOpsService.Stub { scheduleFastWriteLocked(); } } + + MountServiceInternal mountServiceInternal = LocalServices.getService( + MountServiceInternal.class); + mountServiceInternal.addExternalStoragePolicy( + new MountServiceInternal.ExternalStorageMountPolicy() { + @Override + public int getMountMode(int uid, String packageName) { + if (Process.isIsolated(uid)) { + return Zygote.MOUNT_EXTERNAL_NONE; + } + if (noteOperation(AppOpsManager.OP_READ_EXTERNAL_STORAGE, uid, + packageName) != AppOpsManager.MODE_ALLOWED) { + return Zygote.MOUNT_EXTERNAL_NONE; + } + if (noteOperation(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, uid, + packageName) != AppOpsManager.MODE_ALLOWED) { + return Zygote.MOUNT_EXTERNAL_READ; + } + return Zygote.MOUNT_EXTERNAL_WRITE; + } + + @Override + public boolean hasExternalStorage(int uid, String packageName) { + final int mountMode = getMountMode(uid, packageName); + return mountMode == Zygote.MOUNT_EXTERNAL_READ + || mountMode == Zygote.MOUNT_EXTERNAL_WRITE; + } + }); } public void packageRemoved(int uid, String packageName) { diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java index da552dd..bc61c3d 100644 --- a/services/core/java/com/android/server/MountService.java +++ b/services/core/java/com/android/server/MountService.java @@ -68,6 +68,8 @@ import android.os.storage.IMountService; import android.os.storage.IMountServiceListener; import android.os.storage.IMountShutdownObserver; import android.os.storage.IObbActionListener; +import android.os.storage.MountServiceInternal; +import android.os.storage.MountServiceInternal.ExternalStorageMountPolicy; import android.os.storage.OnObbStateChangeListener; import android.os.storage.StorageManager; import android.os.storage.StorageResultCode; @@ -127,6 +129,7 @@ import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -307,16 +310,6 @@ class MountService extends IMountService.Stub @GuardedBy("mLock") private String mMoveTargetUuid; - private DiskInfo findDiskById(String id) { - synchronized (mLock) { - final DiskInfo disk = mDisks.get(id); - if (disk != null) { - return disk; - } - } - throw new IllegalArgumentException("No disk found for ID " + id); - } - private VolumeInfo findVolumeByIdOrThrow(String id) { synchronized (mLock) { final VolumeInfo vol = mVolumes.get(id); @@ -456,6 +449,9 @@ class MountService extends IMountService.Stub /** Map from raw paths to {@link ObbState}. */ final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>(); + // Not guarded by a lock. + private final MountServiceInternalImpl mMountServiceInternal = new MountServiceInternalImpl(); + class ObbState implements IBinder.DeathRecipient { public ObbState(String rawPath, String canonicalPath, int callingUid, IObbActionListener token, int nonce) { @@ -807,7 +803,7 @@ class MountService extends IMountService.Stub for (int i = 0; i < mVolumes.size(); i++) { final VolumeInfo vol = mVolumes.valueAt(i); if (vol.isVisibleToUser(userId) && vol.isMountedReadable()) { - final StorageVolume userVol = vol.buildStorageVolume(mContext, userId); + final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false); mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget(); final String envState = VolumeInfo.getEnvironmentForState(vol.getState()); @@ -1250,7 +1246,7 @@ class MountService extends IMountService.Stub // user-specific broadcasts. for (int userId : mStartedUsers) { if (vol.isVisibleToUser(userId)) { - final StorageVolume userVol = vol.buildStorageVolume(mContext, userId); + final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false); mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget(); mCallbacks.notifyStorageStateChanged(userVol.getPath(), oldStateEnv, @@ -1370,6 +1366,8 @@ class MountService extends IMountService.Stub readSettingsLocked(); } + LocalServices.addService(MountServiceInternal.class, mMountServiceInternal); + /* * Create the connection to vold with a maximum queue of twice the * amount of containers we'd ever expect to have. This keeps an @@ -1787,27 +1785,28 @@ class MountService extends IMountService.Stub } } - @Override - public void remountUid(int uid) { - enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); + private void remountUidExternalStorage(int uid, int mode) { waitForReady(); - final int mountExternal = mPms.getMountExternalMode(uid); - final String mode; - if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) { - mode = "default"; - } else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) { - mode = "read"; - } else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) { - mode = "write"; - } else { - mode = "none"; + String modeName = "none"; + switch (mode) { + case Zygote.MOUNT_EXTERNAL_DEFAULT: { + modeName = "default"; + } break; + + case Zygote.MOUNT_EXTERNAL_READ: { + modeName = "read"; + } break; + + case Zygote.MOUNT_EXTERNAL_WRITE: { + modeName = "write"; + } break; } try { - mConnector.execute("volume", "remount_uid", uid, mode); + mConnector.execute("volume", "remount_uid", uid, modeName); } catch (NativeDaemonConnectorException e) { - Slog.w(TAG, "Failed to remount UID " + uid + " as " + mode + ": " + e); + Slog.w(TAG, "Failed to remount UID " + uid + " as " + modeName + ": " + e); } } @@ -2598,15 +2597,20 @@ class MountService extends IMountService.Stub } @Override - public StorageVolume[] getVolumeList(int userId) { + public StorageVolume[] getVolumeList(int uid, String packageName) { final ArrayList<StorageVolume> res = new ArrayList<>(); boolean foundPrimary = false; + final int userId = UserHandle.getUserId(uid); + final boolean reportUnmounted = !mMountServiceInternal.hasExternalStorage( + uid, packageName); + synchronized (mLock) { for (int i = 0; i < mVolumes.size(); i++) { final VolumeInfo vol = mVolumes.valueAt(i); if (vol.isVisibleToUser(userId)) { - final StorageVolume userVol = vol.buildStorageVolume(mContext, userId); + final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, + reportUnmounted); if (vol.isPrimary()) { res.add(0, userVol); foundPrimary = true; @@ -3379,4 +3383,50 @@ class MountService extends IMountService.Stub mCryptConnector.monitor(); } } + + private final class MountServiceInternalImpl extends MountServiceInternal { + // Not guarded by a lock. + private final CopyOnWriteArrayList<ExternalStorageMountPolicy> mPolicies = + new CopyOnWriteArrayList<>(); + + @Override + public void addExternalStoragePolicy(ExternalStorageMountPolicy policy) { + // No locking - CopyOnWriteArrayList + mPolicies.add(policy); + } + + @Override + public void onExternalStoragePolicyChanged(int uid, String packageName) { + final int mountMode = getExternalStorageMountMode(uid, packageName); + remountUidExternalStorage(uid, mountMode); + } + + @Override + public int getExternalStorageMountMode(int uid, String packageName) { + // No locking - CopyOnWriteArrayList + int mountMode = Integer.MAX_VALUE; + for (ExternalStorageMountPolicy policy : mPolicies) { + final int policyMode = policy.getMountMode(uid, packageName); + if (policyMode == Zygote.MOUNT_EXTERNAL_NONE) { + return Zygote.MOUNT_EXTERNAL_NONE; + } + mountMode = Math.min(mountMode, policyMode); + } + if (mountMode == Integer.MAX_VALUE) { + return Zygote.MOUNT_EXTERNAL_NONE; + } + return mountMode; + } + + public boolean hasExternalStorage(int uid, String packageName) { + // No locking - CopyOnWriteArrayList + for (ExternalStorageMountPolicy policy : mPolicies) { + final boolean policyHasStorage = policy.hasExternalStorage(uid, packageName); + if (!policyHasStorage) { + return false; + } + } + return true; + } + } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 6e94647..5bfca10 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -18,7 +18,10 @@ package com.android.server.am; import static android.Manifest.permission.INTERACT_ACROSS_USERS; import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; +import static android.Manifest.permission.READ_EXTERNAL_STORAGE; import static android.Manifest.permission.START_TASKS_FROM_RECENTS; +import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE; +import static android.Manifest.permission.WRITE_MEDIA_STORAGE; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static com.android.internal.util.XmlUtils.readBooleanAttribute; import static com.android.internal.util.XmlUtils.readIntAttribute; @@ -62,6 +65,7 @@ import android.os.Trace; import android.os.TransactionTooLargeException; import android.os.WorkSource; import android.os.storage.IMountService; +import android.os.storage.MountServiceInternal; import android.os.storage.StorageManager; import android.service.voice.IVoiceInteractionSession; import android.util.ArrayMap; @@ -3219,7 +3223,10 @@ public final class ActivityManagerService extends ActivityManagerNative checkTime(startTime, "startProcess: getting gids from package manager"); final IPackageManager pm = AppGlobals.getPackageManager(); permGids = pm.getPackageGids(app.info.packageName, app.userId); - mountExternal = pm.getMountExternalMode(uid); + MountServiceInternal mountServiceInternal = LocalServices.getService( + MountServiceInternal.class); + mountExternal = mountServiceInternal.getExternalStorageMountMode(uid, + app.info.packageName); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 13aca79..6d76832 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -62,6 +62,7 @@ import static android.content.pm.PackageManager.MOVE_FAILED_DOESNT_EXIST; import static android.content.pm.PackageManager.MOVE_FAILED_INTERNAL_ERROR; import static android.content.pm.PackageManager.MOVE_FAILED_OPERATION_PENDING; import static android.content.pm.PackageManager.MOVE_FAILED_SYSTEM_PACKAGE; +import static android.content.pm.PackageManager.PERMISSION_DENIED; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.content.pm.PackageParser.isApkFile; import static android.os.Process.PACKAGE_INFO_GID; @@ -166,6 +167,7 @@ import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.os.storage.IMountService; +import android.os.storage.MountServiceInternal; import android.os.storage.StorageEventListener; import android.os.storage.StorageManager; import android.os.storage.VolumeInfo; @@ -2727,23 +2729,6 @@ public class PackageManagerService extends IPackageManager.Stub { return null; } - @Override - public int getMountExternalMode(int uid) { - if (Process.isIsolated(uid)) { - return Zygote.MOUNT_EXTERNAL_NONE; - } else { - if (checkUidPermission(WRITE_MEDIA_STORAGE, uid) == PERMISSION_GRANTED) { - return Zygote.MOUNT_EXTERNAL_DEFAULT; - } else if (checkUidPermission(WRITE_EXTERNAL_STORAGE, uid) == PERMISSION_GRANTED) { - return Zygote.MOUNT_EXTERNAL_WRITE; - } else if (checkUidPermission(READ_EXTERNAL_STORAGE, uid) == PERMISSION_GRANTED) { - return Zygote.MOUNT_EXTERNAL_READ; - } else { - return Zygote.MOUNT_EXTERNAL_DEFAULT; - } - } - } - static PermissionInfo generatePermissionInfo( BasePermission bp, int flags) { if (bp.perm != null) { @@ -3466,8 +3451,9 @@ public class PackageManagerService extends IPackageManager.Stub { final long token = Binder.clearCallingIdentity(); try { if (sUserManager.isInitialized(userId)) { - final StorageManager storage = mContext.getSystemService(StorageManager.class); - storage.remountUid(uid); + MountServiceInternal mountServiceInternal = LocalServices.getService( + MountServiceInternal.class); + mountServiceInternal.onExternalStoragePolicyChanged(uid, packageName); } } finally { Binder.restoreCallingIdentity(token); @@ -14439,6 +14425,33 @@ public class PackageManagerService extends IPackageManager.Stub { mInstallerService.systemReady(); mPackageDexOptimizer.systemReady(); + + MountServiceInternal mountServiceInternal = LocalServices.getService( + MountServiceInternal.class); + mountServiceInternal.addExternalStoragePolicy( + new MountServiceInternal.ExternalStorageMountPolicy() { + @Override + public int getMountMode(int uid, String packageName) { + if (Process.isIsolated(uid)) { + return Zygote.MOUNT_EXTERNAL_NONE; + } + if (checkUidPermission(WRITE_MEDIA_STORAGE, uid) == PERMISSION_GRANTED) { + return Zygote.MOUNT_EXTERNAL_DEFAULT; + } + if (checkUidPermission(READ_EXTERNAL_STORAGE, uid) == PERMISSION_DENIED) { + return Zygote.MOUNT_EXTERNAL_DEFAULT; + } + if (checkUidPermission(WRITE_EXTERNAL_STORAGE, uid) == PERMISSION_DENIED) { + return Zygote.MOUNT_EXTERNAL_READ; + } + return Zygote.MOUNT_EXTERNAL_WRITE; + } + + @Override + public boolean hasExternalStorage(int uid, String packageName) { + return true; + } + }); } @Override |