Add native InputTransferToken
Added a native class that corresponds to the Java InputTransferToken.
Test: SurfaceControlInputReceiverTests
Test: AInputTransferTokenTest
Bug: 324271765
Change-Id: Ic5549227ad8c8ab311f8953eaf370e1a2896d8f3
diff --git a/core/java/android/window/InputTransferToken.java b/core/java/android/window/InputTransferToken.java
index e572853..c62eee4 100644
--- a/core/java/android/window/InputTransferToken.java
+++ b/core/java/android/window/InputTransferToken.java
@@ -18,7 +18,6 @@
import android.annotation.FlaggedApi;
import android.annotation.NonNull;
-import android.os.Binder;
import android.os.IBinder;
import android.os.Looper;
import android.os.Parcel;
@@ -30,6 +29,8 @@
import com.android.window.flags.Flags;
+import libcore.util.NativeAllocationRegistry;
+
import java.util.Objects;
/**
@@ -51,28 +52,51 @@
*/
@FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER)
public final class InputTransferToken implements Parcelable {
+ private static native long nativeCreate();
+ private static native long nativeCreate(IBinder token);
+ private static native void nativeWriteToParcel(long nativeObject, Parcel out);
+ private static native long nativeReadFromParcel(Parcel in);
+ private static native IBinder nativeGetBinderToken(long nativeObject);
+ private static native long nativeGetNativeInputTransferTokenFinalizer();
+ private static native boolean nativeEquals(long nativeObject1, long nativeObject2);
+
+ private static final NativeAllocationRegistry sRegistry =
+ NativeAllocationRegistry.createMalloced(InputTransferToken.class.getClassLoader(),
+ nativeGetNativeInputTransferTokenFinalizer());
+
/**
* @hide
*/
- @NonNull
- public final IBinder mToken;
+ public final long mNativeObject;
+
+ private InputTransferToken(long nativeObject) {
+ mNativeObject = nativeObject;
+ sRegistry.registerNativeAllocation(this, nativeObject);
+ }
/**
* @hide
*/
public InputTransferToken(@NonNull IBinder token) {
- mToken = token;
+ this(nativeCreate(token));
}
/**
* @hide
*/
public InputTransferToken() {
- mToken = new Binder();
+ this(nativeCreate());
+ }
+
+ /**
+ * @hide
+ */
+ public IBinder getToken() {
+ return nativeGetBinderToken(mNativeObject);
}
private InputTransferToken(Parcel in) {
- mToken = in.readStrongBinder();
+ this(nativeReadFromParcel(in));
}
/**
@@ -88,7 +112,7 @@
*/
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeStrongBinder(mToken);
+ nativeWriteToParcel(mNativeObject, dest);
}
public static final @NonNull Creator<InputTransferToken> CREATOR = new Creator<>() {
@@ -101,13 +125,12 @@
}
};
-
/**
* @hide
*/
@Override
public int hashCode() {
- return Objects.hash(mToken);
+ return Objects.hash(getToken());
}
/**
@@ -118,7 +141,8 @@
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
InputTransferToken other = (InputTransferToken) obj;
- return other.mToken == mToken;
+ if (other.mNativeObject == mNativeObject) return true;
+ return nativeEquals(mNativeObject, other.mNativeObject);
}
}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 76e7138..77c6436 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -265,6 +265,7 @@
"fd_utils.cpp",
"android_hardware_input_InputWindowHandle.cpp",
"android_hardware_input_InputApplicationHandle.cpp",
+ "android_window_InputTransferToken.cpp",
"android_window_WindowInfosListener.cpp",
"android_window_ScreenCapture.cpp",
"jni_common.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index aa63f4f..9bbd191 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -221,6 +221,7 @@
extern int register_android_tracing_PerfettoDataSource(JNIEnv* env);
extern int register_android_tracing_PerfettoDataSourceInstance(JNIEnv* env);
extern int register_android_tracing_PerfettoProducer(JNIEnv* env);
+extern int register_android_window_InputTransferToken(JNIEnv* env);
// Namespace for Android Runtime flags applied during boot time.
static const char* RUNTIME_NATIVE_BOOT_NAMESPACE = "runtime_native_boot";
@@ -1678,6 +1679,7 @@
REG_JNI(register_android_tracing_PerfettoDataSource),
REG_JNI(register_android_tracing_PerfettoDataSourceInstance),
REG_JNI(register_android_tracing_PerfettoProducer),
+ REG_JNI(register_android_window_InputTransferToken),
};
/*
diff --git a/core/jni/android_window_InputTransferToken.cpp b/core/jni/android_window_InputTransferToken.cpp
new file mode 100644
index 0000000..60568e30
--- /dev/null
+++ b/core/jni/android_window_InputTransferToken.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "InputTransferToken"
+
+#include <android_runtime/android_window_InputTransferToken.h>
+#include <gui/InputTransferToken.h>
+#include <nativehelper/JNIHelp.h>
+
+#include "android_os_Parcel.h"
+#include "android_util_Binder.h"
+#include "core_jni_helpers.h"
+
+namespace android {
+
+static struct {
+ jclass clazz;
+ jfieldID mNativeObject;
+ jmethodID ctor;
+} gInputTransferTokenClassInfo;
+
+static jlong nativeCreate(JNIEnv* env, jclass clazz) {
+ sp<InputTransferToken> inputTransferToken = sp<InputTransferToken>::make();
+ inputTransferToken->incStrong((void*)nativeCreate);
+ return reinterpret_cast<jlong>(inputTransferToken.get());
+}
+
+static jlong nativeCreateFromBinder(JNIEnv* env, jclass clazz, jobject tokenBinderObj) {
+ if (tokenBinderObj == nullptr) {
+ return 0;
+ }
+ sp<IBinder> token(ibinderForJavaObject(env, tokenBinderObj));
+ if (token == nullptr) {
+ return 0;
+ }
+ sp<InputTransferToken> inputTransferToken = sp<InputTransferToken>::make(token);
+ inputTransferToken->incStrong((void*)nativeCreate);
+ return reinterpret_cast<jlong>(inputTransferToken.get());
+}
+
+static void nativeWriteToParcel(JNIEnv* env, jclass clazz, jlong nativeObj, jobject parcelObj) {
+ InputTransferToken* inputTransferToken = reinterpret_cast<InputTransferToken*>(nativeObj);
+ Parcel* parcel = parcelForJavaObject(env, parcelObj);
+ inputTransferToken->writeToParcel(parcel);
+}
+
+static jlong nativeReadFromParcel(JNIEnv* env, jclass clazz, jobject parcelObj) {
+ sp<InputTransferToken> inputTransferToken = sp<InputTransferToken>::make();
+ Parcel* parcel = parcelForJavaObject(env, parcelObj);
+ inputTransferToken->readFromParcel(parcel);
+ inputTransferToken->incStrong((void*)nativeCreate);
+ return reinterpret_cast<jlong>(inputTransferToken.get());
+}
+
+static jobject nativeGetBinderToken(JNIEnv* env, jclass clazz, jlong nativeObj) {
+ sp<InputTransferToken> inputTransferToken = reinterpret_cast<InputTransferToken*>(nativeObj);
+ return javaObjectForIBinder(env, inputTransferToken->mToken);
+}
+
+InputTransferToken* android_window_InputTransferToken_getNativeInputTransferToken(
+ JNIEnv* env, jobject inputTransferTokenObj) {
+ if (inputTransferTokenObj != nullptr &&
+ env->IsInstanceOf(inputTransferTokenObj, gInputTransferTokenClassInfo.clazz)) {
+ return reinterpret_cast<InputTransferToken*>(
+ env->GetLongField(inputTransferTokenObj,
+ gInputTransferTokenClassInfo.mNativeObject));
+ } else {
+ return nullptr;
+ }
+}
+
+jobject android_window_InputTransferToken_getJavaInputTransferToken(
+ JNIEnv* env, const InputTransferToken* inputTransferToken) {
+ if (inputTransferToken == nullptr || env == nullptr) {
+ return nullptr;
+ }
+
+ inputTransferToken->incStrong((void*)nativeCreate);
+ return env->NewObject(gInputTransferTokenClassInfo.clazz, gInputTransferTokenClassInfo.ctor,
+ reinterpret_cast<jlong>(inputTransferToken));
+}
+
+static void release(InputTransferToken* inputTransferToken) {
+ inputTransferToken->decStrong((void*)nativeCreate);
+}
+
+static jlong nativeGetNativeInputTransferTokenFinalizer(JNIEnv* env, jclass clazz) {
+ return static_cast<jlong>(reinterpret_cast<uintptr_t>(&release));
+}
+
+static bool nativeEquals(JNIEnv* env, jclass clazz, jlong inputTransferTokenObj1,
+ jlong inputTransferTokenObj2) {
+ sp<InputTransferToken> inputTransferToken1(
+ reinterpret_cast<InputTransferToken*>(inputTransferTokenObj1));
+ sp<InputTransferToken> inputTransferToken2(
+ reinterpret_cast<InputTransferToken*>(inputTransferTokenObj2));
+
+ return inputTransferToken1 == inputTransferToken2;
+}
+
+static const JNINativeMethod sInputTransferTokenMethods[] = {
+ // clang-format off
+ {"nativeCreate", "()J", (void*)nativeCreate},
+ {"nativeCreate", "(Landroid/os/IBinder;)J", (void*)nativeCreateFromBinder},
+ {"nativeWriteToParcel", "(JLandroid/os/Parcel;)V", (void*)nativeWriteToParcel},
+ {"nativeReadFromParcel", "(Landroid/os/Parcel;)J", (void*)nativeReadFromParcel},
+ {"nativeGetBinderToken", "(J)Landroid/os/IBinder;", (void*)nativeGetBinderToken},
+ {"nativeGetNativeInputTransferTokenFinalizer", "()J", (void*)nativeGetNativeInputTransferTokenFinalizer},
+ {"nativeEquals", "(JJ)Z", (void*) nativeEquals},
+ // clang-format on
+};
+
+int register_android_window_InputTransferToken(JNIEnv* env) {
+ int err = RegisterMethodsOrDie(env, "android/window/InputTransferToken",
+ sInputTransferTokenMethods, NELEM(sInputTransferTokenMethods));
+ jclass inputTransferTokenClass = FindClassOrDie(env, "android/window/InputTransferToken");
+ gInputTransferTokenClassInfo.clazz = MakeGlobalRefOrDie(env, inputTransferTokenClass);
+ gInputTransferTokenClassInfo.mNativeObject =
+ GetFieldIDOrDie(env, gInputTransferTokenClassInfo.clazz, "mNativeObject", "J");
+ gInputTransferTokenClassInfo.ctor =
+ GetMethodIDOrDie(env, gInputTransferTokenClassInfo.clazz, "<init>", "(J)V");
+ return err;
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/core/jni/include/android_runtime/android_window_InputTransferToken.h b/core/jni/include/android_runtime/android_window_InputTransferToken.h
new file mode 100644
index 0000000..75dbe37
--- /dev/null
+++ b/core/jni/include/android_runtime/android_window_InputTransferToken.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ANDROID_WINDOW_INPUTTRANSFERTOKEN_H
+#define _ANDROID_WINDOW_INPUTTRANSFERTOKEN_H
+
+#include <gui/InputTransferToken.h>
+#include <jni.h>
+
+namespace android {
+
+extern InputTransferToken* android_window_InputTransferToken_getNativeInputTransferToken(
+ JNIEnv* env, jobject inputTransferTokenObj);
+
+extern jobject android_window_InputTransferToken_getJavaInputTransferToken(
+ JNIEnv* env, const InputTransferToken* inputTransferToken);
+
+} // namespace android
+
+#endif // _ANDROID_WINDOW_INPUTTRANSFERTOKEN_H
diff --git a/native/android/Android.bp b/native/android/Android.bp
index 752ebdf..4812685 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -58,6 +58,7 @@
"configuration.cpp",
"hardware_buffer_jni.cpp",
"input.cpp",
+ "input_transfer_token.cpp",
"looper.cpp",
"native_activity.cpp",
"native_window_jni.cpp",
diff --git a/native/android/input_transfer_token.cpp b/native/android/input_transfer_token.cpp
new file mode 100644
index 0000000..501e1d3
--- /dev/null
+++ b/native/android/input_transfer_token.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "InputTransferToken"
+
+#include <android/input_transfer_token_jni.h>
+#include <android_runtime/android_window_InputTransferToken.h>
+#include <gui/InputTransferToken.h>
+#include <log/log_main.h>
+
+using namespace android;
+
+#define CHECK_NOT_NULL(name) \
+ LOG_ALWAYS_FATAL_IF(name == nullptr, "nullptr passed as " #name " argument");
+
+void InputTransferToken_acquire(InputTransferToken* inputTransferToken) {
+ // incStrong/decStrong token must be the same, doesn't matter what it is
+ inputTransferToken->incStrong((void*)InputTransferToken_acquire);
+}
+
+void InputTransferToken_release(InputTransferToken* inputTransferToken) {
+ // incStrong/decStrong token must be the same, doesn't matter what it is
+ inputTransferToken->decStrong((void*)InputTransferToken_acquire);
+}
+
+AInputTransferToken* AInputTransferToken_fromJava(JNIEnv* env, jobject inputTransferTokenObj) {
+ CHECK_NOT_NULL(env);
+ CHECK_NOT_NULL(inputTransferTokenObj);
+ InputTransferToken* inputTransferToken =
+ android_window_InputTransferToken_getNativeInputTransferToken(env,
+ inputTransferTokenObj);
+ CHECK_NOT_NULL(inputTransferToken);
+ InputTransferToken_acquire(inputTransferToken);
+ return reinterpret_cast<AInputTransferToken*>(inputTransferToken);
+}
+
+jobject AInputTransferToken_toJava(JNIEnv* _Nonnull env,
+ const AInputTransferToken* aInputTransferToken) {
+ CHECK_NOT_NULL(env);
+ CHECK_NOT_NULL(aInputTransferToken);
+ const InputTransferToken* inputTransferToken =
+ reinterpret_cast<const InputTransferToken*>(aInputTransferToken);
+ return android_window_InputTransferToken_getJavaInputTransferToken(env, inputTransferToken);
+}
+
+void AInputTransferToken_release(AInputTransferToken* aInputTransferToken) {
+ CHECK_NOT_NULL(aInputTransferToken);
+ InputTransferToken* inputTransferToken =
+ reinterpret_cast<InputTransferToken*>(aInputTransferToken);
+ InputTransferToken_release(inputTransferToken);
+}
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index 35e37b2..b2925bf 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -98,6 +98,9 @@
AInputQueue_getEvent;
AInputQueue_hasEvents;
AInputQueue_preDispatchEvent;
+ AInputTransferToken_fromJava; # introduced=35
+ AInputTransferToken_release; # introduced=35
+ AInputTransferToken_toJava; # introduced=35
AKeyEvent_getAction;
AKeyEvent_getDownTime;
AKeyEvent_getEventTime;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index a055db2..d49b4e3 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -9082,7 +9082,7 @@
Objects.requireNonNull(outInputChannel);
synchronized (mGlobalLock) {
WindowState hostWindowState = hostInputTransferToken != null
- ? mInputToWindowMap.get(hostInputTransferToken.mToken) : null;
+ ? mInputToWindowMap.get(hostInputTransferToken.getToken()) : null;
EmbeddedWindowController.EmbeddedWindow win =
new EmbeddedWindowController.EmbeddedWindow(session, this, clientToken,
hostWindowState, callingUid, callingPid, sanitizedType, displayId,
@@ -9111,12 +9111,13 @@
// If the transferToToken exists in the input to window map, it means the request
// is to transfer from embedded to host. Otherwise, the transferToToken
// represents an embedded window so transfer from host to embedded.
- WindowState windowStateTo = mInputToWindowMap.get(transferToToken.mToken);
+ WindowState windowStateTo = mInputToWindowMap.get(transferToToken.getToken());
if (windowStateTo != null) {
didTransfer = mEmbeddedWindowController.transferToHost(transferFromToken,
windowStateTo);
} else {
- WindowState windowStateFrom = mInputToWindowMap.get(transferFromToken.mToken);
+ WindowState windowStateFrom = mInputToWindowMap.get(
+ transferFromToken.getToken());
didTransfer = mEmbeddedWindowController.transferToEmbedded(windowStateFrom,
transferToToken);
}