From b94da308c86bed6b89043aaced3724c2710ab4a0 Mon Sep 17 00:00:00 2001 From: Chavi Weingarten <chaviw@google.com> Date: Thu, 29 Feb 2024 16:33:27 +0000 Subject: [PATCH] Add native InputTransferToken Added a native class that corresponds to the Java InputTransferToken. Test: SurfaceControlInputReceiverTests Test: AInputTransferTokenTest Bug: 324271765 Change-Id: Ic5549227ad8c8ab311f8953eaf370e1a2896d8f3 --- .../android/window/InputTransferToken.java | 44 ++++-- core/jni/Android.bp | 1 + core/jni/AndroidRuntime.cpp | 2 + .../jni/android_window_InputTransferToken.cpp | 138 ++++++++++++++++++ .../android_window_InputTransferToken.h | 33 +++++ native/android/Android.bp | 1 + native/android/input_transfer_token.cpp | 63 ++++++++ native/android/libandroid.map.txt | 3 + .../server/wm/WindowManagerService.java | 7 +- 9 files changed, 279 insertions(+), 13 deletions(-) create mode 100644 core/jni/android_window_InputTransferToken.cpp create mode 100644 core/jni/include/android_runtime/android_window_InputTransferToken.h create mode 100644 native/android/input_transfer_token.cpp diff --git a/core/java/android/window/InputTransferToken.java b/core/java/android/window/InputTransferToken.java index e572853e5d5d..c62eee40da98 100644 --- a/core/java/android/window/InputTransferToken.java +++ b/core/java/android/window/InputTransferToken.java @@ -18,7 +18,6 @@ package android.window; 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 android.view.SurfaceControlViewHost; import com.android.window.flags.Flags; +import libcore.util.NativeAllocationRegistry; + import java.util.Objects; /** @@ -51,28 +52,51 @@ import java.util.Objects; */ @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 @@ public final class InputTransferToken implements Parcelable { */ @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 @@ public final class InputTransferToken implements Parcelable { } }; - /** * @hide */ @Override public int hashCode() { - return Objects.hash(mToken); + return Objects.hash(getToken()); } /** @@ -118,7 +141,8 @@ public final class InputTransferToken implements Parcelable { 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 76e71380017c..77c6436a8c43 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -265,6 +265,7 @@ cc_library_shared_for_libandroid_runtime { "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 aa63f4fa03d4..9bbd19122153 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -221,6 +221,7 @@ extern int register_jni_common(JNIEnv* env); 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 @@ static const RegJNIRec gRegJNI[] = { 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 000000000000..60568e30ccb2 --- /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 000000000000..75dbe37f781f --- /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 752ebdf3d0e3..481268516b51 100644 --- a/native/android/Android.bp +++ b/native/android/Android.bp @@ -58,6 +58,7 @@ cc_library_shared { "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 000000000000..501e1d312bfc --- /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 35e37b2a6893..b2925bfa6881 100644 --- a/native/android/libandroid.map.txt +++ b/native/android/libandroid.map.txt @@ -98,6 +98,9 @@ LIBANDROID { 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 a055db274ae8..d49b4e3795ee 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 @@ public class WindowManagerService extends IWindowManager.Stub 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 @@ public class WindowManagerService extends IWindowManager.Stub // 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); } -- GitLab