Loading api/system-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -10183,6 +10183,7 @@ package android.service.storage { 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 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 field public static final int FLAG_SESSION_TYPE_FUSE = 1; // 0x1 field public static final String SERVICE_INTERFACE = "android.service.storage.ExternalStorageService"; core/java/android/service/storage/ExternalStorageService.java +31 −2 Original line number Diff line number Diff line Loading @@ -25,11 +25,13 @@ import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.ParcelFileDescriptor; import android.os.ParcelableException; import android.os.RemoteCallback; import android.os.RemoteException; import android.os.storage.StorageVolume; import com.android.internal.os.BackgroundThread; import java.io.File; import java.io.IOException; Loading Loading @@ -97,7 +99,7 @@ public abstract class ExternalStorageService extends Service { public @interface SessionFlag {} private final ExternalStorageServiceWrapper mWrapper = new ExternalStorageServiceWrapper(); private final Handler mHandler = new Handler(Looper.getMainLooper(), null, true); private final Handler mHandler = BackgroundThread.getHandler(); /** * Called when the system starts a session associated with {@code deviceFd} Loading Loading @@ -131,6 +133,20 @@ public abstract class ExternalStorageService extends Service { */ public abstract void onEndSession(@NonNull String sessionId) throws IOException; /** * Called when any volume's state changes. * * <p> This is required to communicate volume state changes with the Storage Service before * broadcasting to other apps. The Storage Service needs to process any change in the volume * state (before other apps receive a broadcast for the same) to update the database so that * other apps have the correct view of the volume. * * <p> Blocks until the Storage Service processes/scans the volume or fails in doing so. * * @param vol name of the volume that was changed */ public abstract void onVolumeStateChanged(@NonNull StorageVolume vol) throws IOException; @Override @NonNull public final IBinder onBind(@NonNull Intent intent) { Loading @@ -153,6 +169,19 @@ public abstract class ExternalStorageService extends Service { }); } @Override public void notifyVolumeStateChanged(String sessionId, StorageVolume vol, RemoteCallback callback) { mHandler.post(() -> { try { onVolumeStateChanged(vol); sendResult(sessionId, null /* throwable */, callback); } catch (Throwable t) { sendResult(sessionId, t, callback); } }); } @Override public void endSession(String sessionId, RemoteCallback callback) throws RemoteException { mHandler.post(() -> { Loading core/java/android/service/storage/IExternalStorageService.aidl +3 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package android.service.storage; import android.os.ParcelFileDescriptor; import android.os.RemoteCallback; import android.os.storage.StorageVolume; /** * @hide Loading @@ -27,4 +28,6 @@ oneway interface IExternalStorageService void startSession(@utf8InCpp String sessionId, int type, in ParcelFileDescriptor deviceFd, @utf8InCpp String upperPath, @utf8InCpp String lowerPath, in RemoteCallback callback); void endSession(@utf8InCpp String sessionId, in RemoteCallback callback); void notifyVolumeStateChanged(@utf8InCpp String sessionId, in StorageVolume vol, in RemoteCallback callback); } No newline at end of file services/core/java/com/android/server/StorageManagerService.java +84 −63 Original line number Diff line number Diff line Loading @@ -682,6 +682,7 @@ class StorageManagerService extends IStorageManager.Stub private static final int H_ABORT_IDLE_MAINT = 12; private static final int H_BOOT_COMPLETED = 13; private static final int H_COMPLETE_UNLOCK_USER = 14; private static final int H_VOLUME_STATE_CHANGED = 15; class StorageManagerServiceHandler extends Handler { public StorageManagerServiceHandler(Looper looper) { Loading Loading @@ -805,6 +806,11 @@ class StorageManagerService extends IStorageManager.Stub completeUnlockUser((int) msg.obj); break; } case H_VOLUME_STATE_CHANGED: { final SomeArgs args = (SomeArgs) msg.obj; onVolumeStateChangedInternal((VolumeInfo) args.arg1, (int) args.arg2, (int) args.arg3); } } } } Loading Loading @@ -1323,7 +1329,11 @@ class StorageManagerService extends IStorageManager.Stub final int oldState = vol.state; final int newState = state; vol.state = newState; onVolumeStateChangedLocked(vol, oldState, newState); final SomeArgs args = SomeArgs.obtain(); args.arg1 = vol; args.arg2 = oldState; args.arg3 = newState; mHandler.obtainMessage(H_VOLUME_STATE_CHANGED, args).sendToTarget(); } } } Loading Loading @@ -1496,8 +1506,8 @@ class StorageManagerService extends IStorageManager.Stub return true; } @GuardedBy("mLock") private void onVolumeStateChangedLocked(VolumeInfo vol, int oldState, int newState) { private void onVolumeStateChangedInternal(VolumeInfo vol, int oldState, int newState) { synchronized (mLock) { if (vol.type == VolumeInfo.TYPE_EMULATED && newState != VolumeInfo.STATE_MOUNTED) { mFuseMountedUser.remove(vol.getMountUserId()); } Loading @@ -1523,7 +1533,16 @@ class StorageManagerService extends IStorageManager.Stub rec.lastSeenMillis = System.currentTimeMillis(); writeSettingsLocked(); } } // This is a blocking call to Storage Service which needs to process volume state changed // before notifying other listeners. // Intentionally called without the mLock to avoid deadlocking from the Storage Service. try { mStorageSessionController.notifyVolumeStateChanged(vol); } catch (ExternalStorageServiceException e) { Log.e(TAG, "Failed to notify volume state changed to the Storage Service", e); } synchronized (mLock) { mCallbacks.notifyVolumeStateChanged(vol, oldState, newState); // Do not broadcast before boot has completed to avoid launching the Loading @@ -1547,7 +1566,8 @@ class StorageManagerService extends IStorageManager.Stub // user-specific broadcasts. for (int userId : mSystemUnlockedUsers) { if (vol.isVisibleForRead(userId)) { final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false); final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false); mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget(); mCallbacks.notifyStorageStateChanged(userVol.getPath(), oldStateEnv, Loading @@ -1569,6 +1589,7 @@ class StorageManagerService extends IStorageManager.Stub } maybeLogMediaMount(vol, newState); } } private void maybeLogMediaMount(VolumeInfo vol, int newState) { if (!SecurityLog.isLoggingEnabled()) { Loading services/core/java/com/android/server/storage/StorageSessionController.java +32 −0 Original line number Diff line number Diff line Loading @@ -105,6 +105,38 @@ public final class StorageSessionController { } } /** * Notifies the Storage Service that volume state for {@code vol} is changed. * A session may already be created for this volume if it is mounted before or the volume state * has changed to mounted. * * Does nothing if {@link #shouldHandle} is {@code false} * * Blocks until the Storage Service processes/scans the volume or fails in doing so. * * @throws ExternalStorageServiceException if it fails to connect to ExternalStorageService */ public void notifyVolumeStateChanged(VolumeInfo vol) throws ExternalStorageServiceException { if (!shouldHandle(vol)) { return; } String sessionId = vol.getId(); int userId = vol.getMountUserId(); StorageUserConnection connection = null; synchronized (mLock) { connection = mConnections.get(userId); if (connection != null) { Slog.i(TAG, "Notifying volume state changed for session with id: " + sessionId); connection.notifyVolumeStateChanged(sessionId, vol.buildStorageVolume(mContext, userId, false)); } else { Slog.w(TAG, "No available storage user connection for userId : " + userId); } } } /** * Removes and returns the {@link StorageUserConnection} for {@code vol}. * Loading Loading
api/system-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -10183,6 +10183,7 @@ package android.service.storage { 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 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 field public static final int FLAG_SESSION_TYPE_FUSE = 1; // 0x1 field public static final String SERVICE_INTERFACE = "android.service.storage.ExternalStorageService";
core/java/android/service/storage/ExternalStorageService.java +31 −2 Original line number Diff line number Diff line Loading @@ -25,11 +25,13 @@ import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.ParcelFileDescriptor; import android.os.ParcelableException; import android.os.RemoteCallback; import android.os.RemoteException; import android.os.storage.StorageVolume; import com.android.internal.os.BackgroundThread; import java.io.File; import java.io.IOException; Loading Loading @@ -97,7 +99,7 @@ public abstract class ExternalStorageService extends Service { public @interface SessionFlag {} private final ExternalStorageServiceWrapper mWrapper = new ExternalStorageServiceWrapper(); private final Handler mHandler = new Handler(Looper.getMainLooper(), null, true); private final Handler mHandler = BackgroundThread.getHandler(); /** * Called when the system starts a session associated with {@code deviceFd} Loading Loading @@ -131,6 +133,20 @@ public abstract class ExternalStorageService extends Service { */ public abstract void onEndSession(@NonNull String sessionId) throws IOException; /** * Called when any volume's state changes. * * <p> This is required to communicate volume state changes with the Storage Service before * broadcasting to other apps. The Storage Service needs to process any change in the volume * state (before other apps receive a broadcast for the same) to update the database so that * other apps have the correct view of the volume. * * <p> Blocks until the Storage Service processes/scans the volume or fails in doing so. * * @param vol name of the volume that was changed */ public abstract void onVolumeStateChanged(@NonNull StorageVolume vol) throws IOException; @Override @NonNull public final IBinder onBind(@NonNull Intent intent) { Loading @@ -153,6 +169,19 @@ public abstract class ExternalStorageService extends Service { }); } @Override public void notifyVolumeStateChanged(String sessionId, StorageVolume vol, RemoteCallback callback) { mHandler.post(() -> { try { onVolumeStateChanged(vol); sendResult(sessionId, null /* throwable */, callback); } catch (Throwable t) { sendResult(sessionId, t, callback); } }); } @Override public void endSession(String sessionId, RemoteCallback callback) throws RemoteException { mHandler.post(() -> { Loading
core/java/android/service/storage/IExternalStorageService.aidl +3 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package android.service.storage; import android.os.ParcelFileDescriptor; import android.os.RemoteCallback; import android.os.storage.StorageVolume; /** * @hide Loading @@ -27,4 +28,6 @@ oneway interface IExternalStorageService void startSession(@utf8InCpp String sessionId, int type, in ParcelFileDescriptor deviceFd, @utf8InCpp String upperPath, @utf8InCpp String lowerPath, in RemoteCallback callback); void endSession(@utf8InCpp String sessionId, in RemoteCallback callback); void notifyVolumeStateChanged(@utf8InCpp String sessionId, in StorageVolume vol, in RemoteCallback callback); } No newline at end of file
services/core/java/com/android/server/StorageManagerService.java +84 −63 Original line number Diff line number Diff line Loading @@ -682,6 +682,7 @@ class StorageManagerService extends IStorageManager.Stub private static final int H_ABORT_IDLE_MAINT = 12; private static final int H_BOOT_COMPLETED = 13; private static final int H_COMPLETE_UNLOCK_USER = 14; private static final int H_VOLUME_STATE_CHANGED = 15; class StorageManagerServiceHandler extends Handler { public StorageManagerServiceHandler(Looper looper) { Loading Loading @@ -805,6 +806,11 @@ class StorageManagerService extends IStorageManager.Stub completeUnlockUser((int) msg.obj); break; } case H_VOLUME_STATE_CHANGED: { final SomeArgs args = (SomeArgs) msg.obj; onVolumeStateChangedInternal((VolumeInfo) args.arg1, (int) args.arg2, (int) args.arg3); } } } } Loading Loading @@ -1323,7 +1329,11 @@ class StorageManagerService extends IStorageManager.Stub final int oldState = vol.state; final int newState = state; vol.state = newState; onVolumeStateChangedLocked(vol, oldState, newState); final SomeArgs args = SomeArgs.obtain(); args.arg1 = vol; args.arg2 = oldState; args.arg3 = newState; mHandler.obtainMessage(H_VOLUME_STATE_CHANGED, args).sendToTarget(); } } } Loading Loading @@ -1496,8 +1506,8 @@ class StorageManagerService extends IStorageManager.Stub return true; } @GuardedBy("mLock") private void onVolumeStateChangedLocked(VolumeInfo vol, int oldState, int newState) { private void onVolumeStateChangedInternal(VolumeInfo vol, int oldState, int newState) { synchronized (mLock) { if (vol.type == VolumeInfo.TYPE_EMULATED && newState != VolumeInfo.STATE_MOUNTED) { mFuseMountedUser.remove(vol.getMountUserId()); } Loading @@ -1523,7 +1533,16 @@ class StorageManagerService extends IStorageManager.Stub rec.lastSeenMillis = System.currentTimeMillis(); writeSettingsLocked(); } } // This is a blocking call to Storage Service which needs to process volume state changed // before notifying other listeners. // Intentionally called without the mLock to avoid deadlocking from the Storage Service. try { mStorageSessionController.notifyVolumeStateChanged(vol); } catch (ExternalStorageServiceException e) { Log.e(TAG, "Failed to notify volume state changed to the Storage Service", e); } synchronized (mLock) { mCallbacks.notifyVolumeStateChanged(vol, oldState, newState); // Do not broadcast before boot has completed to avoid launching the Loading @@ -1547,7 +1566,8 @@ class StorageManagerService extends IStorageManager.Stub // user-specific broadcasts. for (int userId : mSystemUnlockedUsers) { if (vol.isVisibleForRead(userId)) { final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false); final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false); mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget(); mCallbacks.notifyStorageStateChanged(userVol.getPath(), oldStateEnv, Loading @@ -1569,6 +1589,7 @@ class StorageManagerService extends IStorageManager.Stub } maybeLogMediaMount(vol, newState); } } private void maybeLogMediaMount(VolumeInfo vol, int newState) { if (!SecurityLog.isLoggingEnabled()) { Loading
services/core/java/com/android/server/storage/StorageSessionController.java +32 −0 Original line number Diff line number Diff line Loading @@ -105,6 +105,38 @@ public final class StorageSessionController { } } /** * Notifies the Storage Service that volume state for {@code vol} is changed. * A session may already be created for this volume if it is mounted before or the volume state * has changed to mounted. * * Does nothing if {@link #shouldHandle} is {@code false} * * Blocks until the Storage Service processes/scans the volume or fails in doing so. * * @throws ExternalStorageServiceException if it fails to connect to ExternalStorageService */ public void notifyVolumeStateChanged(VolumeInfo vol) throws ExternalStorageServiceException { if (!shouldHandle(vol)) { return; } String sessionId = vol.getId(); int userId = vol.getMountUserId(); StorageUserConnection connection = null; synchronized (mLock) { connection = mConnections.get(userId); if (connection != null) { Slog.i(TAG, "Notifying volume state changed for session with id: " + sessionId); connection.notifyVolumeStateChanged(sessionId, vol.buildStorageVolume(mContext, userId, false)); } else { Slog.w(TAG, "No available storage user connection for userId : " + userId); } } } /** * Removes and returns the {@link StorageUserConnection} for {@code vol}. * Loading