Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7df4e1c5 authored by Zimuzo Ezeozue's avatar Zimuzo Ezeozue Committed by Android (Google) Code Review
Browse files

Merge "Add API to notify the system_server when app is blocked on I/O" into sc-dev

parents ea1be967 c534503a
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -214,6 +214,16 @@ package android.os {

}

package android.os.storage {

  public class StorageManager {
    method public void notifyAppIoBlocked(@NonNull String, int, int, int);
    method public void notifyAppIoResumed(@NonNull String, int, int, int);
    field public static final int APP_IO_BLOCKED_REASON_TRANSCODING = 0; // 0x0
  }

}

package android.provider {

  public final class DeviceConfig {
+3 −1
Original line number Diff line number Diff line
@@ -196,4 +196,6 @@ interface IStorageManager {
    void clearUserKeyAuth(int userId, int serialNumber, in byte[] token, in byte[] secret) = 88;
    void fixupAppDir(in String path) = 89;
    void disableAppDataIsolation(in String pkgName, int pid, int userId) = 90;
    void notifyAppIoBlocked(in String volumeUuid, int uid, int tid, int reason) = 91;
    void notifyAppIoResumed(in String volumeUuid, int uid, int tid, int reason) = 92;
    }
+74 −0
Original line number Diff line number Diff line
@@ -2699,6 +2699,80 @@ public class StorageManager {
        }
    }

    /**
     * Reason to provide if app IO is blocked/resumed because of transcoding
     *
     * @hide
     */
    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
    public static final int APP_IO_BLOCKED_REASON_TRANSCODING = 0;

    /**
     * Constants for use with
     * {@link #notifyAppIoBlocked} and {@link notifyAppIoResumed}, to specify the reason an app's
     * IO is blocked/resumed.
     *
     * @hide
     */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef(prefix = { "APP_IO_BLOCKED_REASON_" }, value = {
            APP_IO_BLOCKED_REASON_TRANSCODING
    })
    public @interface AppIoBlockedReason {}

    /**
     * Notify the system that an app with {@code uid} and {@code tid} is blocked on an IO request on
     * {@code volumeUuid} for {@code reason}.
     *
     * This blocked state can be used to modify the ANR behavior for the app while it's blocked.
     * For example during transcoding.
     *
     * This can only be called by the {@link ExternalStorageService} holding the
     * {@link android.Manifest.permission#WRITE_MEDIA_STORAGE} permission.
     *
     * @param volumeUuid the UUID of the storage volume that the app IO is blocked on
     * @param uid the UID of the app blocked on IO
     * @param tid the tid of the app blocked on IO
     * @param reason the reason the app is blocked on IO
     *
     * @hide
     */
    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
    public void notifyAppIoBlocked(@NonNull String volumeUuid, int uid, int tid,
            @AppIoBlockedReason int reason) {
        try {
            mStorageManager.notifyAppIoBlocked(volumeUuid, uid, tid, reason);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Notify the system that an app with {@code uid} and {@code tid} has resmued a previously
     * blocked IO request on {@code volumeUuid} for {@code reason}.
     *
     * All app IO will be automatically marked as unblocked if {@code volumeUuid} is unmounted.
     *
     * This can only be called by the {@link ExternalStorageService} holding the
     * {@link android.Manifest.permission#WRITE_MEDIA_STORAGE} permission.
     *
     * @param volumeUuid the UUID of the storage volume that the app IO is resumed on
     * @param uid the UID of the app resuming IO
     * @param tid the tid of the app resuming IO
     * @param reason the reason the app is resuming IO
     *
     * @hide
     */
    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
    public void notifyAppIoResumed(@NonNull String volumeUuid, int uid, int tid,
            @AppIoBlockedReason int reason) {
        try {
            mStorageManager.notifyAppIoResumed(volumeUuid, uid, tid, reason);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    private final Object mFuseAppLoopLock = new Object();

    @GuardedBy("mFuseAppLoopLock")
+33 −0
Original line number Diff line number Diff line
@@ -3338,6 +3338,39 @@ class StorageManagerService extends IStorageManager.Stub
        }
    }

    @Override
    public void notifyAppIoBlocked(String volumeUuid, int uid, int tid, int reason) {
        enforceExternalStorageService();

        mStorageSessionController.notifyAppIoBlocked(volumeUuid, uid, tid, reason);
    }

    @Override
    public void notifyAppIoResumed(String volumeUuid, int uid, int tid, int reason) {
        enforceExternalStorageService();

        mStorageSessionController.notifyAppIoResumed(volumeUuid, uid, tid, reason);
    }

    private boolean isAppIoBlocked(int uid) {
        return mStorageSessionController.isAppIoBlocked(uid);
    }

    /**
     * Enforces that the caller is the {@link ExternalStorageService}
     *
     * @throws SecurityException if the caller doesn't have the
     * {@link android.Manifest.permission.WRITE_MEDIA_STORAGE} permission or is not the
     * {@link ExternalStorageService}
     */
    private void enforceExternalStorageService() {
        enforcePermission(android.Manifest.permission.WRITE_MEDIA_STORAGE);
        int callingAppId = UserHandle.getAppId(Binder.getCallingUid());
        if (callingAppId != mMediaStoreAuthorityAppId) {
            throw new SecurityException("Only the ExternalStorageService is permitted");
        }
    }

    /** Not thread safe */
    class AppFuseMountScope extends AppFuseBridge.MountScope {
        private boolean mMounted = false;
+55 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.os.UserHandle;
import android.os.storage.StorageManager;
import android.os.storage.StorageVolume;
import android.os.storage.VolumeInfo;
import android.provider.MediaStore;
@@ -371,6 +372,60 @@ public final class StorageSessionController {
        return mExternalStorageServiceComponent;
    }

    /**
     * Notify the controller that an app with {@code uid} and {@code tid} is blocked on an IO
     * request on {@code volumeUuid} for {@code reason}.
     *
     * This blocked state can be queried with {@link #isAppIoBlocked}
     *
     * @hide
     */
    public void notifyAppIoBlocked(String volumeUuid, int uid, int tid,
            @StorageManager.AppIoBlockedReason int reason) {
        final int userId = UserHandle.getUserId(uid);
        final StorageUserConnection connection;
        synchronized (mLock) {
            connection = mConnections.get(userId);
        }

        if (connection != null) {
            connection.notifyAppIoBlocked(volumeUuid, uid, tid, reason);
        }
    }

    /**
     * Notify the controller that an app with {@code uid} and {@code tid} has resmed a previously
     * blocked IO request on {@code volumeUuid} for {@code reason}.
     *
     * All app IO will be automatically marked as unblocked if {@code volumeUuid} is unmounted.
     */
    public void notifyAppIoResumed(String volumeUuid, int uid, int tid,
            @StorageManager.AppIoBlockedReason int reason) {
        final int userId = UserHandle.getUserId(uid);
        final StorageUserConnection connection;
        synchronized (mLock) {
            connection = mConnections.get(userId);
        }

        if (connection != null) {
            connection.notifyAppIoResumed(volumeUuid, uid, tid, reason);
        }
    }

    /** Returns {@code true} if {@code uid} is blocked on IO, {@code false} otherwise */
    public boolean isAppIoBlocked(int uid) {
        final int userId = UserHandle.getUserId(uid);
        final StorageUserConnection connection;
        synchronized (mLock) {
            connection = mConnections.get(userId);
        }

        if (connection != null) {
            return connection.isAppIoBlocked(uid);
        }
        return false;
    }

    private void killExternalStorageService(int userId) {
        IActivityManager am = ActivityManager.getService();
        try {
Loading