From 296c6554a0fd714b033c1f5c49b2d4dced885927 Mon Sep 17 00:00:00 2001 From: chaviw Date: Wed, 9 Jun 2021 15:14:15 -0500 Subject: [PATCH] Add Java and JNI WindowInfosChangedListener hooks to register with SCC Bug: 188792659 Test: Existing tests pass Change-Id: I0a6fa58e1c8648bf1d9d30f5e2c59e056a07cb88 --- .../android/window/WindowInfosListener.java | 63 ++++++++ core/jni/Android.bp | 2 + core/jni/AndroidRuntime.cpp | 3 + core/jni/OWNERS | 1 + ..._hardware_input_InputApplicationHandle.cpp | 19 +++ ...id_hardware_input_InputApplicationHandle.h | 3 + ...droid_hardware_input_InputWindowHandle.cpp | 89 +++++++++++- ...android_hardware_input_InputWindowHandle.h | 3 + .../android_window_WindowInfosListener.cpp | 134 ++++++++++++++++++ 9 files changed, 311 insertions(+), 6 deletions(-) create mode 100644 core/java/android/window/WindowInfosListener.java create mode 100644 core/jni/android_window_WindowInfosListener.cpp diff --git a/core/java/android/window/WindowInfosListener.java b/core/java/android/window/WindowInfosListener.java new file mode 100644 index 0000000000000..4376e3eb572ef --- /dev/null +++ b/core/java/android/window/WindowInfosListener.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2021 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. + */ + +package android.window; + +import android.view.InputWindowHandle; + +import libcore.util.NativeAllocationRegistry; + +/** + * Listener for getting {@link InputWindowHandle} updates from SurfaceFlinger. + * @hide + */ +public abstract class WindowInfosListener { + private final long mNativeListener; + + public WindowInfosListener() { + NativeAllocationRegistry registry = NativeAllocationRegistry.createMalloced( + WindowInfosListener.class.getClassLoader(), nativeGetFinalizer()); + + mNativeListener = nativeCreate(this); + registry.registerNativeAllocation(this, mNativeListener); + } + + /** + * Called when WindowInfos in SurfaceFlinger have changed. + * @param windowHandles Reverse Z ordered array of window information that was on screen, + * where the first value is the topmost window. + */ + public abstract void onWindowInfosChanged(InputWindowHandle[] windowHandles); + + /** + * Register the WindowInfosListener. + */ + public void register() { + nativeRegister(mNativeListener); + } + + /** + * Unregisters the WindowInfosListener. + */ + public void unregister() { + nativeUnregister(mNativeListener); + } + + private static native long nativeCreate(WindowInfosListener thiz); + private static native void nativeRegister(long ptr); + private static native void nativeUnregister(long ptr); + private static native long nativeGetFinalizer(); +} diff --git a/core/jni/Android.bp b/core/jni/Android.bp index 98fc84c64de0c..5f4c0c12dfa11 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -224,6 +224,7 @@ cc_library_shared { "fd_utils.cpp", "android_hardware_input_InputWindowHandle.cpp", "android_hardware_input_InputApplicationHandle.cpp", + "android_window_WindowInfosListener.cpp", ], static_libs: [ @@ -236,6 +237,7 @@ cc_library_shared { "libgrallocusage", "libscrypt_static", "libstatssocket_lazy", + "libskia", ], shared_libs: [ diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 2fd1e543cc5bc..c18d227fa6748 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -207,6 +207,7 @@ extern int register_com_android_internal_os_ZygoteCommandBuffer(JNIEnv *env); extern int register_com_android_internal_os_ZygoteInit(JNIEnv *env); extern int register_com_android_internal_security_VerityUtils(JNIEnv* env); extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env); +extern int register_android_window_WindowInfosListener(JNIEnv* env); // Namespace for Android Runtime flags applied during boot time. static const char* RUNTIME_NATIVE_BOOT_NAMESPACE = "runtime_native_boot"; @@ -1649,6 +1650,8 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_com_android_internal_os_KernelCpuUidBpfMapReader), REG_JNI(register_com_android_internal_os_KernelSingleProcessCpuThreadReader), REG_JNI(register_com_android_internal_os_KernelSingleUidTimeReader), + + REG_JNI(register_android_window_WindowInfosListener), }; /* diff --git a/core/jni/OWNERS b/core/jni/OWNERS index 666ab957b8ced..af77cb7aae8db 100644 --- a/core/jni/OWNERS +++ b/core/jni/OWNERS @@ -22,6 +22,7 @@ per-file android_view_PointerIcon.* = file:/services/core/java/com/android/serve # WindowManager per-file android_graphics_BLASTBufferQueue.cpp = file:/services/core/java/com/android/server/wm/OWNERS per-file android_view_Surface* = file:/services/core/java/com/android/server/wm/OWNERS +per-file android_window_WindowInfosListener.cpp = file:/services/core/java/com/android/server/wm/OWNERS # Resources per-file android_content_res_* = file:/core/java/android/content/res/OWNERS diff --git a/core/jni/android_hardware_input_InputApplicationHandle.cpp b/core/jni/android_hardware_input_InputApplicationHandle.cpp index 995bfa97ab2e8..24d35316ef208 100644 --- a/core/jni/android_hardware_input_InputApplicationHandle.cpp +++ b/core/jni/android_hardware_input_InputApplicationHandle.cpp @@ -28,6 +28,8 @@ namespace android { static struct { + jclass clazz; + jmethodID ctor; jfieldID ptr; jfieldID name; jfieldID dispatchingTimeoutMillis; @@ -101,6 +103,15 @@ std::shared_ptr android_view_InputApplicationHandle_getH return *handle; } +jobject android_view_InputApplicationHandle_fromInputApplicationInfo( + JNIEnv* env, gui::InputApplicationInfo inputApplicationInfo) { + jobject binderObject = javaObjectForIBinder(env, inputApplicationInfo.token); + ScopedLocalRef name(env, env->NewStringUTF(inputApplicationInfo.name.data())); + return env->NewObject(gInputApplicationHandleClassInfo.clazz, + gInputApplicationHandleClassInfo.ctor, binderObject, name.get(), + inputApplicationInfo.dispatchingTimeoutMillis); +} + // --- JNI --- static void android_view_InputApplicationHandle_nativeDispose(JNIEnv* env, jobject obj) { @@ -131,6 +142,10 @@ static const JNINativeMethod gInputApplicationHandleMethods[] = { var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ LOG_FATAL_IF(! (var), "Unable to find field " fieldName); +#define GET_METHOD_ID(var, clazz, methodName, methodSignature) \ + var = env->GetMethodID(clazz, methodName, methodSignature); \ + LOG_ALWAYS_FATAL_IF(!(var), "Unable to find method " methodName); + int register_android_view_InputApplicationHandle(JNIEnv* env) { int res = jniRegisterNativeMethods(env, "android/view/InputApplicationHandle", gInputApplicationHandleMethods, NELEM(gInputApplicationHandleMethods)); @@ -139,6 +154,10 @@ int register_android_view_InputApplicationHandle(JNIEnv* env) { jclass clazz; FIND_CLASS(clazz, "android/view/InputApplicationHandle"); + gInputApplicationHandleClassInfo.clazz = MakeGlobalRefOrDie(env, clazz); + + GET_METHOD_ID(gInputApplicationHandleClassInfo.ctor, clazz, "", + "(Landroid/os/IBinder;Ljava/lang/String;J)V"); GET_FIELD_ID(gInputApplicationHandleClassInfo.ptr, clazz, "ptr", "J"); diff --git a/core/jni/android_hardware_input_InputApplicationHandle.h b/core/jni/android_hardware_input_InputApplicationHandle.h index 7eb7ac4bc305b..5d88d8e251607 100644 --- a/core/jni/android_hardware_input_InputApplicationHandle.h +++ b/core/jni/android_hardware_input_InputApplicationHandle.h @@ -42,6 +42,9 @@ private: extern std::shared_ptr android_view_InputApplicationHandle_getHandle( JNIEnv* env, jobject inputApplicationHandleObj); +extern jobject android_view_InputApplicationHandle_fromInputApplicationInfo( + JNIEnv* env, gui::InputApplicationInfo inputApplicationInfo); + } // namespace android #endif // _ANDROID_VIEW_INPUT_APPLICATION_HANDLE_H diff --git a/core/jni/android_hardware_input_InputWindowHandle.cpp b/core/jni/android_hardware_input_InputWindowHandle.cpp index afc44ff808a90..3f51dd8617c17 100644 --- a/core/jni/android_hardware_input_InputWindowHandle.cpp +++ b/core/jni/android_hardware_input_InputWindowHandle.cpp @@ -27,6 +27,7 @@ #include #include +#include "SkRegion.h" #include "android_hardware_input_InputApplicationHandle.h" #include "android_util_Binder.h" #include "core_jni_helpers.h" @@ -44,6 +45,8 @@ struct WeakRefHandleField { }; static struct { + jclass clazz; + jmethodID ctor; jfieldID ptr; jfieldID inputApplicationHandle; jfieldID token; @@ -69,11 +72,16 @@ static struct { jfieldID packageName; jfieldID inputFeatures; jfieldID displayId; - jfieldID portalToDisplayId; jfieldID replaceTouchableRegionWithCrop; WeakRefHandleField touchableRegionSurfaceControl; } gInputWindowHandleClassInfo; +static struct { + jclass clazz; + jmethodID ctor; + jfieldID nativeRegion; +} gRegionClassInfo; + static Mutex gHandleMutex; @@ -166,8 +174,6 @@ bool NativeInputWindowHandle::updateInfo() { env->GetIntField(obj, gInputWindowHandleClassInfo.inputFeatures)); mInfo.displayId = env->GetIntField(obj, gInputWindowHandleClassInfo.displayId); - mInfo.portalToDisplayId = env->GetIntField(obj, - gInputWindowHandleClassInfo.portalToDisplayId); jobject inputApplicationHandleObj = env->GetObjectField(obj, gInputWindowHandleClassInfo.inputApplicationHandle); @@ -236,6 +242,71 @@ sp android_view_InputWindowHandle_getHandle( return handle; } +jobject android_view_InputWindowHandle_fromWindowInfo(JNIEnv* env, gui::WindowInfo windowInfo) { + ScopedLocalRef + applicationHandle(env, + android_view_InputApplicationHandle_fromInputApplicationInfo( + env, windowInfo.applicationInfo)); + + jobject inputWindowHandle = + env->NewObject(gInputWindowHandleClassInfo.clazz, gInputWindowHandleClassInfo.ctor, + applicationHandle.get(), windowInfo.displayId); + env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.token, + javaObjectForIBinder(env, windowInfo.token)); + env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.name, + env->NewStringUTF(windowInfo.name.data())); + env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.layoutParamsFlags, + static_cast(windowInfo.flags.get())); + env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.layoutParamsType, + static_cast(windowInfo.type)); + env->SetLongField(inputWindowHandle, gInputWindowHandleClassInfo.dispatchingTimeoutMillis, + std::chrono::duration_cast( + windowInfo.dispatchingTimeout) + .count()); + env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.frameLeft, + windowInfo.frameLeft); + env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.frameTop, windowInfo.frameTop); + env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.frameRight, + windowInfo.frameRight); + env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.frameBottom, + windowInfo.frameBottom); + env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.surfaceInset, + windowInfo.surfaceInset); + env->SetFloatField(inputWindowHandle, gInputWindowHandleClassInfo.scaleFactor, + windowInfo.globalScaleFactor); + + SkRegion* region = new SkRegion(); + for (const auto& r : windowInfo.touchableRegion) { + region->op({r.left, r.top, r.right, r.bottom}, SkRegion::kUnion_Op); + } + ScopedLocalRef regionObj(env, + env->NewObject(gRegionClassInfo.clazz, + gRegionClassInfo.ctor)); + env->SetLongField(regionObj.get(), gRegionClassInfo.nativeRegion, + reinterpret_cast(region)); + env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.touchableRegion, + regionObj.get()); + + env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.visible, + windowInfo.visible); + env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.focusable, + windowInfo.focusable); + env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.hasWallpaper, + windowInfo.hasWallpaper); + env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.paused, windowInfo.paused); + env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.trustedOverlay, + windowInfo.trustedOverlay); + env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.touchOcclusionMode, + static_cast(windowInfo.touchOcclusionMode)); + env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.ownerPid, windowInfo.ownerPid); + env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.ownerUid, windowInfo.ownerUid); + env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.packageName, + env->NewStringUTF(windowInfo.packageName.data())); + env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.inputFeatures, + static_cast(windowInfo.inputFeatures.get())); + + return inputWindowHandle; +} // --- JNI --- @@ -278,6 +349,10 @@ int register_android_view_InputWindowHandle(JNIEnv* env) { jclass clazz; FIND_CLASS(clazz, "android/view/InputWindowHandle"); + gInputWindowHandleClassInfo.clazz = MakeGlobalRefOrDie(env, clazz); + + GET_METHOD_ID(gInputWindowHandleClassInfo.ctor, clazz, "", + "(Landroid/view/InputApplicationHandle;I)V"); GET_FIELD_ID(gInputWindowHandleClassInfo.ptr, clazz, "ptr", "J"); @@ -351,9 +426,6 @@ int register_android_view_InputWindowHandle(JNIEnv* env) { GET_FIELD_ID(gInputWindowHandleClassInfo.displayId, clazz, "displayId", "I"); - GET_FIELD_ID(gInputWindowHandleClassInfo.portalToDisplayId, clazz, - "portalToDisplayId", "I"); - GET_FIELD_ID(gInputWindowHandleClassInfo.replaceTouchableRegionWithCrop, clazz, "replaceTouchableRegionWithCrop", "Z"); @@ -371,6 +443,11 @@ int register_android_view_InputWindowHandle(JNIEnv* env) { GET_FIELD_ID(gInputWindowHandleClassInfo.touchableRegionSurfaceControl.mNativeObject, surfaceControlClazz, "mNativeObject", "J"); + jclass regionClazz; + FIND_CLASS(regionClazz, "android/graphics/Region"); + gRegionClassInfo.clazz = MakeGlobalRefOrDie(env, regionClazz); + GET_METHOD_ID(gRegionClassInfo.ctor, gRegionClassInfo.clazz, "", "()V"); + GET_FIELD_ID(gRegionClassInfo.nativeRegion, gRegionClassInfo.clazz, "mNativeRegion", "J"); return 0; } diff --git a/core/jni/android_hardware_input_InputWindowHandle.h b/core/jni/android_hardware_input_InputWindowHandle.h index 635480fc5abc3..408e0f1bfa367 100644 --- a/core/jni/android_hardware_input_InputWindowHandle.h +++ b/core/jni/android_hardware_input_InputWindowHandle.h @@ -40,6 +40,9 @@ private: extern sp android_view_InputWindowHandle_getHandle( JNIEnv* env, jobject inputWindowHandleObj); +extern jobject android_view_InputWindowHandle_fromWindowInfo(JNIEnv* env, + gui::WindowInfo windowInfo); + } // namespace android #endif // _ANDROID_VIEW_INPUT_WINDOW_HANDLE_H diff --git a/core/jni/android_window_WindowInfosListener.cpp b/core/jni/android_window_WindowInfosListener.cpp new file mode 100644 index 0000000000000..ab88b537f96bc --- /dev/null +++ b/core/jni/android_window_WindowInfosListener.cpp @@ -0,0 +1,134 @@ +/* + * Copyright 2021 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 "WindowInfosListener" + +#include +#include +#include +#include +#include + +#include "android_hardware_input_InputWindowHandle.h" +#include "core_jni_helpers.h" + +namespace android { + +using gui::WindowInfo; + +namespace { + +static struct { + jclass clazz; + jmethodID onWindowInfosChanged; +} gListenerClassInfo; + +static jclass gInputWindowHandleClass; + +struct WindowInfosListener : public gui::WindowInfosListener { + WindowInfosListener(JNIEnv* env, jobject listener) + : mListener(env->NewWeakGlobalRef(listener)) {} + + void onWindowInfosChanged(const std::vector& windowInfos) override { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + LOG_ALWAYS_FATAL_IF(env == nullptr, "Unable to retrieve JNIEnv in onWindowInfoChanged."); + + jobject listener = env->NewGlobalRef(mListener); + if (listener == nullptr) { + // Weak reference went out of scope + return; + } + + jobjectArray jWindowHandlesArray = + env->NewObjectArray(windowInfos.size(), gInputWindowHandleClass, nullptr); + for (int i = 0; i < windowInfos.size(); i++) { + ScopedLocalRef + jWindowHandle(env, + android_view_InputWindowHandle_fromWindowInfo(env, + windowInfos[i])); + env->SetObjectArrayElement(jWindowHandlesArray, i, jWindowHandle.get()); + } + + env->CallVoidMethod(listener, gListenerClassInfo.onWindowInfosChanged, jWindowHandlesArray); + env->DeleteGlobalRef(listener); + + if (env->ExceptionCheck()) { + ALOGE("WindowInfosListener.onWindowInfosChanged() failed."); + LOGE_EX(env); + env->ExceptionClear(); + } + } + + ~WindowInfosListener() override { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + env->DeleteWeakGlobalRef(mListener); + } + +private: + jweak mListener; +}; + +jlong nativeCreate(JNIEnv* env, jclass clazz, jobject obj) { + WindowInfosListener* listener = new WindowInfosListener(env, obj); + listener->incStrong((void*)nativeCreate); + return reinterpret_cast(listener); +} + +void destroyNativeService(void* ptr) { + WindowInfosListener* listener = reinterpret_cast(ptr); + listener->decStrong((void*)nativeCreate); +} + +void nativeRegister(JNIEnv* env, jclass clazz, jlong ptr) { + sp listener = reinterpret_cast(ptr); + SurfaceComposerClient::getDefault()->addWindowInfosListener(listener); +} + +void nativeUnregister(JNIEnv* env, jclass clazz, jlong ptr) { + sp listener = reinterpret_cast(ptr); + SurfaceComposerClient::getDefault()->removeWindowInfosListener(listener); +} + +static jlong nativeGetFinalizer(JNIEnv* /* env */, jclass /* clazz */) { + return static_cast(reinterpret_cast(&destroyNativeService)); +} + +const JNINativeMethod gMethods[] = { + /* name, signature, funcPtr */ + {"nativeCreate", "(Landroid/window/WindowInfosListener;)J", (void*)nativeCreate}, + {"nativeRegister", "(J)V", (void*)nativeRegister}, + {"nativeUnregister", "(J)V", (void*)nativeUnregister}, + {"nativeGetFinalizer", "()J", (void*)nativeGetFinalizer}}; + +} // namespace + +int register_android_window_WindowInfosListener(JNIEnv* env) { + int res = jniRegisterNativeMethods(env, "android/window/WindowInfosListener", gMethods, + NELEM(gMethods)); + LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods."); + + jclass clazz = env->FindClass("android/window/WindowInfosListener"); + gListenerClassInfo.clazz = MakeGlobalRefOrDie(env, clazz); + gListenerClassInfo.onWindowInfosChanged = + env->GetMethodID(gListenerClassInfo.clazz, "onWindowInfosChanged", + "([Landroid/view/InputWindowHandle;)V"); + + clazz = env->FindClass("android/view/InputWindowHandle"); + gInputWindowHandleClass = MakeGlobalRefOrDie(env, clazz); + return 0; +} + +} // namespace android