Merge "Get ANR delay from the MediaProvider" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
944eece7a4
@@ -10386,6 +10386,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 void onFreeCache(@NonNull java.util.UUID, long) throws java.io.IOException;
|
||||
method public long onGetAnrDelayMillis(@NonNull String, int);
|
||||
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
|
||||
|
||||
@@ -95,6 +95,21 @@ public abstract class ExternalStorageService extends Service {
|
||||
public static final String EXTRA_ERROR =
|
||||
"android.service.storage.extra.error";
|
||||
|
||||
/**
|
||||
* {@link Bundle} key for a package name {@link String} value.
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
public static final String EXTRA_PACKAGE_NAME = "android.service.storage.extra.package_name";
|
||||
|
||||
/**
|
||||
* {@link Bundle} key for a {@link Long} value.
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
public static final String EXTRA_ANR_TIMEOUT_MS =
|
||||
"android.service.storage.extra.anr_timeout_ms";
|
||||
|
||||
/** @hide */
|
||||
@IntDef(flag = true, prefix = {"FLAG_SESSION_"},
|
||||
value = {FLAG_SESSION_TYPE_FUSE, FLAG_SESSION_ATTRIBUTE_INDEXABLE})
|
||||
@@ -162,6 +177,15 @@ public abstract class ExternalStorageService extends Service {
|
||||
throw new UnsupportedOperationException("onFreeCacheRequested not implemented");
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when {@code packageName} is about to ANR
|
||||
*
|
||||
* @return ANR dialog delay in milliseconds
|
||||
*/
|
||||
public long onGetAnrDelayMillis(@NonNull String packageName, int uid) {
|
||||
throw new UnsupportedOperationException("onGetAnrDelayMillis not implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public final IBinder onBind(@NonNull Intent intent) {
|
||||
@@ -222,6 +246,19 @@ public abstract class ExternalStorageService extends Service {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getAnrDelayMillis(String packageName, int uid, RemoteCallback callback)
|
||||
throws RemoteException {
|
||||
mHandler.post(() -> {
|
||||
try {
|
||||
long timeoutMs = onGetAnrDelayMillis(packageName, uid);
|
||||
sendTimeoutResult(packageName, timeoutMs, null /* throwable */, callback);
|
||||
} catch (Throwable t) {
|
||||
sendTimeoutResult(packageName, 0 /* timeoutMs */, t, callback);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void sendResult(String sessionId, Throwable throwable, RemoteCallback callback) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(EXTRA_SESSION_ID, sessionId);
|
||||
@@ -230,5 +267,16 @@ public abstract class ExternalStorageService extends Service {
|
||||
}
|
||||
callback.sendResult(bundle);
|
||||
}
|
||||
|
||||
private void sendTimeoutResult(String packageName, long timeoutMs, Throwable throwable,
|
||||
RemoteCallback callback) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(EXTRA_PACKAGE_NAME, packageName);
|
||||
bundle.putLong(EXTRA_ANR_TIMEOUT_MS, timeoutMs);
|
||||
if (throwable != null) {
|
||||
bundle.putParcelable(EXTRA_ERROR, new ParcelableException(throwable));
|
||||
}
|
||||
callback.sendResult(bundle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,4 +32,5 @@ oneway interface IExternalStorageService
|
||||
in RemoteCallback callback);
|
||||
void freeCache(@utf8InCpp String sessionId, in String volumeUuid, long bytes,
|
||||
in RemoteCallback callback);
|
||||
void getAnrDelayMillis(String packageName, int uid, in RemoteCallback callback);
|
||||
}
|
||||
@@ -939,9 +939,12 @@ class StorageManagerService extends IStorageManager.Stub
|
||||
if (transcodeEnabled) {
|
||||
LocalServices.getService(ActivityManagerInternal.class)
|
||||
.registerAnrController((packageName, uid) -> {
|
||||
// TODO: Retrieve delay from ExternalStorageService that can check
|
||||
// transcoding status
|
||||
return SystemProperties.getInt("sys.fuse.transcode_anr_delay_ms", 0);
|
||||
try {
|
||||
return mStorageSessionController.getAnrDelayMillis(packageName, uid);
|
||||
} catch (ExternalStorageServiceException e) {
|
||||
Log.e(TAG, "Failed to get ANR delay for " + packageName, e);
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,6 +157,29 @@ public final class StorageSessionController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when {@code packageName} is about to ANR
|
||||
*
|
||||
* @return ANR dialog delay in milliseconds
|
||||
*/
|
||||
public long getAnrDelayMillis(String packageName, int uid)
|
||||
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) {
|
||||
long delay = connection.getAnrDelayMillis(packageName, uid);
|
||||
if (delay > 0) {
|
||||
return delay;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes and returns the {@link StorageUserConnection} for {@code vol}.
|
||||
*
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.server.storage;
|
||||
|
||||
import static android.service.storage.ExternalStorageService.EXTRA_ANR_TIMEOUT_MS;
|
||||
import static android.service.storage.ExternalStorageService.EXTRA_ERROR;
|
||||
import static android.service.storage.ExternalStorageService.FLAG_SESSION_ATTRIBUTE_INDEXABLE;
|
||||
import static android.service.storage.ExternalStorageService.FLAG_SESSION_TYPE_FUSE;
|
||||
@@ -142,6 +143,24 @@ public final class StorageUserConnection {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when {@code packageName} is about to ANR
|
||||
*
|
||||
* @return ANR dialog delay in milliseconds
|
||||
*/
|
||||
public long getAnrDelayMillis(String packageName, int uid)
|
||||
throws ExternalStorageServiceException {
|
||||
synchronized (mSessionsLock) {
|
||||
for (String sessionId : mSessions.keySet()) {
|
||||
long delay = mActiveConnection.getAnrDelayMillis(packageName, uid);
|
||||
if (delay > 0) {
|
||||
return delay;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a session without ending it or waiting for exit.
|
||||
*
|
||||
@@ -234,6 +253,9 @@ public final class StorageUserConnection {
|
||||
@GuardedBy("mLock")
|
||||
private final ArrayList<CompletableFuture<Void>> mOutstandingOps = new ArrayList<>();
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private final ArrayList<CompletableFuture<Long>> mOutstandingTimeoutOps = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
ServiceConnection oldConnection = null;
|
||||
@@ -250,6 +272,9 @@ public final class StorageUserConnection {
|
||||
for (CompletableFuture<Void> op : mOutstandingOps) {
|
||||
op.cancel(true);
|
||||
}
|
||||
for (CompletableFuture<Long> op : mOutstandingTimeoutOps) {
|
||||
op.cancel(true);
|
||||
}
|
||||
mOutstandingOps.clear();
|
||||
}
|
||||
|
||||
@@ -264,27 +289,44 @@ public final class StorageUserConnection {
|
||||
}
|
||||
}
|
||||
|
||||
private void waitForAsync(AsyncStorageServiceCall asyncCall) throws Exception {
|
||||
CompletableFuture<IExternalStorageService> serviceFuture = connectIfNeeded();
|
||||
private void waitForAsyncVoid(AsyncStorageServiceCall asyncCall) throws Exception {
|
||||
CompletableFuture<Void> opFuture = new CompletableFuture<>();
|
||||
RemoteCallback callback = new RemoteCallback(result -> setResult(result, opFuture));
|
||||
|
||||
waitForAsync(asyncCall, callback, opFuture, mOutstandingOps,
|
||||
DEFAULT_REMOTE_TIMEOUT_SECONDS);
|
||||
}
|
||||
|
||||
private long waitForAsyncLong(AsyncStorageServiceCall asyncCall) throws Exception {
|
||||
CompletableFuture<Long> opFuture = new CompletableFuture<>();
|
||||
RemoteCallback callback =
|
||||
new RemoteCallback(result -> setTimeoutResult(result, opFuture));
|
||||
|
||||
return waitForAsync(asyncCall, callback, opFuture, mOutstandingTimeoutOps,
|
||||
1 /* timeoutSeconds */);
|
||||
}
|
||||
|
||||
private <T> T waitForAsync(AsyncStorageServiceCall asyncCall, RemoteCallback callback,
|
||||
CompletableFuture<T> opFuture, ArrayList<CompletableFuture<T>> outstandingOps,
|
||||
long timeoutSeconds) throws Exception {
|
||||
CompletableFuture<IExternalStorageService> serviceFuture = connectIfNeeded();
|
||||
|
||||
try {
|
||||
synchronized (mLock) {
|
||||
mOutstandingOps.add(opFuture);
|
||||
outstandingOps.add(opFuture);
|
||||
}
|
||||
serviceFuture.thenCompose(service -> {
|
||||
return serviceFuture.thenCompose(service -> {
|
||||
try {
|
||||
asyncCall.run(service,
|
||||
new RemoteCallback(result -> setResult(result, opFuture)));
|
||||
asyncCall.run(service, callback);
|
||||
} catch (RemoteException e) {
|
||||
opFuture.completeExceptionally(e);
|
||||
}
|
||||
|
||||
return opFuture;
|
||||
}).get(DEFAULT_REMOTE_TIMEOUT_SECONDS, TimeUnit.SECONDS);
|
||||
}).get(timeoutSeconds, TimeUnit.SECONDS);
|
||||
} finally {
|
||||
synchronized (mLock) {
|
||||
mOutstandingOps.remove(opFuture);
|
||||
outstandingOps.remove(opFuture);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -292,9 +334,9 @@ public final class StorageUserConnection {
|
||||
public void startSession(Session session, ParcelFileDescriptor fd)
|
||||
throws ExternalStorageServiceException {
|
||||
try {
|
||||
waitForAsync((service, callback) -> service.startSession(session.sessionId,
|
||||
waitForAsyncVoid((service, callback) -> service.startSession(session.sessionId,
|
||||
FLAG_SESSION_TYPE_FUSE | FLAG_SESSION_ATTRIBUTE_INDEXABLE,
|
||||
fd, session.upperPath, session.lowerPath, callback));
|
||||
fd, session.upperPath, session.lowerPath, callback));
|
||||
} catch (Exception e) {
|
||||
throw new ExternalStorageServiceException("Failed to start session: " + session, e);
|
||||
} finally {
|
||||
@@ -308,7 +350,7 @@ public final class StorageUserConnection {
|
||||
|
||||
public void endSession(Session session) throws ExternalStorageServiceException {
|
||||
try {
|
||||
waitForAsync((service, callback) ->
|
||||
waitForAsyncVoid((service, callback) ->
|
||||
service.endSession(session.sessionId, callback));
|
||||
} catch (Exception e) {
|
||||
throw new ExternalStorageServiceException("Failed to end session: " + session, e);
|
||||
@@ -319,7 +361,7 @@ public final class StorageUserConnection {
|
||||
public void notifyVolumeStateChanged(String sessionId, StorageVolume vol) throws
|
||||
ExternalStorageServiceException {
|
||||
try {
|
||||
waitForAsync((service, callback) ->
|
||||
waitForAsyncVoid((service, callback) ->
|
||||
service.notifyVolumeStateChanged(sessionId, vol, callback));
|
||||
} catch (Exception e) {
|
||||
throw new ExternalStorageServiceException("Failed to notify volume state changed "
|
||||
@@ -330,7 +372,7 @@ public final class StorageUserConnection {
|
||||
public void freeCache(String sessionId, String volumeUuid, long bytes)
|
||||
throws ExternalStorageServiceException {
|
||||
try {
|
||||
waitForAsync((service, callback) ->
|
||||
waitForAsyncVoid((service, callback) ->
|
||||
service.freeCache(sessionId, volumeUuid, bytes, callback));
|
||||
} catch (Exception e) {
|
||||
throw new ExternalStorageServiceException("Failed to free " + bytes
|
||||
@@ -338,6 +380,27 @@ public final class StorageUserConnection {
|
||||
}
|
||||
}
|
||||
|
||||
public long getAnrDelayMillis(String packgeName, int uid)
|
||||
throws ExternalStorageServiceException {
|
||||
try {
|
||||
return waitForAsyncLong((service, callback) ->
|
||||
service.getAnrDelayMillis(packgeName, uid, callback));
|
||||
} catch (Exception e) {
|
||||
throw new ExternalStorageServiceException("Failed to notify app not responding: "
|
||||
+ packgeName, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void setTimeoutResult(Bundle result, CompletableFuture<Long> future) {
|
||||
ParcelableException ex = result.getParcelable(EXTRA_ERROR);
|
||||
if (ex != null) {
|
||||
future.completeExceptionally(ex);
|
||||
} else {
|
||||
long timeoutMs = result.getLong(EXTRA_ANR_TIMEOUT_MS);
|
||||
future.complete(timeoutMs);
|
||||
}
|
||||
}
|
||||
|
||||
private void setResult(Bundle result, CompletableFuture<Void> future) {
|
||||
ParcelableException ex = result.getParcelable(EXTRA_ERROR);
|
||||
if (ex != null) {
|
||||
|
||||
Reference in New Issue
Block a user