Implement ANR delay with app IO blocked reason
The ExternalStorageService now notifies the system_server of app IO blocked reasons, specifically transcoding. If an ANR occurs, we query these reasons for the uid to modify the ANR dialog behavior Bug: 170486601 Test: Manual Change-Id: I86f800c4a6c565a7bced0f2a5c5da7ba6c048168
This commit is contained in:
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.os.IVold;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@@ -112,4 +113,10 @@ public abstract class StorageManagerInternal {
|
||||
* @param bytes number of bytes which need to be freed
|
||||
*/
|
||||
public abstract void freeCache(@Nullable String volumeUuid, long bytes);
|
||||
|
||||
/**
|
||||
* Returns the {@link VolumeInfo#getId()} values for the volumes matching
|
||||
* {@link VolumeInfo#isPrimary()}
|
||||
*/
|
||||
public abstract List<String> getPrimaryVolumeIds();
|
||||
}
|
||||
|
||||
@@ -573,6 +573,12 @@ class StorageManagerService extends IStorageManager.Stub
|
||||
*/
|
||||
private static final int PBKDF2_HASH_ROUNDS = 1024;
|
||||
|
||||
private static final String ANR_DELAY_MILLIS_DEVICE_CONFIG_KEY =
|
||||
"anr_delay_millis";
|
||||
|
||||
private static final String ANR_DELAY_NOTIFY_EXTERNAL_STORAGE_SERVICE_DEVICE_CONFIG_KEY =
|
||||
"anr_delay_notify_external_storage_service";
|
||||
|
||||
/**
|
||||
* Mounted OBB tracking information. Used to track the current state of all
|
||||
* OBBs.
|
||||
@@ -943,25 +949,51 @@ class StorageManagerService extends IStorageManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(b/170486601): Check transcoding status based on events pushed from the MediaProvider
|
||||
private class ExternalStorageServiceAnrController implements AnrController {
|
||||
@Override
|
||||
public long getAnrDelayMillis(String packageName, int uid) {
|
||||
int delay = SystemProperties.getInt("sys.fuse.transcode_anr_delay", 0);
|
||||
Log.d(TAG, "getAnrDelayMillis: " + packageName + ". Delaying for " + delay + "ms");
|
||||
if (!isAppIoBlocked(uid)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int delay = DeviceConfig.getInt(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
|
||||
ANR_DELAY_MILLIS_DEVICE_CONFIG_KEY, 0);
|
||||
Slog.v(TAG, "getAnrDelayMillis for " + packageName + ". " + delay + "ms");
|
||||
return delay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnrDelayStarted(String packageName, int uid) {
|
||||
Log.d(TAG, "onAnrDelayStarted: " + packageName);
|
||||
if (!isAppIoBlocked(uid)) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean notifyExternalStorageService = DeviceConfig.getBoolean(
|
||||
DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
|
||||
ANR_DELAY_NOTIFY_EXTERNAL_STORAGE_SERVICE_DEVICE_CONFIG_KEY, true);
|
||||
if (notifyExternalStorageService) {
|
||||
Slog.d(TAG, "onAnrDelayStarted for " + packageName
|
||||
+ ". Notifying external storage service");
|
||||
try {
|
||||
mStorageSessionController.notifyAnrDelayStarted(packageName, uid, 0 /* tid */,
|
||||
StorageManager.APP_IO_BLOCKED_REASON_TRANSCODING);
|
||||
} catch (ExternalStorageServiceException e) {
|
||||
Slog.e(TAG, "Failed to notify ANR delay started for " + packageName, e);
|
||||
}
|
||||
} else {
|
||||
// TODO(b/170973510): Implement framework spinning dialog for ANR delay
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onAnrDelayCompleted(String packageName, int uid) {
|
||||
boolean show = SystemProperties.getBoolean("sys.fuse.transcode_anr_dialog_show", true);
|
||||
Log.d(TAG, "onAnrDelayCompleted: " + packageName + ". Show: " + show);
|
||||
return show;
|
||||
if (isAppIoBlocked(uid)) {
|
||||
Slog.d(TAG, "onAnrDelayCompleted for " + packageName + ". Showing ANR dialog...");
|
||||
return true;
|
||||
} else {
|
||||
Slog.d(TAG, "onAnrDelayCompleted for " + packageName + ". Skipping ANR dialog...");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4637,5 +4669,19 @@ class StorageManagerService extends IStorageManager.Stub
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getPrimaryVolumeIds() {
|
||||
final List<String> primaryVolumeIds = new ArrayList<>();
|
||||
synchronized (mLock) {
|
||||
for (int i = 0; i < mVolumes.size(); i++) {
|
||||
final VolumeInfo vol = mVolumes.valueAt(i);
|
||||
if (vol.isPrimary()) {
|
||||
primaryVolumeIds.add(vol.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
return primaryVolumeIds;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
@@ -72,6 +73,7 @@ public final class StorageUserConnection {
|
||||
private final Context mContext;
|
||||
private final int mUserId;
|
||||
private final StorageSessionController mSessionController;
|
||||
private final StorageManagerInternal mSmInternal;
|
||||
private final ActiveConnection mActiveConnection = new ActiveConnection();
|
||||
@GuardedBy("mLock") private final Map<String, Session> mSessions = new HashMap<>();
|
||||
@GuardedBy("mLock") private final Set<Integer> mUidsBlockedOnIo = new ArraySet<>();
|
||||
@@ -81,6 +83,7 @@ public final class StorageUserConnection {
|
||||
mContext = Objects.requireNonNull(context);
|
||||
mUserId = Preconditions.checkArgumentNonnegative(userId);
|
||||
mSessionController = controller;
|
||||
mSmInternal = LocalServices.getService(StorageManagerInternal.class);
|
||||
mHandlerThread = new HandlerThread("StorageUserConnectionThread-" + mUserId);
|
||||
mHandlerThread.start();
|
||||
}
|
||||
@@ -152,9 +155,13 @@ public final class StorageUserConnection {
|
||||
*/
|
||||
public void notifyAnrDelayStarted(String packageName, int uid, int tid, int reason)
|
||||
throws ExternalStorageServiceException {
|
||||
List<String> primarySessionIds = mSmInternal.getPrimaryVolumeIds();
|
||||
synchronized (mSessionsLock) {
|
||||
for (String sessionId : mSessions.keySet()) {
|
||||
mActiveConnection.notifyAnrDelayStarted(packageName, uid, tid, reason);
|
||||
if (primarySessionIds.contains(sessionId)) {
|
||||
mActiveConnection.notifyAnrDelayStarted(packageName, uid, tid, reason);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -201,8 +208,7 @@ public final class StorageUserConnection {
|
||||
return;
|
||||
}
|
||||
}
|
||||
StorageManagerInternal sm = LocalServices.getService(StorageManagerInternal.class);
|
||||
sm.resetUser(mUserId);
|
||||
mSmInternal.resetUser(mUserId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user