Merge "Add freeCache API to ExternalStorageService"
This commit is contained in:
@@ -9777,6 +9777,7 @@ package android.service.storage {
|
||||
ctor public ExternalStorageService();
|
||||
method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent);
|
||||
method public abstract void onEndSession(@NonNull String) throws java.io.IOException;
|
||||
method public void onFreeCacheRequested(@NonNull java.util.UUID, long);
|
||||
method public abstract void onStartSession(@NonNull String, int, @NonNull android.os.ParcelFileDescriptor, @NonNull java.io.File, @NonNull java.io.File) throws java.io.IOException;
|
||||
method public abstract void onVolumeStateChanged(@NonNull android.os.storage.StorageVolume) throws java.io.IOException;
|
||||
field public static final int FLAG_SESSION_ATTRIBUTE_INDEXABLE = 2; // 0x2
|
||||
|
||||
@@ -101,4 +101,15 @@ public abstract class StorageManagerInternal {
|
||||
* Return true if uid is external storage service.
|
||||
*/
|
||||
public abstract boolean isExternalStorageService(int uid);
|
||||
|
||||
/**
|
||||
* Frees cache held by ExternalStorageService.
|
||||
*
|
||||
* <p> Blocks until the service frees the cache or fails in doing so.
|
||||
*
|
||||
* @param volumeUuid uuid of the {@link StorageVolume} from which cache needs to be freed,
|
||||
* null value indicates private internal volume.
|
||||
* @param bytes number of bytes which need to be freed
|
||||
*/
|
||||
public abstract void freeCache(@Nullable String volumeUuid, long bytes);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package android.service.storage;
|
||||
|
||||
import android.annotation.BytesLong;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.SdkConstant;
|
||||
@@ -29,6 +30,7 @@ import android.os.ParcelFileDescriptor;
|
||||
import android.os.ParcelableException;
|
||||
import android.os.RemoteCallback;
|
||||
import android.os.RemoteException;
|
||||
import android.os.storage.StorageManager;
|
||||
import android.os.storage.StorageVolume;
|
||||
|
||||
import com.android.internal.os.BackgroundThread;
|
||||
@@ -37,6 +39,7 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* A service to handle filesystem I/O from other apps.
|
||||
@@ -147,6 +150,18 @@ public abstract class ExternalStorageService extends Service {
|
||||
*/
|
||||
public abstract void onVolumeStateChanged(@NonNull StorageVolume vol) throws IOException;
|
||||
|
||||
/**
|
||||
* Called when any cache held by the ExternalStorageService needs to be freed.
|
||||
*
|
||||
* <p> Blocks until the service frees the cache or fails in doing so.
|
||||
*
|
||||
* @param volumeUuid uuid of the {@link StorageVolume} from which cache needs to be freed
|
||||
* @param bytes number of bytes which need to be freed
|
||||
*/
|
||||
public void onFreeCacheRequested(@NonNull UUID volumeUuid, @BytesLong long bytes) {
|
||||
throw new UnsupportedOperationException("onFreeCacheRequested not implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public final IBinder onBind(@NonNull Intent intent) {
|
||||
@@ -182,6 +197,19 @@ public abstract class ExternalStorageService extends Service {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void freeCache(String sessionId, String volumeUuid, long bytes,
|
||||
RemoteCallback callback) {
|
||||
mHandler.post(() -> {
|
||||
try {
|
||||
onFreeCacheRequested(StorageManager.convert(volumeUuid), bytes);
|
||||
sendResult(sessionId, null /* throwable */, callback);
|
||||
} catch (Throwable t) {
|
||||
sendResult(sessionId, t, callback);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endSession(String sessionId, RemoteCallback callback) throws RemoteException {
|
||||
mHandler.post(() -> {
|
||||
|
||||
@@ -30,4 +30,6 @@ oneway interface IExternalStorageService
|
||||
void endSession(@utf8InCpp String sessionId, in RemoteCallback callback);
|
||||
void notifyVolumeStateChanged(@utf8InCpp String sessionId, in StorageVolume vol,
|
||||
in RemoteCallback callback);
|
||||
void freeCache(@utf8InCpp String sessionId, in String volumeUuid, long bytes,
|
||||
in RemoteCallback callback);
|
||||
}
|
||||
@@ -4475,6 +4475,15 @@ class StorageManagerService extends IStorageManager.Stub
|
||||
return mMediaStoreAuthorityAppId == UserHandle.getAppId(uid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void freeCache(String volumeUuid, long freeBytes) {
|
||||
try {
|
||||
mStorageSessionController.freeCache(volumeUuid, freeBytes);
|
||||
} catch (ExternalStorageServiceException e) {
|
||||
Log.e(TAG, "Failed to free cache of vol : " + volumeUuid, e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasExternalStorage(int uid, String packageName) {
|
||||
// No need to check for system uid. This avoids a deadlock between
|
||||
// PackageManagerService and AppOpsService.
|
||||
|
||||
@@ -5417,6 +5417,14 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
InstantAppRegistry.DEFAULT_UNINSTALLED_INSTANT_APP_MIN_CACHE_PERIOD))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 11. Free storage service cache
|
||||
StorageManagerInternal smInternal =
|
||||
mInjector.getLocalService(StorageManagerInternal.class);
|
||||
// TODO(b/170481432): Decide what value of bytes needs to be sent instead of
|
||||
// sending the bytes parameter of freeStorage
|
||||
smInternal.freeCache(volumeUuid, bytes);
|
||||
if (file.getUsableSpace() >= bytes) return;
|
||||
} else {
|
||||
try {
|
||||
mInstaller.freeCache(volumeUuid, bytes, 0, 0);
|
||||
|
||||
@@ -32,6 +32,7 @@ import android.os.ParcelFileDescriptor;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceSpecificException;
|
||||
import android.os.UserHandle;
|
||||
import android.os.storage.StorageVolume;
|
||||
import android.os.storage.VolumeInfo;
|
||||
import android.provider.MediaStore;
|
||||
import android.service.storage.ExternalStorageService;
|
||||
@@ -133,6 +134,28 @@ public final class StorageSessionController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees any cache held by ExternalStorageService.
|
||||
*
|
||||
* <p> Blocks until the service frees the cache or fails in doing so.
|
||||
*
|
||||
* @param volumeUuid uuid of the {@link StorageVolume} from which cache needs to be freed
|
||||
* @param bytes number of bytes which need to be freed
|
||||
* @throws ExternalStorageServiceException if it fails to connect to ExternalStorageService
|
||||
*/
|
||||
public void freeCache(String volumeUuid, long bytes)
|
||||
throws ExternalStorageServiceException {
|
||||
synchronized (mLock) {
|
||||
int size = mConnections.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
int key = mConnections.keyAt(i);
|
||||
StorageUserConnection connection = mConnections.get(key);
|
||||
if (connection != null) {
|
||||
connection.freeCache(volumeUuid, bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes and returns the {@link StorageUserConnection} for {@code vol}.
|
||||
|
||||
@@ -124,6 +124,26 @@ public final class StorageUserConnection {
|
||||
mActiveConnection.notifyVolumeStateChanged(sessionId, vol);
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees any cache held by ExternalStorageService.
|
||||
*
|
||||
* <p> Blocks until the service frees the cache or fails in doing so.
|
||||
*
|
||||
* @param volumeUuid uuid of the {@link StorageVolume} from which cache needs to be freed
|
||||
* @param bytes number of bytes which need to be freed
|
||||
* @throws ExternalStorageServiceException if it fails to connect to ExternalStorageService
|
||||
*/
|
||||
public void freeCache(String volumeUuid, long bytes)
|
||||
throws ExternalStorageServiceException {
|
||||
Objects.requireNonNull(volumeUuid);
|
||||
|
||||
synchronized (mSessionsLock) {
|
||||
for (String sessionId : mSessions.keySet()) {
|
||||
mActiveConnection.freeCache(sessionId, volumeUuid, bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a session without ending it or waiting for exit.
|
||||
*
|
||||
@@ -214,7 +234,7 @@ public final class StorageUserConnection {
|
||||
// A list of outstanding futures for async calls, for which we are still waiting
|
||||
// for a callback. Used to unblock waiters if the service dies.
|
||||
@GuardedBy("mLock")
|
||||
private ArrayList<CompletableFuture<Void>> mOutstandingOps = new ArrayList<>();
|
||||
private final ArrayList<CompletableFuture<Void>> mOutstandingOps = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
@@ -309,6 +329,17 @@ public final class StorageUserConnection {
|
||||
}
|
||||
}
|
||||
|
||||
public void freeCache(String sessionId, String volumeUuid, long bytes)
|
||||
throws ExternalStorageServiceException {
|
||||
try {
|
||||
waitForAsync((service, callback) ->
|
||||
service.freeCache(sessionId, volumeUuid, bytes, callback));
|
||||
} catch (Exception e) {
|
||||
throw new ExternalStorageServiceException("Failed to free " + bytes
|
||||
+ " bytes for volumeUuid : " + volumeUuid, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void setResult(Bundle result, CompletableFuture<Void> future) {
|
||||
ParcelableException ex = result.getParcelable(EXTRA_ERROR);
|
||||
if (ex != null) {
|
||||
|
||||
Reference in New Issue
Block a user