From 692bbdb3a8ec16753ba37b65bba2b1b09eb3dad7 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Fri, 24 Feb 2023 01:52:13 +0000 Subject: [PATCH 1/2] Get mouse cursor position from PointerController instead of WM PointerController is the source of truth of the mouse cursor position. When the VirtualDevice APIs queried the cursor position, we were previously getting the position from WM. WM's values only update once system_server's global monitor has processed the input event, which leads us into a race condition. Remove the race consition by querying the mouse cursor position directly from PointerController. Bug: 266687189 Test: atest VirtualMouseTest Change-Id: Id0e0e20a0d547f969d3a27d43fdfdca34d0fa7c0 --- libs/input/PointerController.cpp | 39 +++++++++++++------ .../server/input/InputManagerInternal.java | 6 ++- .../server/input/InputManagerService.java | 9 +++-- .../input/NativeInputManagerService.java | 13 +++++++ .../server/wm/InputManagerCallback.java | 6 --- .../server/wm/WindowManagerService.java | 9 ----- ...droid_server_input_InputManagerService.cpp | 20 ++++++++++ 7 files changed, 70 insertions(+), 32 deletions(-) diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp index fedf58d7c6d07..e748c692743d4 100644 --- a/libs/input/PointerController.cpp +++ b/libs/input/PointerController.cpp @@ -262,19 +262,34 @@ void PointerController::reloadPointerResources() { } void PointerController::setDisplayViewport(const DisplayViewport& viewport) { - std::scoped_lock lock(getLock()); + struct PointerDisplayChangeArgs { + int32_t displayId; + float x, y; + }; + std::optional pointerDisplayChanged; - bool getAdditionalMouseResources = false; - if (mLocked.presentation == PointerController::Presentation::POINTER || - mLocked.presentation == PointerController::Presentation::STYLUS_HOVER) { - getAdditionalMouseResources = true; - } - mCursorController.setDisplayViewport(viewport, getAdditionalMouseResources); - if (viewport.displayId != mLocked.pointerDisplayId) { - float xPos, yPos; - mCursorController.getPosition(&xPos, &yPos); - mContext.getPolicy()->onPointerDisplayIdChanged(viewport.displayId, xPos, yPos); - mLocked.pointerDisplayId = viewport.displayId; + { // acquire lock + std::scoped_lock lock(getLock()); + + bool getAdditionalMouseResources = false; + if (mLocked.presentation == PointerController::Presentation::POINTER || + mLocked.presentation == PointerController::Presentation::STYLUS_HOVER) { + getAdditionalMouseResources = true; + } + mCursorController.setDisplayViewport(viewport, getAdditionalMouseResources); + if (viewport.displayId != mLocked.pointerDisplayId) { + float xPos, yPos; + mCursorController.getPosition(&xPos, &yPos); + mLocked.pointerDisplayId = viewport.displayId; + pointerDisplayChanged = {viewport.displayId, xPos, yPos}; + } + } // release lock + + if (pointerDisplayChanged) { + // Notify the policy without holding the pointer controller lock. + mContext.getPolicy()->onPointerDisplayIdChanged(pointerDisplayChanged->displayId, + pointerDisplayChanged->x, + pointerDisplayChanged->y); } } diff --git a/services/core/java/com/android/server/input/InputManagerInternal.java b/services/core/java/com/android/server/input/InputManagerInternal.java index 4d03e44bfd19e..7e990c6c2f4a3 100644 --- a/services/core/java/com/android/server/input/InputManagerInternal.java +++ b/services/core/java/com/android/server/input/InputManagerInternal.java @@ -96,7 +96,11 @@ public abstract class InputManagerInternal { */ public abstract int getVirtualMousePointerDisplayId(); - /** Gets the current position of the mouse cursor. */ + /** + * Gets the current position of the mouse cursor. + * + * Returns NaN-s as the coordinates if the cursor is not available. + */ public abstract PointF getCursorPosition(); /** diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index b2b22a0a083ad..efc4f11168bbe 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -2863,9 +2863,6 @@ public class InputManagerService extends IInputManager.Stub int getPointerDisplayId(); - /** Gets the x and y coordinates of the cursor's current position. */ - PointF getCursorPosition(); - /** * Notifies window manager that a {@link android.view.MotionEvent#ACTION_DOWN} pointer event * occurred on a window that did not have focus. @@ -3189,7 +3186,11 @@ public class InputManagerService extends IInputManager.Stub @Override public PointF getCursorPosition() { - return mWindowManagerCallbacks.getCursorPosition(); + final float[] p = mNative.getMouseCursorPosition(); + if (p == null || p.length != 2) { + throw new IllegalStateException("Failed to get mouse cursor position"); + } + return new PointF(p[0], p[1]); } @Override diff --git a/services/core/java/com/android/server/input/NativeInputManagerService.java b/services/core/java/com/android/server/input/NativeInputManagerService.java index 22226e88f15f2..5395302d1c320 100644 --- a/services/core/java/com/android/server/input/NativeInputManagerService.java +++ b/services/core/java/com/android/server/input/NativeInputManagerService.java @@ -224,6 +224,16 @@ interface NativeInputManagerService { /** Set whether stylus button reporting through motion events should be enabled. */ void setStylusButtonMotionEventsEnabled(boolean enabled); + /** + * Get the current position of the mouse cursor. + * + * If the mouse cursor is not currently shown, the coordinate values will be NaN-s. + * + * NOTE: This will grab the PointerController's lock, so we must be careful about calling this + * from the InputReader or Display threads, which may result in a deadlock. + */ + float[] getMouseCursorPosition(); + /** The native implementation of InputManagerService methods. */ class NativeImpl implements NativeInputManagerService { /** Pointer to native input manager service object, used by native code. */ @@ -465,5 +475,8 @@ interface NativeInputManagerService { @Override public native void setStylusButtonMotionEventsEnabled(boolean enabled); + + @Override + public native float[] getMouseCursorPosition(); } } diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java index 1e9d451b1a69d..0a47fe09dbd99 100644 --- a/services/core/java/com/android/server/wm/InputManagerCallback.java +++ b/services/core/java/com/android/server/wm/InputManagerCallback.java @@ -25,7 +25,6 @@ import static com.android.server.wm.WindowManagerService.H.ON_POINTER_DOWN_OUTSI import android.annotation.NonNull; import android.annotation.Nullable; -import android.graphics.PointF; import android.os.Debug; import android.os.IBinder; import android.util.Slog; @@ -220,11 +219,6 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal } } - @Override - public PointF getCursorPosition() { - return mService.getLatestMousePosition(); - } - @Override public void onPointerDownOutsideFocus(IBinder touchedToken) { mService.mH.obtainMessage(ON_POINTER_DOWN_OUTSIDE_FOCUS, touchedToken).sendToTarget(); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 45cdacd503a8a..42d23e755b216 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -186,7 +186,6 @@ import android.database.ContentObserver; import android.graphics.Bitmap; import android.graphics.Matrix; import android.graphics.Point; -import android.graphics.PointF; import android.graphics.Rect; import android.graphics.Region; import android.hardware.configstore.V1_0.OptionalBool; @@ -7361,14 +7360,6 @@ public class WindowManagerService extends IWindowManager.Stub .setPointerIconType(PointerIcon.TYPE_DEFAULT); } } - - PointF getLatestMousePosition() { - synchronized (mMousePositionTracker) { - return new PointF(mMousePositionTracker.mLatestMouseX, - mMousePositionTracker.mLatestMouseY); - } - } - void setMousePointerDisplayId(int displayId) { mMousePositionTracker.setPointerDisplayId(displayId); } diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index b4e2fb6ca3e3f..dc43949984f01 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -308,6 +308,7 @@ public: void setMotionClassifierEnabled(bool enabled); std::optional getBluetoothAddress(int32_t deviceId); void setStylusButtonMotionEventsEnabled(bool enabled); + std::array getMouseCursorPosition(); /* --- InputReaderPolicyInterface implementation --- */ @@ -1655,6 +1656,16 @@ bool NativeInputManager::isPerDisplayTouchModeEnabled() { return static_cast(enabled); } +std::array NativeInputManager::getMouseCursorPosition() { + AutoMutex _l(mLock); + const auto pc = mLocked.pointerController.lock(); + if (!pc) return {{std::nanf(""), std::nanf("")}}; + + std::array p{}; + pc->getPosition(&p[0], &p[1]); + return p; +} + // ---------------------------------------------------------------------------- static NativeInputManager* getNativeInputManager(JNIEnv* env, jobject clazz) { @@ -2547,6 +2558,14 @@ static void nativeSetStylusButtonMotionEventsEnabled(JNIEnv* env, jobject native im->setStylusButtonMotionEventsEnabled(enabled); } +static jfloatArray nativeGetMouseCursorPosition(JNIEnv* env, jobject nativeImplObj) { + NativeInputManager* im = getNativeInputManager(env, nativeImplObj); + const std::array p = im->getMouseCursorPosition(); + jfloatArray outArr = env->NewFloatArray(2); + env->SetFloatArrayRegion(outArr, 0, p.size(), p.data()); + return outArr; +} + // ---------------------------------------------------------------------------- static const JNINativeMethod gInputManagerMethods[] = { @@ -2640,6 +2659,7 @@ static const JNINativeMethod gInputManagerMethods[] = { {"getBluetoothAddress", "(I)Ljava/lang/String;", (void*)nativeGetBluetoothAddress}, {"setStylusButtonMotionEventsEnabled", "(Z)V", (void*)nativeSetStylusButtonMotionEventsEnabled}, + {"getMouseCursorPosition", "()[F", (void*)nativeGetMouseCursorPosition}, }; #define FIND_CLASS(var, className) \ From b5dadece430fce65b2698ac662c2ee4ff62a5997 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Tue, 28 Feb 2023 17:43:09 +0000 Subject: [PATCH 2/2] Return values in PointerController's getters Rather than passing pointers in to get output from the functions, return values from getPosition() and getBounds(). Bug: 245989146 Bug: 21566609 Test: Build, presubmit Change-Id: Ie5b44a433c94b6c455486922f6894ccde1f1b127 --- libs/input/MouseCursorController.cpp | 58 +++++++------------ libs/input/MouseCursorController.h | 6 +- libs/input/PointerController.cpp | 24 +++----- libs/input/PointerController.h | 4 +- libs/input/PointerControllerContext.h | 2 +- libs/input/tests/PointerController_test.cpp | 6 +- ...droid_server_input_InputManagerService.cpp | 23 ++++---- 7 files changed, 51 insertions(+), 72 deletions(-) diff --git a/libs/input/MouseCursorController.cpp b/libs/input/MouseCursorController.cpp index 24cfc9d70c9b4..c3984055a2782 100644 --- a/libs/input/MouseCursorController.cpp +++ b/libs/input/MouseCursorController.cpp @@ -63,24 +63,23 @@ MouseCursorController::~MouseCursorController() { mLocked.pointerSprite.clear(); } -bool MouseCursorController::getBounds(float* outMinX, float* outMinY, float* outMaxX, - float* outMaxY) const { +std::optional MouseCursorController::getBounds() const { std::scoped_lock lock(mLock); - return getBoundsLocked(outMinX, outMinY, outMaxX, outMaxY); + return getBoundsLocked(); } -bool MouseCursorController::getBoundsLocked(float* outMinX, float* outMinY, float* outMaxX, - float* outMaxY) const REQUIRES(mLock) { +std::optional MouseCursorController::getBoundsLocked() const REQUIRES(mLock) { if (!mLocked.viewport.isValid()) { - return false; + return {}; } - *outMinX = mLocked.viewport.logicalLeft; - *outMinY = mLocked.viewport.logicalTop; - *outMaxX = mLocked.viewport.logicalRight - 1; - *outMaxY = mLocked.viewport.logicalBottom - 1; - return true; + return FloatRect{ + static_cast(mLocked.viewport.logicalLeft), + static_cast(mLocked.viewport.logicalTop), + static_cast(mLocked.viewport.logicalRight - 1), + static_cast(mLocked.viewport.logicalBottom - 1), + }; } void MouseCursorController::move(float deltaX, float deltaY) { @@ -121,31 +120,19 @@ void MouseCursorController::setPosition(float x, float y) { } void MouseCursorController::setPositionLocked(float x, float y) REQUIRES(mLock) { - float minX, minY, maxX, maxY; - if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) { - if (x <= minX) { - mLocked.pointerX = minX; - } else if (x >= maxX) { - mLocked.pointerX = maxX; - } else { - mLocked.pointerX = x; - } - if (y <= minY) { - mLocked.pointerY = minY; - } else if (y >= maxY) { - mLocked.pointerY = maxY; - } else { - mLocked.pointerY = y; - } - updatePointerLocked(); - } + const auto bounds = getBoundsLocked(); + if (!bounds) return; + + mLocked.pointerX = std::max(bounds->left, std::min(bounds->right, x)); + mLocked.pointerY = std::max(bounds->top, std::min(bounds->bottom, y)); + + updatePointerLocked(); } -void MouseCursorController::getPosition(float* outX, float* outY) const { +FloatPoint MouseCursorController::getPosition() const { std::scoped_lock lock(mLock); - *outX = mLocked.pointerX; - *outY = mLocked.pointerY; + return {mLocked.pointerX, mLocked.pointerY}; } int32_t MouseCursorController::getDisplayId() const { @@ -235,10 +222,9 @@ void MouseCursorController::setDisplayViewport(const DisplayViewport& viewport, // Reset cursor position to center if size or display changed. if (oldViewport.displayId != viewport.displayId || oldDisplayWidth != newDisplayWidth || oldDisplayHeight != newDisplayHeight) { - float minX, minY, maxX, maxY; - if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) { - mLocked.pointerX = (minX + maxX) * 0.5f; - mLocked.pointerY = (minY + maxY) * 0.5f; + if (const auto bounds = getBoundsLocked(); bounds) { + mLocked.pointerX = (bounds->left + bounds->right) * 0.5f; + mLocked.pointerY = (bounds->top + bounds->bottom) * 0.5f; // Reload icon resources for density may be changed. loadResourcesLocked(getAdditionalMouseResources); } else { diff --git a/libs/input/MouseCursorController.h b/libs/input/MouseCursorController.h index db0ab56429b21..26be2a858c4e3 100644 --- a/libs/input/MouseCursorController.h +++ b/libs/input/MouseCursorController.h @@ -43,12 +43,12 @@ public: MouseCursorController(PointerControllerContext& context); ~MouseCursorController(); - bool getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const; + std::optional getBounds() const; void move(float deltaX, float deltaY); void setButtonState(int32_t buttonState); int32_t getButtonState() const; void setPosition(float x, float y); - void getPosition(float* outX, float* outY) const; + FloatPoint getPosition() const; int32_t getDisplayId() const; void fade(PointerControllerInterface::Transition transition); void unfade(PointerControllerInterface::Transition transition); @@ -102,7 +102,7 @@ private: } mLocked GUARDED_BY(mLock); - bool getBoundsLocked(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const; + std::optional getBoundsLocked() const; void setPositionLocked(float x, float y); void updatePointerLocked(); diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp index e748c692743d4..544edc2a716f5 100644 --- a/libs/input/PointerController.cpp +++ b/libs/input/PointerController.cpp @@ -114,16 +114,15 @@ PointerController::PointerController(const sp& PointerController::~PointerController() { mDisplayInfoListener->onPointerControllerDestroyed(); mUnregisterWindowInfosListener(mDisplayInfoListener); - mContext.getPolicy()->onPointerDisplayIdChanged(ADISPLAY_ID_NONE, 0, 0); + mContext.getPolicy()->onPointerDisplayIdChanged(ADISPLAY_ID_NONE, FloatPoint{0, 0}); } std::mutex& PointerController::getLock() const { return mDisplayInfoListener->mLock; } -bool PointerController::getBounds(float* outMinX, float* outMinY, float* outMaxX, - float* outMaxY) const { - return mCursorController.getBounds(outMinX, outMinY, outMaxX, outMaxY); +std::optional PointerController::getBounds() const { + return mCursorController.getBounds(); } void PointerController::move(float deltaX, float deltaY) { @@ -156,15 +155,13 @@ void PointerController::setPosition(float x, float y) { mCursorController.setPosition(transformed.x, transformed.y); } -void PointerController::getPosition(float* outX, float* outY) const { +FloatPoint PointerController::getPosition() const { const int32_t displayId = mCursorController.getDisplayId(); - mCursorController.getPosition(outX, outY); + const auto p = mCursorController.getPosition(); { std::scoped_lock lock(getLock()); const auto& transform = getTransformForDisplayLocked(displayId); - const auto xy = transform.inverse().transform(*outX, *outY); - *outX = xy.x; - *outY = xy.y; + return FloatPoint{transform.inverse().transform(p.x, p.y)}; } } @@ -264,7 +261,7 @@ void PointerController::reloadPointerResources() { void PointerController::setDisplayViewport(const DisplayViewport& viewport) { struct PointerDisplayChangeArgs { int32_t displayId; - float x, y; + FloatPoint cursorPosition; }; std::optional pointerDisplayChanged; @@ -278,18 +275,15 @@ void PointerController::setDisplayViewport(const DisplayViewport& viewport) { } mCursorController.setDisplayViewport(viewport, getAdditionalMouseResources); if (viewport.displayId != mLocked.pointerDisplayId) { - float xPos, yPos; - mCursorController.getPosition(&xPos, &yPos); mLocked.pointerDisplayId = viewport.displayId; - pointerDisplayChanged = {viewport.displayId, xPos, yPos}; + pointerDisplayChanged = {viewport.displayId, mCursorController.getPosition()}; } } // release lock if (pointerDisplayChanged) { // Notify the policy without holding the pointer controller lock. mContext.getPolicy()->onPointerDisplayIdChanged(pointerDisplayChanged->displayId, - pointerDisplayChanged->x, - pointerDisplayChanged->y); + pointerDisplayChanged->cursorPosition); } } diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h index 48d5a5756a696..6d3557c89cc79 100644 --- a/libs/input/PointerController.h +++ b/libs/input/PointerController.h @@ -50,12 +50,12 @@ public: ~PointerController() override; - virtual bool getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const; + virtual std::optional getBounds() const; virtual void move(float deltaX, float deltaY); virtual void setButtonState(int32_t buttonState); virtual int32_t getButtonState() const; virtual void setPosition(float x, float y); - virtual void getPosition(float* outX, float* outY) const; + virtual FloatPoint getPosition() const; virtual int32_t getDisplayId() const; virtual void fade(Transition transition); virtual void unfade(Transition transition); diff --git a/libs/input/PointerControllerContext.h b/libs/input/PointerControllerContext.h index 96d83a5f0d15f..f6f5d3bc51bdd 100644 --- a/libs/input/PointerControllerContext.h +++ b/libs/input/PointerControllerContext.h @@ -81,7 +81,7 @@ public: virtual PointerIconStyle getDefaultPointerIconId() = 0; virtual PointerIconStyle getDefaultStylusIconId() = 0; virtual PointerIconStyle getCustomPointerIconId() = 0; - virtual void onPointerDisplayIdChanged(int32_t displayId, float xPos, float yPos) = 0; + virtual void onPointerDisplayIdChanged(int32_t displayId, const FloatPoint& position) = 0; }; /* diff --git a/libs/input/tests/PointerController_test.cpp b/libs/input/tests/PointerController_test.cpp index c820d0007a4bb..2378d42793a1b 100644 --- a/libs/input/tests/PointerController_test.cpp +++ b/libs/input/tests/PointerController_test.cpp @@ -60,7 +60,7 @@ public: virtual PointerIconStyle getDefaultPointerIconId() override; virtual PointerIconStyle getDefaultStylusIconId() override; virtual PointerIconStyle getCustomPointerIconId() override; - virtual void onPointerDisplayIdChanged(int32_t displayId, float xPos, float yPos) override; + virtual void onPointerDisplayIdChanged(int32_t displayId, const FloatPoint& position) override; bool allResourcesAreLoaded(); bool noResourcesAreLoaded(); @@ -143,8 +143,8 @@ void MockPointerControllerPolicyInterface::loadPointerIconForType(SpriteIcon* ic } void MockPointerControllerPolicyInterface::onPointerDisplayIdChanged(int32_t displayId, - float /*xPos*/, - float /*yPos*/) { + const FloatPoint& /*position*/ +) { latestPointerDisplayId = displayId; } diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index dc43949984f01..da44da4f2838e 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -308,7 +308,7 @@ public: void setMotionClassifierEnabled(bool enabled); std::optional getBluetoothAddress(int32_t deviceId); void setStylusButtonMotionEventsEnabled(bool enabled); - std::array getMouseCursorPosition(); + FloatPoint getMouseCursorPosition(); /* --- InputReaderPolicyInterface implementation --- */ @@ -367,7 +367,7 @@ public: virtual PointerIconStyle getDefaultPointerIconId(); virtual PointerIconStyle getDefaultStylusIconId(); virtual PointerIconStyle getCustomPointerIconId(); - virtual void onPointerDisplayIdChanged(int32_t displayId, float xPos, float yPos); + virtual void onPointerDisplayIdChanged(int32_t displayId, const FloatPoint& position); /* --- If touch mode is enabled per display or global --- */ @@ -731,11 +731,11 @@ std::shared_ptr NativeInputManager::obtainPointerCon return controller; } -void NativeInputManager::onPointerDisplayIdChanged(int32_t pointerDisplayId, float xPos, - float yPos) { +void NativeInputManager::onPointerDisplayIdChanged(int32_t pointerDisplayId, + const FloatPoint& position) { JNIEnv* env = jniEnv(); env->CallVoidMethod(mServiceObj, gServiceClassInfo.onPointerDisplayIdChanged, pointerDisplayId, - xPos, yPos); + position.x, position.y); checkAndClearExceptionFromCallback(env, "onPointerDisplayIdChanged"); } @@ -1656,14 +1656,12 @@ bool NativeInputManager::isPerDisplayTouchModeEnabled() { return static_cast(enabled); } -std::array NativeInputManager::getMouseCursorPosition() { +FloatPoint NativeInputManager::getMouseCursorPosition() { AutoMutex _l(mLock); const auto pc = mLocked.pointerController.lock(); - if (!pc) return {{std::nanf(""), std::nanf("")}}; + if (!pc) return {AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION}; - std::array p{}; - pc->getPosition(&p[0], &p[1]); - return p; + return pc->getPosition(); } // ---------------------------------------------------------------------------- @@ -2560,9 +2558,10 @@ static void nativeSetStylusButtonMotionEventsEnabled(JNIEnv* env, jobject native static jfloatArray nativeGetMouseCursorPosition(JNIEnv* env, jobject nativeImplObj) { NativeInputManager* im = getNativeInputManager(env, nativeImplObj); - const std::array p = im->getMouseCursorPosition(); + const auto p = im->getMouseCursorPosition(); + const std::array arr = {{p.x, p.y}}; jfloatArray outArr = env->NewFloatArray(2); - env->SetFloatArrayRegion(outArr, 0, p.size(), p.data()); + env->SetFloatArrayRegion(outArr, 0, arr.size(), arr.data()); return outArr; }