summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Sharkey <jsharkey@google.com>2017-06-13 00:24:59 +0000
committerandroid-build-merger <android-build-merger@google.com>2017-06-13 00:24:59 +0000
commitdc292b6003c80aa954bd82ca06d1b4eec271144e (patch)
treef7f6f40893bbea008a7b3ee42e798ce02a3a7528
parentb8b6f00b759e467f083831470870ad0848fdcbe5 (diff)
parentde624f3fbbce27ed614b954988f1f6e39d92e6ed (diff)
Merge "Active camera apps can defy reserved cache space." into oc-dr1-dev am: f7dc56ecc9
am: de624f3fbb Change-Id: I0a125a6c00220ba280dca4e0d8ece88202a68afe
-rw-r--r--cmds/pm/src/com/android/commands/pm/Pm.java2
-rw-r--r--core/java/android/app/AppOpsManager.java9
-rw-r--r--core/java/android/os/storage/IStorageManager.aidl4
-rw-r--r--core/java/android/os/storage/StorageManager.java36
-rw-r--r--core/java/com/android/internal/app/IAppOpsService.aidl2
-rw-r--r--services/core/java/com/android/server/AppOpsService.java22
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java64
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/MockStorageManager.java5
-rw-r--r--services/usage/java/com/android/server/usage/StorageStatsService.java2
10 files changed, 107 insertions, 44 deletions
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 9813cb1631ce..ad989dee7b55 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -1473,7 +1473,7 @@ public final class Pm {
ClearDataObserver obs = new ClearDataObserver();
try {
mPm.freeStorageAndNotify(volumeUuid, sizeVal,
- StorageManager.FLAG_ALLOCATE_DEFY_RESERVED, obs);
+ StorageManager.FLAG_ALLOCATE_DEFY_ALL_RESERVED, obs);
synchronized (obs) {
while (!obs.finished) {
try {
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index e672ada3cbb4..b331d84010d0 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1947,4 +1947,13 @@ public class AppOpsManager {
public void finishOp(int op) {
finishOp(op, Process.myUid(), mContext.getOpPackageName());
}
+
+ /** @hide */
+ public boolean isOperationActive(int code, int uid, String packageName) {
+ try {
+ return mService.isOperationActive(code, uid, packageName);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index 92f7f319a14b..50855bb349d9 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -293,7 +293,7 @@ interface IStorageManager {
ParcelFileDescriptor openProxyFileDescriptor(int mountPointId, int fileId, int mode) = 74;
long getCacheQuotaBytes(String volumeUuid, int uid) = 75;
long getCacheSizeBytes(String volumeUuid, int uid) = 76;
- long getAllocatableBytes(String volumeUuid, int flags) = 77;
- void allocateBytes(String volumeUuid, long bytes, int flags) = 78;
+ long getAllocatableBytes(String volumeUuid, int flags, String callingPackage) = 77;
+ void allocateBytes(String volumeUuid, long bytes, int flags, String callingPackage) = 78;
void secdiscard(in String path) = 79;
}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 504673529238..ca7c73903481 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1174,7 +1174,7 @@ public class StorageManager {
*
* @hide
*/
- public long getStorageCacheBytes(File path) {
+ public long getStorageCacheBytes(File path, @AllocateFlags int flags) {
final long cachePercent = Settings.Global.getInt(mResolver,
Settings.Global.SYS_STORAGE_CACHE_PERCENTAGE, DEFAULT_CACHE_PERCENTAGE);
final long cacheBytes = (path.getTotalSpace() * cachePercent) / 100;
@@ -1182,7 +1182,16 @@ public class StorageManager {
final long maxCacheBytes = Settings.Global.getLong(mResolver,
Settings.Global.SYS_STORAGE_CACHE_MAX_BYTES, DEFAULT_CACHE_MAX_BYTES);
- return Math.min(cacheBytes, maxCacheBytes);
+ final long result = Math.min(cacheBytes, maxCacheBytes);
+ if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) {
+ return 0;
+ } else if ((flags & StorageManager.FLAG_ALLOCATE_DEFY_ALL_RESERVED) != 0) {
+ return 0;
+ } else if ((flags & StorageManager.FLAG_ALLOCATE_DEFY_HALF_RESERVED) != 0) {
+ return result / 2;
+ } else {
+ return result;
+ }
}
/**
@@ -1628,17 +1637,26 @@ public class StorageManager {
public static final int FLAG_ALLOCATE_AGGRESSIVE = 1 << 0;
/**
- * Flag indicating that a disk space allocation request should defy any
- * reserved disk space.
+ * Flag indicating that a disk space allocation request should be allowed to
+ * clear up to all reserved disk space.
+ *
+ * @hide
+ */
+ public static final int FLAG_ALLOCATE_DEFY_ALL_RESERVED = 1 << 1;
+
+ /**
+ * Flag indicating that a disk space allocation request should be allowed to
+ * clear up to half of all reserved disk space.
*
* @hide
*/
- public static final int FLAG_ALLOCATE_DEFY_RESERVED = 1 << 1;
+ public static final int FLAG_ALLOCATE_DEFY_HALF_RESERVED = 1 << 2;
/** @hide */
@IntDef(flag = true, value = {
FLAG_ALLOCATE_AGGRESSIVE,
- FLAG_ALLOCATE_DEFY_RESERVED,
+ FLAG_ALLOCATE_DEFY_ALL_RESERVED,
+ FLAG_ALLOCATE_DEFY_HALF_RESERVED,
})
@Retention(RetentionPolicy.SOURCE)
public @interface AllocateFlags {}
@@ -1688,7 +1706,8 @@ public class StorageManager {
public long getAllocatableBytes(@NonNull UUID storageUuid,
@RequiresPermission @AllocateFlags int flags) throws IOException {
try {
- return mStorageManager.getAllocatableBytes(convert(storageUuid), flags);
+ return mStorageManager.getAllocatableBytes(convert(storageUuid), flags,
+ mContext.getOpPackageName());
} catch (ParcelableException e) {
e.maybeRethrow(IOException.class);
throw new RuntimeException(e);
@@ -1738,7 +1757,8 @@ public class StorageManager {
public void allocateBytes(@NonNull UUID storageUuid, @BytesLong long bytes,
@RequiresPermission @AllocateFlags int flags) throws IOException {
try {
- mStorageManager.allocateBytes(convert(storageUuid), bytes, flags);
+ mStorageManager.allocateBytes(convert(storageUuid), bytes, flags,
+ mContext.getOpPackageName());
} catch (ParcelableException e) {
e.maybeRethrow(IOException.class);
} catch (RemoteException e) {
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 35d4ba81bd69..7a119b4351c0 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -48,4 +48,6 @@ interface IAppOpsService {
void setUserRestrictions(in Bundle restrictions, IBinder token, int userHandle);
void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle, in String[] exceptionPackages);
void removeUser(int userHandle);
+
+ boolean isOperationActive(int code, int uid, String packageName);
}
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index 1a5ec61a1510..c8e6e2efb240 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -2445,6 +2445,28 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}
+ @Override
+ public boolean isOperationActive(int code, int uid, String packageName) {
+ verifyIncomingUid(uid);
+ verifyIncomingOp(code);
+ String resolvedPackageName = resolvePackageName(uid, packageName);
+ if (resolvedPackageName == null) {
+ return false;
+ }
+ synchronized (this) {
+ for (int i = mClients.size() - 1; i >= 0; i--) {
+ final ClientState client = mClients.valueAt(i);
+ if (client.mStartedOps == null) continue;
+
+ for (int j = client.mStartedOps.size() - 1; j >= 0; j--) {
+ final Op op = client.mStartedOps.get(j);
+ if (op.op == code && op.uid == uid) return true;
+ }
+ }
+ }
+ return false;
+ }
+
private void removeUidsForUserLocked(int userHandle) {
for (int i = mUidStates.size() - 1; i >= 0; --i) {
final int uid = mUidStates.keyAt(i);
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 35b452a12e64..f718e803a973 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -90,14 +90,12 @@ import android.util.AtomicFile;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
-import android.util.SparseArray;
import android.util.TimeUtils;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IMediaContainerService;
import com.android.internal.os.AppFuseMount;
-import com.android.internal.os.FuseAppLoop;
import com.android.internal.os.FuseUnavailableMountException;
import com.android.internal.os.SomeArgs;
import com.android.internal.os.Zygote;
@@ -143,7 +141,6 @@ import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
-import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -3291,20 +3288,41 @@ class StorageManagerService extends IStorageManager.Stub
}
}
- @Override
- public long getAllocatableBytes(String volumeUuid, int flags) {
- final StorageManager storage = mContext.getSystemService(StorageManager.class);
- final StorageStatsManager stats = mContext.getSystemService(StorageStatsManager.class);
-
- // Apps can't defy reserved space
- flags &= ~StorageManager.FLAG_ALLOCATE_DEFY_RESERVED;
-
- final boolean aggressive = (flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0;
- if (aggressive) {
+ private int adjustAllocateFlags(int flags, int callingUid, String callingPackage) {
+ // Require permission to allocate aggressively
+ if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.ALLOCATE_AGGRESSIVE, TAG);
}
+ // Apps normally can't directly defy reserved space
+ flags &= ~StorageManager.FLAG_ALLOCATE_DEFY_ALL_RESERVED;
+ flags &= ~StorageManager.FLAG_ALLOCATE_DEFY_HALF_RESERVED;
+
+ // However, if app is actively using the camera, then we're willing to
+ // clear up to half of the reserved cache space, since the user might be
+ // trying to capture an important memory.
+ final AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ if (appOps.isOperationActive(AppOpsManager.OP_CAMERA, callingUid, callingPackage)) {
+ Slog.d(TAG, "UID " + callingUid + " is actively using camera;"
+ + " letting them defy reserved cached data");
+ flags |= StorageManager.FLAG_ALLOCATE_DEFY_HALF_RESERVED;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+
+ return flags;
+ }
+
+ @Override
+ public long getAllocatableBytes(String volumeUuid, int flags, String callingPackage) {
+ flags = adjustAllocateFlags(flags, Binder.getCallingUid(), callingPackage);
+
+ final StorageManager storage = mContext.getSystemService(StorageManager.class);
+ final StorageStatsManager stats = mContext.getSystemService(StorageStatsManager.class);
final long token = Binder.clearCallingIdentity();
try {
// In general, apps can allocate as much space as they want, except
@@ -3319,18 +3337,18 @@ class StorageManagerService extends IStorageManager.Stub
if (stats.isQuotaSupported(volumeUuid)) {
final long cacheTotal = stats.getCacheBytes(volumeUuid);
- final long cacheReserved = storage.getStorageCacheBytes(path);
+ final long cacheReserved = storage.getStorageCacheBytes(path, flags);
final long cacheClearable = Math.max(0, cacheTotal - cacheReserved);
- if (aggressive) {
- return Math.max(0, (usable + cacheTotal) - fullReserved);
+ if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) {
+ return Math.max(0, (usable + cacheClearable) - fullReserved);
} else {
return Math.max(0, (usable + cacheClearable) - lowReserved);
}
} else {
// When we don't have fast quota information, we ignore cached
// data and only consider unused bytes.
- if (aggressive) {
+ if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) {
return Math.max(0, usable - fullReserved);
} else {
return Math.max(0, usable - lowReserved);
@@ -3344,20 +3362,16 @@ class StorageManagerService extends IStorageManager.Stub
}
@Override
- public void allocateBytes(String volumeUuid, long bytes, int flags) {
- final StorageManager storage = mContext.getSystemService(StorageManager.class);
+ public void allocateBytes(String volumeUuid, long bytes, int flags, String callingPackage) {
+ flags = adjustAllocateFlags(flags, Binder.getCallingUid(), callingPackage);
- // Apps can't defy reserved space
- flags &= ~StorageManager.FLAG_ALLOCATE_DEFY_RESERVED;
-
- // This method call will enforce FLAG_ALLOCATE_AGGRESSIVE permissions so
- // we don't have to enforce them locally
- final long allocatableBytes = getAllocatableBytes(volumeUuid, flags);
+ final long allocatableBytes = getAllocatableBytes(volumeUuid, flags, callingPackage);
if (bytes > allocatableBytes) {
throw new ParcelableException(new IOException("Failed to allocate " + bytes
+ " because only " + allocatableBytes + " allocatable"));
}
+ final StorageManager storage = mContext.getSystemService(StorageManager.class);
final long token = Binder.clearCallingIdentity();
try {
// Free up enough disk space to satisfy both the requested allocation
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 48b9c7de650b..9c04801c056b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -4258,10 +4258,7 @@ public class PackageManagerService extends IPackageManager.Stub
volumeUuid);
final boolean aggressive = (storageFlags
& StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0;
- final boolean defyReserved = (storageFlags
- & StorageManager.FLAG_ALLOCATE_DEFY_RESERVED) != 0;
- final long reservedBytes = (aggressive || defyReserved) ? 0
- : storage.getStorageCacheBytes(file);
+ final long reservedBytes = storage.getStorageCacheBytes(file, storageFlags);
// 1. Pre-flight to determine if we have any chance to succeed
// 2. Consider preloaded data (after 1w honeymoon, unless aggressive)
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/MockStorageManager.java b/services/tests/servicestests/src/com/android/server/locksettings/MockStorageManager.java
index 89e18b4c2f41..40e114bfaef2 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/MockStorageManager.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/MockStorageManager.java
@@ -491,12 +491,12 @@ public class MockStorageManager implements IStorageManager {
}
@Override
- public long getAllocatableBytes(String path, int flags) {
+ public long getAllocatableBytes(String path, int flags, String callingPackage) {
throw new UnsupportedOperationException();
}
@Override
- public void allocateBytes(String path, long bytes, int flags) {
+ public void allocateBytes(String path, long bytes, int flags, String callingPackage) {
throw new UnsupportedOperationException();
}
@@ -504,5 +504,4 @@ public class MockStorageManager implements IStorageManager {
public void secdiscard(String path) throws RemoteException {
throw new UnsupportedOperationException();
}
-
}
diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java
index 562443f53546..9f4fb85f64c4 100644
--- a/services/usage/java/com/android/server/usage/StorageStatsService.java
+++ b/services/usage/java/com/android/server/usage/StorageStatsService.java
@@ -197,7 +197,7 @@ public class StorageStatsService extends IStorageStatsManager.Stub {
// logic should be kept in sync with getAllocatableBytes().
if (isQuotaSupported(volumeUuid, callingPackage)) {
final long cacheTotal = getCacheBytes(volumeUuid, callingPackage);
- final long cacheReserved = mStorage.getStorageCacheBytes(path);
+ final long cacheReserved = mStorage.getStorageCacheBytes(path, 0);
final long cacheClearable = Math.max(0, cacheTotal - cacheReserved);
return path.getUsableSpace() + cacheClearable;