Merge "Active camera apps can defy reserved cache space." into oc-dr1-dev
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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_RESERVED = 1 << 1;
|
||||
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_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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user