Drop task snapshot with invalid hw buffer
The notifyTaskSnapshotChanged may not be always called after
Binder.clearCallingIdentity. And because there was commit
67b0902 that avoids keeping unnecessary buffer in remote
processes, it may mis-close the buffer in system server if
the calling pid isn't cleared on binder thread.
e.g. there are several suspects from ActivityTaskManagerInternal
Though it might be the responsibility of the caller to clear
binder identity before calling internal interfaces.
Instead of adding clearCallingIdentity every where:
1. Explicitly set the listener as local to skip closing the buffer
so it is independent of which thread is calling.
2. Protect the persister when using the buffer.
Bug: 192143094
Bug: 220659717
Bug: 223950159
Bug: 225794452
Test: atest TaskSnapshotPersisterLoaderTest
Change-Id: I94e8e706e56a73fffe8189023bcef5efd797a24c
This commit is contained in:
@@ -19,7 +19,6 @@ package android.app;
|
||||
import android.app.ActivityManager.RunningTaskInfo;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.content.ComponentName;
|
||||
import android.os.Binder;
|
||||
import android.os.Build;
|
||||
import android.os.RemoteException;
|
||||
import android.window.TaskSnapshot;
|
||||
@@ -32,10 +31,18 @@ import android.window.TaskSnapshot;
|
||||
*/
|
||||
public abstract class TaskStackListener extends ITaskStackListener.Stub {
|
||||
|
||||
/** Whether this listener and the callback dispatcher are in different processes. */
|
||||
private boolean mIsRemote = true;
|
||||
|
||||
@UnsupportedAppUsage
|
||||
public TaskStackListener() {
|
||||
}
|
||||
|
||||
/** Indicates that this listener lives in system server. */
|
||||
public void setIsLocal() {
|
||||
mIsRemote = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||||
public void onTaskStackChanged() throws RemoteException {
|
||||
@@ -154,8 +161,7 @@ public abstract class TaskStackListener extends ITaskStackListener.Stub {
|
||||
@Override
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||||
public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) throws RemoteException {
|
||||
if (Binder.getCallingPid() != android.os.Process.myPid()
|
||||
&& snapshot != null && snapshot.getHardwareBuffer() != null) {
|
||||
if (mIsRemote && snapshot != null && snapshot.getHardwareBuffer() != null) {
|
||||
// Preemptively clear any reference to the buffer
|
||||
snapshot.getHardwareBuffer().close();
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.app.ActivityManager;
|
||||
import android.app.ActivityManager.RunningTaskInfo;
|
||||
import android.app.ITaskStackListener;
|
||||
import android.app.TaskInfo;
|
||||
import android.app.TaskStackListener;
|
||||
import android.content.ComponentName;
|
||||
import android.os.Binder;
|
||||
import android.os.Handler;
|
||||
@@ -286,6 +287,9 @@ class TaskChangeNotificationController {
|
||||
if (listener instanceof Binder) {
|
||||
synchronized (mLocalTaskStackListeners) {
|
||||
if (!mLocalTaskStackListeners.contains(listener)) {
|
||||
if (listener instanceof TaskStackListener) {
|
||||
((TaskStackListener) listener).setIsLocal();
|
||||
}
|
||||
mLocalTaskStackListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -480,12 +480,17 @@ class TaskSnapshotController {
|
||||
}
|
||||
final HardwareBuffer buffer = screenshotBuffer == null ? null
|
||||
: screenshotBuffer.getHardwareBuffer();
|
||||
if (buffer == null || buffer.getWidth() <= 1 || buffer.getHeight() <= 1) {
|
||||
if (isInvalidHardwareBuffer(buffer)) {
|
||||
return null;
|
||||
}
|
||||
return screenshotBuffer;
|
||||
}
|
||||
|
||||
static boolean isInvalidHardwareBuffer(HardwareBuffer buffer) {
|
||||
return buffer == null || buffer.isClosed() // This must be checked before getting size.
|
||||
|| buffer.getWidth() <= 1 || buffer.getHeight() <= 1;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
TaskSnapshot snapshotTask(Task task) {
|
||||
return snapshotTask(task, PixelFormat.UNKNOWN);
|
||||
|
||||
@@ -407,6 +407,10 @@ class TaskSnapshotPersister {
|
||||
}
|
||||
|
||||
boolean writeBuffer() {
|
||||
if (TaskSnapshotController.isInvalidHardwareBuffer(mSnapshot.getHardwareBuffer())) {
|
||||
Slog.e(TAG, "Invalid task snapshot hw buffer, taskId=" + mTaskId);
|
||||
return false;
|
||||
}
|
||||
final Bitmap bitmap = Bitmap.wrapHardwareBuffer(
|
||||
mSnapshot.getHardwareBuffer(), mSnapshot.getColorSpace());
|
||||
if (bitmap == null) {
|
||||
|
||||
@@ -9045,13 +9045,18 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
}
|
||||
|
||||
TaskSnapshot taskSnapshot;
|
||||
synchronized (mGlobalLock) {
|
||||
Task task = mRoot.anyTaskForId(taskId, MATCH_ATTACHED_TASK_OR_RECENT_TASKS);
|
||||
if (task == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Failed to find matching task for taskId=" + taskId);
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
synchronized (mGlobalLock) {
|
||||
Task task = mRoot.anyTaskForId(taskId, MATCH_ATTACHED_TASK_OR_RECENT_TASKS);
|
||||
if (task == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Failed to find matching task for taskId=" + taskId);
|
||||
}
|
||||
taskSnapshot = mTaskSnapshotController.captureTaskSnapshot(task, false);
|
||||
}
|
||||
taskSnapshot = mTaskSnapshotController.captureTaskSnapshot(task, false);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
|
||||
if (taskSnapshot == null || taskSnapshot.getHardwareBuffer() == null) {
|
||||
|
||||
@@ -31,13 +31,13 @@ import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.window.TaskSnapshot;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Rect;
|
||||
import android.os.SystemClock;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.util.ArraySet;
|
||||
import android.view.Surface;
|
||||
import android.window.TaskSnapshot;
|
||||
|
||||
import androidx.test.filters.MediumTest;
|
||||
|
||||
@@ -83,6 +83,12 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa
|
||||
assertEquals(TEST_INSETS, snapshot.getContentInsets());
|
||||
assertNotNull(snapshot.getSnapshot());
|
||||
assertEquals(Configuration.ORIENTATION_PORTRAIT, snapshot.getOrientation());
|
||||
|
||||
snapshot.getHardwareBuffer().close();
|
||||
mPersister.persistSnapshot(1, mTestUserId, snapshot);
|
||||
mPersister.waitForQueueEmpty();
|
||||
assertTrueForFiles(files, file -> !file.exists(),
|
||||
" snapshot files must be removed by invalid buffer");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -131,8 +131,7 @@ class TaskSnapshotPersisterTestBase extends WindowTestsBase {
|
||||
}
|
||||
|
||||
TaskSnapshot createSnapshot() {
|
||||
return new TaskSnapshotBuilder()
|
||||
.build();
|
||||
return new TaskSnapshotBuilder().setTopActivityComponent(getUniqueComponentName()).build();
|
||||
}
|
||||
|
||||
protected static void assertTrueForFiles(File[] files, Predicate<File> predicate,
|
||||
|
||||
@@ -903,7 +903,7 @@ class WindowTestsBase extends SystemServiceTestsBase {
|
||||
doReturn(100).when(hardwareBuffer).getHeight();
|
||||
}
|
||||
|
||||
private static ComponentName getUniqueComponentName() {
|
||||
static ComponentName getUniqueComponentName() {
|
||||
return ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME,
|
||||
DEFAULT_COMPONENT_CLASS_NAME + sCurrentActivityId++);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user