Only update native InputApplicationHandle once
This makes sure the write operation (NativeInputApplicationHandle
::updateInfo) is always called from window manager side once when
calling SurfaceControl.Transaction#setInputWindowInfo or
InputManagerService#setFocusedApplication. If the info of input
application handle is changed, a new instance will be created.
That avoids the race condition of reading the fields of the same
InputApplicationInfo instance from input dispatcher.
Bug: 171857140
Bug: 161334769
Bug: 174768985
Test: WindowInputTests
Merged-In: Ief84bbe6e6fa4da5309912059904932ccf775b75
Merged-In: I70de9835c7699fe6f56fc3655b0fee5c317ecc3a
Change-Id: I70de9835c7699fe6f56fc3655b0fee5c317ecc3a
(cherry picked from commit a68473ce978f3e3ad73bd127cdcfcf663d9fd4d9)
diff --git a/core/java/android/view/InputApplicationHandle.java b/core/java/android/view/InputApplicationHandle.java
index 3d05e2a..9b96f7f 100644
--- a/core/java/android/view/InputApplicationHandle.java
+++ b/core/java/android/view/InputApplicationHandle.java
@@ -16,6 +16,7 @@
package android.view;
+import android.annotation.NonNull;
import android.os.IBinder;
/**
@@ -31,17 +32,20 @@
private long ptr;
// Application name.
- public String name;
+ public final @NonNull String name;
// Dispatching timeout.
- public long dispatchingTimeoutNanos;
+ public final long dispatchingTimeoutNanos;
public final IBinder token;
private native void nativeDispose();
- public InputApplicationHandle(IBinder token) {
+ public InputApplicationHandle(@NonNull IBinder token, @NonNull String name,
+ long dispatchingTimeoutNanos) {
this.token = token;
+ this.name = name;
+ this.dispatchingTimeoutNanos = dispatchingTimeoutNanos;
}
public InputApplicationHandle(InputApplicationHandle handle) {
diff --git a/core/java/android/view/InputWindowHandle.java b/core/java/android/view/InputWindowHandle.java
index 5f74b2a..71d26b8 100644
--- a/core/java/android/view/InputWindowHandle.java
+++ b/core/java/android/view/InputWindowHandle.java
@@ -36,7 +36,7 @@
private long ptr;
// The input application handle.
- public final InputApplicationHandle inputApplicationHandle;
+ public InputApplicationHandle inputApplicationHandle;
// The token associates input data with a window and its input channel. The client input
// channel and the server input channel will both contain this token.
diff --git a/core/jni/android_hardware_input_InputApplicationHandle.cpp b/core/jni/android_hardware_input_InputApplicationHandle.cpp
index 71edfd5..c1ecae8 100644
--- a/core/jni/android_hardware_input_InputApplicationHandle.cpp
+++ b/core/jni/android_hardware_input_InputApplicationHandle.cpp
@@ -58,6 +58,11 @@
if (!obj) {
return false;
}
+ if (mInfo.token.get() != nullptr) {
+ // The java fields are immutable, so it doesn't need to update again.
+ env->DeleteLocalRef(obj);
+ return true;
+ }
mInfo.name = getStringField(env, obj, gInputApplicationHandleClassInfo.name, "<null>");
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 1a13d0f..dc4caf8 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -416,7 +416,7 @@
// mOccludesParent field.
final boolean hasWallpaper;
// Input application handle used by the input dispatcher.
- final InputApplicationHandle mInputApplicationHandle;
+ private InputApplicationHandle mInputApplicationHandle;
final int launchedFromPid; // always the pid who started the activity.
final int launchedFromUid; // always the uid who started the activity.
@@ -1501,7 +1501,6 @@
info = aInfo;
mUserId = UserHandle.getUserId(info.applicationInfo.uid);
packageName = info.applicationInfo.packageName;
- mInputApplicationHandle = new InputApplicationHandle(appToken);
intent = _intent;
// If the class name in the intent doesn't match that of the target, this is probably an
@@ -1686,6 +1685,21 @@
return lockTaskLaunchMode;
}
+ @NonNull InputApplicationHandle getInputApplicationHandle(boolean update) {
+ if (mInputApplicationHandle == null) {
+ mInputApplicationHandle = new InputApplicationHandle(appToken, toString(),
+ mInputDispatchingTimeoutNanos);
+ } else if (update) {
+ final String name = toString();
+ if (mInputDispatchingTimeoutNanos != mInputApplicationHandle.dispatchingTimeoutNanos
+ || !name.equals(mInputApplicationHandle.name)) {
+ mInputApplicationHandle = new InputApplicationHandle(appToken, name,
+ mInputDispatchingTimeoutNanos);
+ }
+ }
+ return mInputApplicationHandle;
+ }
+
@Override
ActivityRecord asActivityRecord() {
// I am an activity record!
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index f840d92..7b562a9 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -269,10 +269,8 @@
mInputEventReceiver = new DragInputEventReceiver(mClientChannel,
mService.mH.getLooper(), mDragDropController);
- mDragApplicationHandle = new InputApplicationHandle(new Binder());
- mDragApplicationHandle.name = "drag";
- mDragApplicationHandle.dispatchingTimeoutNanos =
- WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+ mDragApplicationHandle = new InputApplicationHandle(new Binder(), "drag",
+ WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS);
mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle,
display.getDisplayId());
diff --git a/services/core/java/com/android/server/wm/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java
index 3b39b6b..1918573 100644
--- a/services/core/java/com/android/server/wm/InputConsumerImpl.java
+++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java
@@ -67,10 +67,8 @@
}
mService.mInputManager.registerInputChannel(mServerChannel);
- mApplicationHandle = new InputApplicationHandle(new Binder());
- mApplicationHandle.name = name;
- mApplicationHandle.dispatchingTimeoutNanos =
- WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+ mApplicationHandle = new InputApplicationHandle(new Binder(), name,
+ WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS);
mWindowHandle = new InputWindowHandle(mApplicationHandle, displayId);
mWindowHandle.name = name;
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 3663ee1..8366fde 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -43,7 +43,6 @@
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Slog;
-import android.view.InputApplicationHandle;
import android.view.InputChannel;
import android.view.InputEventReceiver;
import android.view.InputWindowHandle;
@@ -268,6 +267,8 @@
final boolean hasFocus, final boolean hasWallpaper) {
// Add a window to our list of input windows.
inputWindowHandle.name = child.toString();
+ inputWindowHandle.inputApplicationHandle = child.mActivityRecord != null
+ ? child.mActivityRecord.getInputApplicationHandle(false /* update */) : null;
flags = child.getSurfaceTouchableRegion(inputWindowHandle, flags);
inputWindowHandle.layoutParamsFlags = flags;
inputWindowHandle.layoutParamsType = type;
@@ -386,15 +387,8 @@
public void setFocusedAppLw(ActivityRecord newApp) {
// Focused app has changed.
- if (newApp == null) {
- mService.mInputManager.setFocusedApplication(mDisplayId, null);
- } else {
- final InputApplicationHandle handle = newApp.mInputApplicationHandle;
- handle.name = newApp.toString();
- handle.dispatchingTimeoutNanos = newApp.mInputDispatchingTimeoutNanos;
-
- mService.mInputManager.setFocusedApplication(mDisplayId, handle);
- }
+ mService.mInputManager.setFocusedApplication(mDisplayId,
+ newApp != null ? newApp.getInputApplicationHandle(true /* update */) : null);
}
public void pauseDispatchingLw(WindowToken window) {
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index c68b660..44f4a58 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -228,10 +228,8 @@
mClientChannel, mService.mAnimationHandler.getLooper(),
mService.mAnimator.getChoreographer());
- mDragApplicationHandle = new InputApplicationHandle(new Binder());
- mDragApplicationHandle.name = TAG;
- mDragApplicationHandle.dispatchingTimeoutNanos =
- WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+ mDragApplicationHandle = new InputApplicationHandle(new Binder(), TAG,
+ WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS);
mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle,
displayContent.getDisplayId());
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index bab83dc..faa483a 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -943,7 +943,8 @@
mLastRequestedHeight = 0;
mLayer = 0;
mInputWindowHandle = new InputWindowHandle(
- mActivityRecord != null ? mActivityRecord.mInputApplicationHandle : null,
+ mActivityRecord != null
+ ? mActivityRecord.getInputApplicationHandle(false /* update */) : null,
getDisplayId());
// Make sure we initial all fields before adding to parentWindow, to prevent exception