diff options
-rw-r--r-- | core/java/android/view/ThreadedRenderer.java | 8 | ||||
-rw-r--r-- | core/java/android/view/ViewFrameInfo.java | 81 | ||||
-rw-r--r-- | core/java/android/view/ViewRootImpl.java | 24 | ||||
-rw-r--r-- | graphics/java/android/graphics/FrameInfo.java | 40 | ||||
-rw-r--r-- | libs/hwui/FrameInfo.cpp | 6 | ||||
-rw-r--r-- | libs/hwui/FrameInfo.h | 3 | ||||
-rw-r--r-- | services/core/jni/com_android_server_input_InputManagerService.cpp | 20 | ||||
-rw-r--r-- | tests/Input/Android.bp | 1 | ||||
-rw-r--r-- | tests/Input/src/com/android/test/input/ViewFrameInfoTest.kt | 78 |
9 files changed, 210 insertions, 51 deletions
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index 57ca71ae4b02..d839e3532b64 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -21,6 +21,7 @@ import android.annotation.Nullable; import android.app.ActivityManager; import android.content.Context; import android.content.res.TypedArray; +import android.graphics.FrameInfo; import android.graphics.HardwareRenderer; import android.graphics.Picture; import android.graphics.Point; @@ -610,8 +611,7 @@ public final class ThreadedRenderer extends HardwareRenderer { * @param attachInfo AttachInfo tied to the specified view. */ void draw(View view, AttachInfo attachInfo, DrawCallbacks callbacks) { - final Choreographer choreographer = attachInfo.mViewRootImpl.mChoreographer; - choreographer.mFrameInfo.markDrawStart(); + attachInfo.mViewRootImpl.mViewFrameInfo.markDrawStart(); updateRootDisplayList(view, callbacks); @@ -629,7 +629,9 @@ public final class ThreadedRenderer extends HardwareRenderer { attachInfo.mPendingAnimatingRenderNodes = null; } - int syncResult = syncAndDrawFrame(choreographer.mFrameInfo); + final FrameInfo frameInfo = attachInfo.mViewRootImpl.getUpdatedFrameInfo(); + + int syncResult = syncAndDrawFrame(frameInfo); if ((syncResult & SYNC_LOST_SURFACE_REWARD_IF_FOUND) != 0) { Log.w("OpenGLRenderer", "Surface lost, forcing relayout"); // We lost our surface. For a relayout next frame which should give us a new diff --git a/core/java/android/view/ViewFrameInfo.java b/core/java/android/view/ViewFrameInfo.java new file mode 100644 index 000000000000..890d071f8090 --- /dev/null +++ b/core/java/android/view/ViewFrameInfo.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2020 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.view; + +import android.graphics.FrameInfo; + +/** + * The timing information of events taking place in ViewRootImpl + * @hide + */ +public class ViewFrameInfo { + public long drawStart; + public long oldestInputEventTime; // the time of the oldest input event consumed for this frame + public long newestInputEventTime; // the time of the newest input event consumed for this frame + // Various flags set to provide extra metadata about the current frame. See flag definitions + // inside FrameInfo. + // @see android.graphics.FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED + public long flags; + + /** + * Update the oldest event time. + * @param eventTime the time of the input event + */ + public void updateOldestInputEvent(long eventTime) { + if (oldestInputEventTime == 0 || eventTime < oldestInputEventTime) { + oldestInputEventTime = eventTime; + } + } + + /** + * Update the newest event time. + * @param eventTime the time of the input event + */ + public void updateNewestInputEvent(long eventTime) { + if (newestInputEventTime == 0 || eventTime > newestInputEventTime) { + newestInputEventTime = eventTime; + } + } + + /** + * Populate the missing fields using the data from ViewFrameInfo + * @param frameInfo : the structure FrameInfo object to populate + */ + public void populateFrameInfo(FrameInfo frameInfo) { + frameInfo.frameInfo[FrameInfo.FLAGS] |= flags; + frameInfo.frameInfo[FrameInfo.DRAW_START] = drawStart; + frameInfo.frameInfo[FrameInfo.OLDEST_INPUT_EVENT] = oldestInputEventTime; + frameInfo.frameInfo[FrameInfo.NEWEST_INPUT_EVENT] = newestInputEventTime; + } + + /** + * Reset this data. Should typically be invoked after calling "populateFrameInfo". + */ + public void reset() { + drawStart = 0; + oldestInputEventTime = 0; + newestInputEventTime = 0; + flags = 0; + } + + /** + * Record the current time, and store it in 'drawStart' + */ + public void markDrawStart() { + drawStart = System.nanoTime(); + } +} diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 2bea0d6b4b04..ae162ede2c70 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -423,7 +423,7 @@ public final class ViewRootImpl implements ViewParent, @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) int mHeight; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - Rect mDirty; + private Rect mDirty; public boolean mIsAnimating; private boolean mUseMTRenderer; @@ -446,6 +446,23 @@ public final class ViewRootImpl implements ViewParent, @UnsupportedAppUsage FallbackEventHandler mFallbackEventHandler; final Choreographer mChoreographer; + protected final ViewFrameInfo mViewFrameInfo = new ViewFrameInfo(); + + /** + * Update the Choreographer's FrameInfo object with the timing information for the current + * ViewRootImpl instance. Erase the data in the current ViewFrameInfo to prepare for the next + * frame. + * @return the updated FrameInfo object + */ + protected @NonNull FrameInfo getUpdatedFrameInfo() { + // Since Choreographer is a thread-local singleton while we can have multiple + // ViewRootImpl's, populate the frame information from the current viewRootImpl before + // starting the draw + FrameInfo frameInfo = mChoreographer.mFrameInfo; + mViewFrameInfo.populateFrameInfo(frameInfo); + mViewFrameInfo.reset(); + return frameInfo; + } // used in relayout to get SurfaceControl size // for BLAST adapter surface setup @@ -2675,7 +2692,7 @@ public final class ViewRootImpl implements ViewParent, // to resume them mDirty.set(0, 0, mWidth, mHeight); } - mChoreographer.mFrameInfo.addFlags(FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED); + mViewFrameInfo.flags |= FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED; } relayoutResult = relayoutWindow(params, viewVisibility, insetsPending); @@ -8138,7 +8155,8 @@ public final class ViewRootImpl implements ViewParent, oldestEventTime = me.getHistoricalEventTimeNano(0); } } - mChoreographer.mFrameInfo.updateInputEventTime(eventTime, oldestEventTime); + mViewFrameInfo.updateOldestInputEvent(oldestEventTime); + mViewFrameInfo.updateNewestInputEvent(eventTime); deliverInputEvent(q); } diff --git a/graphics/java/android/graphics/FrameInfo.java b/graphics/java/android/graphics/FrameInfo.java index 0061ea13f647..d59abb5916a0 100644 --- a/graphics/java/android/graphics/FrameInfo.java +++ b/graphics/java/android/graphics/FrameInfo.java @@ -43,7 +43,7 @@ public final class FrameInfo { public long[] frameInfo = new long[FRAME_INFO_SIZE]; // Various flags set to provide extra metadata about the current frame - private static final int FLAGS = 0; + public static final int FLAGS = 0; // Is this the first-draw following a window layout? public static final long FLAG_WINDOW_LAYOUT_CHANGED = 1; @@ -60,35 +60,35 @@ public final class FrameInfo { @Retention(RetentionPolicy.SOURCE) public @interface FrameInfoFlags {} - private static final int FRAME_TIMELINE_VSYNC_ID = 1; + public static final int FRAME_TIMELINE_VSYNC_ID = 1; // The intended vsync time, unadjusted by jitter - private static final int INTENDED_VSYNC = 2; + public static final int INTENDED_VSYNC = 2; // Jitter-adjusted vsync time, this is what was used as input into the // animation & drawing system - private static final int VSYNC = 3; + public static final int VSYNC = 3; // The time of the oldest input event - private static final int OLDEST_INPUT_EVENT = 4; + public static final int OLDEST_INPUT_EVENT = 4; // The time of the newest input event - private static final int NEWEST_INPUT_EVENT = 5; + public static final int NEWEST_INPUT_EVENT = 5; // When input event handling started - private static final int HANDLE_INPUT_START = 6; + public static final int HANDLE_INPUT_START = 6; // When animation evaluations started - private static final int ANIMATION_START = 7; + public static final int ANIMATION_START = 7; // When ViewRootImpl#performTraversals() started - private static final int PERFORM_TRAVERSALS_START = 8; + public static final int PERFORM_TRAVERSALS_START = 8; // When View:draw() started - private static final int DRAW_START = 9; + public static final int DRAW_START = 9; // When the frame needs to be ready by - private static final int FRAME_DEADLINE = 10; + public static final int FRAME_DEADLINE = 10; // Must be the last one private static final int FRAME_INFO_SIZE = FRAME_DEADLINE + 1; @@ -99,23 +99,11 @@ public final class FrameInfo { frameInfo[FRAME_TIMELINE_VSYNC_ID] = frameTimelineVsyncId; frameInfo[INTENDED_VSYNC] = intendedVsync; frameInfo[VSYNC] = usedVsync; - frameInfo[OLDEST_INPUT_EVENT] = Long.MAX_VALUE; - frameInfo[NEWEST_INPUT_EVENT] = 0; frameInfo[FLAGS] = 0; frameInfo[FRAME_DEADLINE] = frameDeadline; } /** checkstyle */ - public void updateInputEventTime(long inputEventTime, long inputEventOldestTime) { - if (inputEventOldestTime < frameInfo[OLDEST_INPUT_EVENT]) { - frameInfo[OLDEST_INPUT_EVENT] = inputEventOldestTime; - } - if (inputEventTime > frameInfo[NEWEST_INPUT_EVENT]) { - frameInfo[NEWEST_INPUT_EVENT] = inputEventTime; - } - } - - /** checkstyle */ public void markInputHandlingStart() { frameInfo[HANDLE_INPUT_START] = System.nanoTime(); } @@ -131,13 +119,7 @@ public final class FrameInfo { } /** checkstyle */ - public void markDrawStart() { - frameInfo[DRAW_START] = System.nanoTime(); - } - - /** checkstyle */ public void addFlags(@FrameInfoFlags long flags) { frameInfo[FLAGS] |= flags; } - } diff --git a/libs/hwui/FrameInfo.cpp b/libs/hwui/FrameInfo.cpp index fd18d2f9192d..8b20492543f7 100644 --- a/libs/hwui/FrameInfo.cpp +++ b/libs/hwui/FrameInfo.cpp @@ -20,7 +20,7 @@ namespace android { namespace uirenderer { -const std::string FrameInfoNames[] = { +const std::array<std::string, static_cast<int>(FrameInfoIndex::NumIndexes)> FrameInfoNames = { "Flags", "FrameTimelineVsyncId", "IntendedVsync", @@ -42,10 +42,6 @@ const std::string FrameInfoNames[] = { "GpuCompleted", }; -static_assert((sizeof(FrameInfoNames) / sizeof(FrameInfoNames[0])) == - static_cast<int>(FrameInfoIndex::NumIndexes), - "size mismatch: FrameInfoNames doesn't match the enum!"); - static_assert(static_cast<int>(FrameInfoIndex::NumIndexes) == 19, "Must update value in FrameMetrics.java#FRAME_STATS_COUNT (and here)"); diff --git a/libs/hwui/FrameInfo.h b/libs/hwui/FrameInfo.h index bb875e35f6f7..738246d56d0d 100644 --- a/libs/hwui/FrameInfo.h +++ b/libs/hwui/FrameInfo.h @@ -21,6 +21,7 @@ #include <cutils/compiler.h> #include <utils/Timers.h> +#include <array> #include <memory.h> #include <string> @@ -60,7 +61,7 @@ enum class FrameInfoIndex { NumIndexes }; -extern const std::string FrameInfoNames[]; +extern const std::array<std::string, static_cast<int>(FrameInfoIndex::NumIndexes)> FrameInfoNames; namespace FrameInfoFlags { enum { diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index 9e0fb567975a..13450be73d88 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -238,16 +238,16 @@ public: /* --- InputReaderPolicyInterface implementation --- */ - virtual void getReaderConfiguration(InputReaderConfiguration* outConfig); - virtual std::shared_ptr<PointerControllerInterface> obtainPointerController(int32_t deviceId); - virtual void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices); - virtual std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay( - const InputDeviceIdentifier& identifier); - virtual std::string getDeviceAlias(const InputDeviceIdentifier& identifier); - virtual TouchAffineTransformation getTouchAffineTransformation(JNIEnv *env, - jfloatArray matrixArr); - virtual TouchAffineTransformation getTouchAffineTransformation( - const std::string& inputDeviceDescriptor, int32_t surfaceRotation); + void getReaderConfiguration(InputReaderConfiguration* outConfig) override; + std::shared_ptr<PointerControllerInterface> obtainPointerController(int32_t deviceId) override; + void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) override; + std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay( + const InputDeviceIdentifier& identifier) override; + std::string getDeviceAlias(const InputDeviceIdentifier& identifier) override; + TouchAffineTransformation getTouchAffineTransformation(const std::string& inputDeviceDescriptor, + int32_t surfaceRotation) override; + + TouchAffineTransformation getTouchAffineTransformation(JNIEnv* env, jfloatArray matrixArr); /* --- InputDispatcherPolicyInterface implementation --- */ diff --git a/tests/Input/Android.bp b/tests/Input/Android.bp index a8aab2a899fb..a72b07c45dd8 100644 --- a/tests/Input/Android.bp +++ b/tests/Input/Android.bp @@ -6,6 +6,7 @@ android_test { static_libs: [ "androidx.test.ext.junit", "androidx.test.rules", + "truth-prebuilt", "ub-uiautomator", ], test_suites: ["device-tests"], diff --git a/tests/Input/src/com/android/test/input/ViewFrameInfoTest.kt b/tests/Input/src/com/android/test/input/ViewFrameInfoTest.kt new file mode 100644 index 000000000000..f919a3eaf271 --- /dev/null +++ b/tests/Input/src/com/android/test/input/ViewFrameInfoTest.kt @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2020 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 com.android.test.input + +import android.graphics.FrameInfo +import android.os.SystemClock +import android.view.ViewFrameInfo +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test + +class ViewFrameInfoTest { + companion object { + private const val TAG = "ViewFrameInfoTest" + } + private val mViewFrameInfo = ViewFrameInfo() + private var mTimeStarted: Long = 0 + + @Before + fun setUp() { + mViewFrameInfo.reset() + mViewFrameInfo.updateOldestInputEvent(10) + mViewFrameInfo.updateNewestInputEvent(20) + mViewFrameInfo.flags = mViewFrameInfo.flags or FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED + mTimeStarted = SystemClock.uptimeNanos() + mViewFrameInfo.markDrawStart() + } + + @Test + fun testPopulateFields() { + assertThat(mViewFrameInfo.drawStart).isGreaterThan(mTimeStarted) + assertThat(mViewFrameInfo.oldestInputEventTime).isEqualTo(10) + assertThat(mViewFrameInfo.newestInputEventTime).isEqualTo(20) + assertThat(mViewFrameInfo.flags).isEqualTo(FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED) + } + + @Test + fun testReset() { + mViewFrameInfo.reset() + // Ensure that the original object is reset correctly + assertThat(mViewFrameInfo.drawStart).isEqualTo(0) + assertThat(mViewFrameInfo.oldestInputEventTime).isEqualTo(0) + assertThat(mViewFrameInfo.newestInputEventTime).isEqualTo(0) + assertThat(mViewFrameInfo.flags).isEqualTo(0) + } + + @Test + fun testUpdateFrameInfoFromViewFrameInfo() { + val frameInfo = FrameInfo() + // By default, all values should be zero + assertThat(frameInfo.frameInfo[FrameInfo.OLDEST_INPUT_EVENT]).isEqualTo(0) + assertThat(frameInfo.frameInfo[FrameInfo.NEWEST_INPUT_EVENT]).isEqualTo(0) + assertThat(frameInfo.frameInfo[FrameInfo.FLAGS]).isEqualTo(0) + assertThat(frameInfo.frameInfo[FrameInfo.DRAW_START]).isEqualTo(0) + + // The values inside FrameInfo should match those from ViewFrameInfo after we update them + mViewFrameInfo.populateFrameInfo(frameInfo) + assertThat(frameInfo.frameInfo[FrameInfo.OLDEST_INPUT_EVENT]).isEqualTo(10) + assertThat(frameInfo.frameInfo[FrameInfo.NEWEST_INPUT_EVENT]).isEqualTo(20) + assertThat(frameInfo.frameInfo[FrameInfo.FLAGS]).isEqualTo( + FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED) + assertThat(frameInfo.frameInfo[FrameInfo.DRAW_START]).isGreaterThan(mTimeStarted) + } +}
\ No newline at end of file |