diff options
43 files changed, 571 insertions, 206 deletions
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index 25e6dc95c7..2d11b908c2 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -176,6 +176,7 @@ void add_mountinfo(); #define LINKERCONFIG_DIR "/linkerconfig" #define PACKAGE_DEX_USE_LIST "/data/system/package-dex-usage.list" #define SYSTEM_TRACE_SNAPSHOT "/data/misc/perfetto-traces/bugreport/systrace.pftrace" +#define CGROUPFS_DIR "/sys/fs/cgroup" // TODO(narayan): Since this information has to be kept in sync // with tombstoned, we should just put it in a common header. @@ -1240,8 +1241,15 @@ static Dumpstate::RunStatus RunDumpsysTextByPriority(const std::string& title, i if (status == OK) { dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority); std::chrono::duration<double> elapsed_seconds; - status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout, - /* as_proto = */ false, elapsed_seconds, bytes_written); + if (priority == IServiceManager::DUMP_FLAG_PRIORITY_HIGH && + service == String16("meminfo")) { + // Use a longer timeout for meminfo, since 30s is not always enough. + status = dumpsys.writeDump(STDOUT_FILENO, service, 60s, + /* as_proto = */ false, elapsed_seconds, bytes_written); + } else { + status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout, + /* as_proto = */ false, elapsed_seconds, bytes_written); + } dumpsys.writeDumpFooter(STDOUT_FILENO, service, elapsed_seconds); bool dump_complete = (status == OK); dumpsys.stopDumpThread(dump_complete); @@ -1785,6 +1793,9 @@ static Dumpstate::RunStatus dumpstate() { // Add linker configuration directory ds.AddDir(LINKERCONFIG_DIR, true); + /* Dump cgroupfs */ + ds.AddDir(CGROUPFS_DIR, true); + if (ds.dump_pool_) { WAIT_TASK_WITH_CONSENT_CHECK(DUMP_INCIDENT_REPORT_TASK, ds.dump_pool_); } else { diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp index af4a525290..871edfc081 100644 --- a/cmds/installd/dexopt.cpp +++ b/cmds/installd/dexopt.cpp @@ -1231,6 +1231,14 @@ class RunDexoptAnalyzer : public ExecVHelper { } } + // On-device signing related. odsign sets the system property odsign.verification.success if + // AOT artifacts have the expected signatures. + const bool trust_art_apex_data_files = + ::android::base::GetBoolProperty("odsign.verification.success", false); + if (!trust_art_apex_data_files) { + AddRuntimeArg("-Xdeny-art-apex-data-files"); + } + PrepareArgs(dexoptanalyzer_bin); } diff --git a/cmds/installd/run_dex2oat.cpp b/cmds/installd/run_dex2oat.cpp index e847626a14..b6616841f0 100644 --- a/cmds/installd/run_dex2oat.cpp +++ b/cmds/installd/run_dex2oat.cpp @@ -283,6 +283,13 @@ void RunDex2Oat::PrepareCompilerConfigFlags(const UniqueFile& input_vdex, } } + // On-device signing related. odsign sets the system property odsign.verification.success if + // AOT artifacts have the expected signatures. + const bool trust_art_apex_data_files = GetBoolProperty("odsign.verification.success", false); + if (!trust_art_apex_data_files) { + AddRuntimeArg("-Xdeny-art-apex-data-files"); + } + if (target_sdk_version != 0) { AddRuntimeArg(StringPrintf("-Xtarget-sdk-version:%d", target_sdk_version)); } diff --git a/include/input/Input.h b/include/input/Input.h index e8678d27c3..2e326cb102 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -43,6 +43,13 @@ * Additional private constants not defined in ndk/ui/input.h. */ enum { +#ifdef __linux__ + /* This event was generated or modified by accessibility service. */ + AKEY_EVENT_FLAG_IS_ACCESSIBILITY_EVENT = + android::os::IInputConstants::INPUT_EVENT_FLAG_IS_ACCESSIBILITY_EVENT, // 0x800, +#else + AKEY_EVENT_FLAG_IS_ACCESSIBILITY_EVENT = 0x800, +#endif /* Signifies that the key is being predispatched */ AKEY_EVENT_FLAG_PREDISPATCH = 0x20000000, @@ -81,6 +88,16 @@ enum { */ AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE = 0x40, +#ifdef __linux__ + /** + * This event was generated or modified by accessibility service. + */ + AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT = + android::os::IInputConstants::INPUT_EVENT_FLAG_IS_ACCESSIBILITY_EVENT, // 0x800, +#else + AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT = 0x800, +#endif + /* Motion event is inconsistent with previously sent motion events. */ AMOTION_EVENT_FLAG_TAINTED = 0x80000000, }; @@ -89,14 +106,15 @@ enum { * Allowed VerifiedKeyEvent flags. All other flags from KeyEvent do not get verified. * These values must be kept in sync with VerifiedKeyEvent.java */ -constexpr int32_t VERIFIED_KEY_EVENT_FLAGS = AKEY_EVENT_FLAG_CANCELED; +constexpr int32_t VERIFIED_KEY_EVENT_FLAGS = + AKEY_EVENT_FLAG_CANCELED | AKEY_EVENT_FLAG_IS_ACCESSIBILITY_EVENT; /** * Allowed VerifiedMotionEventFlags. All other flags from MotionEvent do not get verified. * These values must be kept in sync with VerifiedMotionEvent.java */ -constexpr int32_t VERIFIED_MOTION_EVENT_FLAGS = - AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; +constexpr int32_t VERIFIED_MOTION_EVENT_FLAGS = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | + AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED | AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT; /** * This flag indicates that the point up event has been canceled. @@ -222,16 +240,14 @@ enum { POLICY_FLAG_GESTURE = 0x00000008, POLICY_FLAG_RAW_MASK = 0x0000ffff, -#ifdef __linux__ - POLICY_FLAG_INPUTFILTER_TRUSTED = android::os::IInputConstants::POLICY_FLAG_INPUTFILTER_TRUSTED, +#ifdef __linux__ POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY = android::os::IInputConstants::POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY, #else - POLICY_FLAG_INPUTFILTER_TRUSTED = 0x10000, - POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY = 0x20000, #endif + /* These flags are set by the input dispatcher. */ // Indicates that the input event was injected. diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h index 1955104a22..7f0324a4a8 100644 --- a/include/input/InputDevice.h +++ b/include/input/InputDevice.h @@ -318,8 +318,6 @@ extern std::string getInputDeviceConfigurationFilePathByName( const std::string& name, InputDeviceConfigurationFileType type); enum ReservedInputDeviceId : int32_t { - // Device id assigned to input events generated inside accessibility service - ACCESSIBILITY_DEVICE_ID = -2, // Device id of a special "virtual" keyboard that is always present. VIRTUAL_KEYBOARD_ID = -1, // Device id of the "built-in" keyboard if there is one. diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING index b58d919d33..1010a2d79d 100644 --- a/libs/binder/TEST_MAPPING +++ b/libs/binder/TEST_MAPPING @@ -52,6 +52,9 @@ "name": "CtsOsTestCases", "options": [ { + "exclude-annotation": "android.platform.test.annotations.LargeTest" + }, + { "exclude-filter": "android.os.cts.BuildTest#testSdkInt" }, { diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index ac8feaa0c2..7d57d8b02c 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -171,6 +171,8 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceCont .apply(); mNumAcquired = 0; mNumFrameAvailable = 0; + BQA_LOGV("BLASTBufferQueue created width=%d height=%d format=%d mTransformHint=%d", width, + height, format, mTransformHint); } BLASTBufferQueue::~BLASTBufferQueue() { @@ -190,7 +192,6 @@ BLASTBufferQueue::~BLASTBufferQueue() { void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height, int32_t format) { std::unique_lock _lock{mMutex}; - BQA_LOGV("update width=%d height=%d format=%d", width, height, format); if (mFormat != format) { mFormat = format; mBufferItemConsumer->setDefaultBufferFormat(convertBufferFormat(format)); @@ -212,6 +213,8 @@ void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, mTransformHint = mSurfaceControl->getTransformHint(); mBufferItemConsumer->setTransformHint(mTransformHint); } + BQA_LOGV("update width=%d height=%d format=%d mTransformHint=%d", width, height, format, + mTransformHint); ui::Size newSize(width, height); if (mRequestedSize != newSize) { @@ -267,6 +270,7 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence mTransformHint = stat.transformHint; mBufferItemConsumer->setTransformHint(mTransformHint); + BQA_LOGV("updated mTransformHint=%d", mTransformHint); // Update frametime stamps if the frame was latched and presented, indicated by a // valid latch time. if (stat.latchTime > 0) { @@ -339,6 +343,7 @@ void BLASTBufferQueue::releaseBufferCallback(const ReleaseCallbackId& id, mTransformHint = transformHint; mSurfaceControl->setTransformHint(transformHint); mBufferItemConsumer->setTransformHint(mTransformHint); + BQA_LOGV("updated mTransformHint=%d", mTransformHint); } // Calculate how many buffers we need to hold before we release them back @@ -422,7 +427,7 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { } if (rejectBuffer(bufferItem)) { - BQA_LOGE("rejecting buffer:active_size=%dx%d, requested_size=%dx%d" + BQA_LOGE("rejecting buffer:active_size=%dx%d, requested_size=%dx%d " "buffer{size=%dx%d transform=%d}", mSize.width, mSize.height, mRequestedSize.width, mRequestedSize.height, buffer->getWidth(), buffer->getHeight(), bufferItem.mTransform); @@ -515,11 +520,11 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { BQA_LOGV("processNextBufferLocked size=%dx%d mFrameNumber=%" PRIu64 " applyTransaction=%s mTimestamp=%" PRId64 "%s mPendingTransactions.size=%d" - " graphicBufferId=%" PRIu64 "%s", + " graphicBufferId=%" PRIu64 "%s transform=%d", mSize.width, mSize.height, bufferItem.mFrameNumber, toString(applyTransaction), bufferItem.mTimestamp, bufferItem.mIsAutoTimestamp ? "(auto)" : "", static_cast<uint32_t>(mPendingTransactions.size()), bufferItem.mGraphicBuffer->getId(), - bufferItem.mAutoRefresh ? " mAutoRefresh" : ""); + bufferItem.mAutoRefresh ? " mAutoRefresh" : "", bufferItem.mTransform); } Rect BLASTBufferQueue::computeCrop(const BufferItem& item) { @@ -646,14 +651,6 @@ public: status_t setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo) override { return mBbq->setFrameTimelineInfo(frameTimelineInfo); } - protected: - uint32_t getTransformHint() const override { - if (mStickyTransform == 0 && !transformToDisplayInverse()) { - return mBbq->getLastTransformHint(); - } else { - return 0; - } - } }; // TODO: Can we coalesce this with frame updates? Need to confirm diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index e65c721ae1..2d99fc1903 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -562,6 +562,10 @@ bool layer_state_t::hasBufferChanges() const { return (what & layer_state_t::eBufferChanged) || (what & layer_state_t::eCachedBufferChanged); } +bool layer_state_t::hasValidBuffer() const { + return buffer || cachedBuffer.isValid(); +} + status_t layer_state_t::matrix22_t::write(Parcel& output) const { SAFE_PARCEL(output.writeFloat, dsdx); SAFE_PARCEL(output.writeFloat, dtdx); diff --git a/libs/gui/bufferqueue/1.0/Conversion.cpp b/libs/gui/bufferqueue/1.0/Conversion.cpp index 3e20a37d54..55462c3b1f 100644 --- a/libs/gui/bufferqueue/1.0/Conversion.cpp +++ b/libs/gui/bufferqueue/1.0/Conversion.cpp @@ -1187,14 +1187,15 @@ bool convertTo(::android::Region* l, Region const& t) { */ constexpr size_t minFlattenedSize( HGraphicBufferProducer::QueueBufferInput const& /* t */) { - return sizeof(int64_t) + // timestamp - sizeof(int) + // isAutoTimestamp + return sizeof(int64_t) + // timestamp + sizeof(int) + // isAutoTimestamp sizeof(android_dataspace) + // dataSpace - sizeof(::android::Rect) + // crop - sizeof(int) + // scalingMode - sizeof(uint32_t) + // transform - sizeof(uint32_t) + // stickyTransform - sizeof(bool); // getFrameTimestamps + sizeof(::android::Rect) + // crop + sizeof(int) + // scalingMode + sizeof(uint32_t) + // transform + sizeof(uint32_t) + // stickyTransform + sizeof(bool) + // getFrameTimestamps + sizeof(int); // slot } /** @@ -1267,6 +1268,7 @@ status_t flatten(HGraphicBufferProducer::QueueBufferInput const& t, return status; } FlattenableUtils::write(buffer, size, decltype(HdrMetadata::validTypes)(0)); + FlattenableUtils::write(buffer, size, -1 /*slot*/); return NO_ERROR; } @@ -1319,7 +1321,7 @@ status_t unflatten( if (status != NO_ERROR) { return status; } - // HdrMetadata ignored + // HdrMetadata and slot ignored return unflatten(&(t->surfaceDamage), buffer, size); } diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 8ac1e5d9e9..465e34ca33 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -126,6 +126,7 @@ struct layer_state_t { status_t write(Parcel& output) const; status_t read(const Parcel& input); bool hasBufferChanges() const; + bool hasValidBuffer() const; struct matrix22_t { float dsdx{0}; diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index 6ff67aa7cb..9082d275a2 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -71,6 +71,10 @@ public: return mBlastBufferQueueAdapter->mSurfaceControl; } + sp<Surface> getSurface() { + return mBlastBufferQueueAdapter->getSurface(false /* includeSurfaceControlHandle */); + } + void waitForCallbacks() { std::unique_lock lock{mBlastBufferQueueAdapter->mMutex}; // Wait until all but one of the submitted buffers have been released. @@ -758,6 +762,48 @@ TEST_F(BLASTBufferQueueTest, OutOfOrderTransactionTest) { {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight / 2})); } +TEST_F(BLASTBufferQueueTest, TransformHint) { + // Transform hint is provided to BBQ via the surface control passed by WM + mSurfaceControl->setTransformHint(ui::Transform::ROT_90); + + BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); + sp<IGraphicBufferProducer> igbProducer = adapter.getIGraphicBufferProducer(); + ASSERT_NE(nullptr, igbProducer.get()); + ASSERT_EQ(NO_ERROR, igbProducer->setMaxDequeuedBufferCount(2)); + sp<Surface> surface = adapter.getSurface(); + + // Before connecting to the surface, we do not get a valid transform hint + int transformHint; + surface->query(NATIVE_WINDOW_TRANSFORM_HINT, &transformHint); + ASSERT_EQ(ui::Transform::ROT_0, transformHint); + + ASSERT_EQ(NO_ERROR, + surface->connect(NATIVE_WINDOW_API_CPU, new TestProducerListener(igbProducer))); + + // After connecting to the surface, we should get the correct hint. + surface->query(NATIVE_WINDOW_TRANSFORM_HINT, &transformHint); + ASSERT_EQ(ui::Transform::ROT_90, transformHint); + + ANativeWindow_Buffer buffer; + surface->lock(&buffer, nullptr /* inOutDirtyBounds */); + + // Transform hint is updated via callbacks or surface control updates + mSurfaceControl->setTransformHint(ui::Transform::ROT_0); + adapter.update(mSurfaceControl, mDisplayWidth, mDisplayHeight); + + // The hint does not change and matches the value used when dequeueing the buffer. + surface->query(NATIVE_WINDOW_TRANSFORM_HINT, &transformHint); + ASSERT_EQ(ui::Transform::ROT_90, transformHint); + + surface->unlockAndPost(); + + // After queuing the buffer, we get the updated transform hint + surface->query(NATIVE_WINDOW_TRANSFORM_HINT, &transformHint); + ASSERT_EQ(ui::Transform::ROT_0, transformHint); + + adapter.waitForCallbacks(); +} + class BLASTBufferQueueTransformTest : public BLASTBufferQueueTest { public: void test(uint32_t tr) { diff --git a/libs/input/android/os/IInputConstants.aidl b/libs/input/android/os/IInputConstants.aidl index 3038d9daa5..474a1e410d 100644 --- a/libs/input/android/os/IInputConstants.aidl +++ b/libs/input/android/os/IInputConstants.aidl @@ -42,16 +42,15 @@ interface IInputConstants const int INVALID_INPUT_EVENT_ID = 0; /** - * The injected event was originally sent from InputDispatcher. Most likely, the journey of the - * event looked as follows: - * InputDispatcherPolicyInterface::filterInputEvent -> InputFilter.java::onInputEvent -> - * InputFilter.java::sendInputEvent -> InputDispatcher::injectInputEvent, without being modified - * along the way. + * The input event was injected from accessibility. Used in policyFlags for input event + * injection. */ - const int POLICY_FLAG_INPUTFILTER_TRUSTED = 0x10000; + const int POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY = 0x20000; /** - * The input event was injected from accessibility + * The input event was generated or modified by accessibility service. + * Shared by both KeyEvent and MotionEvent flags, so this value should not overlap with either + * set of flags, including in input/Input.h and in android/input.h. */ - const int POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY = 0x20000; + const int INPUT_EVENT_FLAG_IS_ACCESSIBILITY_EVENT = 0x800; } diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index b5dd8ac580..467f848237 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -1028,20 +1028,17 @@ bool GLESRenderEngine::supportsProtectedContent() const { return mProtectedEGLContext != EGL_NO_CONTEXT; } -bool GLESRenderEngine::useProtectedContext(bool useProtectedContext) { - if (useProtectedContext == mInProtectedContext) { - return true; - } - if (useProtectedContext && mProtectedEGLContext == EGL_NO_CONTEXT) { - return false; +void GLESRenderEngine::useProtectedContext(bool useProtectedContext) { + if (useProtectedContext == mInProtectedContext || + (useProtectedContext && !supportsProtectedContent())) { + return; } + const EGLSurface surface = useProtectedContext ? mProtectedStubSurface : mStubSurface; const EGLContext context = useProtectedContext ? mProtectedEGLContext : mEGLContext; - const bool success = eglMakeCurrent(mEGLDisplay, surface, surface, context) == EGL_TRUE; - if (success) { + if (eglMakeCurrent(mEGLDisplay, surface, surface, context) == EGL_TRUE) { mInProtectedContext = useProtectedContext; } - return success; } EGLImageKHR GLESRenderEngine::createFramebufferImageIfNeeded(ANativeWindowBuffer* nativeBuffer, bool isProtected, diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h index 915dba364f..4cb1b4259b 100644 --- a/libs/renderengine/gl/GLESRenderEngine.h +++ b/libs/renderengine/gl/GLESRenderEngine.h @@ -62,7 +62,7 @@ public: void deleteTextures(size_t count, uint32_t const* names) override; bool isProtected() const override { return mInProtectedContext; } bool supportsProtectedContent() const override; - bool useProtectedContext(bool useProtectedContext) override; + void useProtectedContext(bool useProtectedContext) override; status_t drawLayers(const DisplaySettings& display, const std::vector<const LayerSettings*>& layers, const std::shared_ptr<ExternalTexture>& buffer, diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index ac0affb2ee..5964bc3927 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -127,7 +127,7 @@ public: virtual bool supportsProtectedContent() const = 0; // Attempt to switch RenderEngine into and out of protectedContext mode - virtual bool useProtectedContext(bool useProtectedContext) = 0; + virtual void useProtectedContext(bool useProtectedContext) = 0; // Notify RenderEngine of changes to the dimensions of the primary display // so that it can configure its internal caches accordingly. diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h index 0175af3a85..a4aa9ea488 100644 --- a/libs/renderengine/include/renderengine/mock/RenderEngine.h +++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h @@ -44,7 +44,7 @@ public: MOCK_CONST_METHOD0(getMaxViewportDims, size_t()); MOCK_CONST_METHOD0(isProtected, bool()); MOCK_CONST_METHOD0(supportsProtectedContent, bool()); - MOCK_METHOD1(useProtectedContext, bool(bool)); + MOCK_METHOD1(useProtectedContext, void(bool)); MOCK_METHOD0(cleanupPostRender, void()); MOCK_CONST_METHOD0(canSkipPostRenderCleanup, bool()); MOCK_METHOD6(drawLayers, diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp index 34577daf2c..ae8f2384c4 100644 --- a/libs/renderengine/skia/Cache.cpp +++ b/libs/renderengine/skia/Cache.cpp @@ -41,6 +41,10 @@ const auto kScaleAsymmetric = mat4(0.8f, 0.f, 0.f, 0.f, 0.f, 1.1f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f); +const auto kFlip = mat4(1.1f, -0.1f, 0.f, 0.f, + 0.1f, 1.1f, 0.f, 0.f, + 0.f, 0.f, 1.f, 0.f, + 2.f, 2.f, 0.f, 1.f); // clang-format on // When setting layer.sourceDataspace, whether it matches the destination or not determines whether // a color correction effect is added to the shader. @@ -52,42 +56,64 @@ static void drawShadowLayers(SkiaRenderEngine* renderengine, const DisplaySettin const std::shared_ptr<ExternalTexture>& dstTexture) { // Somewhat arbitrary dimensions, but on screen and slightly shorter, based // on actual use. - FloatRect rect(0, 0, display.physicalDisplay.width(), display.physicalDisplay.height() - 30); + const Rect& displayRect = display.physicalDisplay; + FloatRect rect(0, 0, displayRect.width(), displayRect.height()); + FloatRect smallerRect(20, 20, displayRect.width()-20, displayRect.height()-20); + LayerSettings layer{ .geometry = Geometry{ .boundaries = rect, .roundedCornersCrop = rect, + .roundedCornersRadius = 50.f, }, // drawShadow ignores alpha .shadow = ShadowSettings{ + .boundaries = rect, .ambientColor = vec4(0, 0, 0, 0.00935997f), .spotColor = vec4(0, 0, 0, 0.0455841f), - .lightPos = vec3(370.508f, -1527.03f, 1650.f), - .lightRadius = 2200.0f, - .length = 0.955342f, + .lightPos = vec3(500.f, -1500.f, 1500.f), + .lightRadius = 2500.0f, + .length = 15.f, }, - // important that this matches dest so the general shadow fragment shader doesn't - // have color correction added, and important that it be srgb, so the *vertex* shader - // doesn't have color correction added. - .sourceDataspace = kDestDataSpace, // setting this is mandatory for shadows and blurs .skipContentDraw = true, + .alpha = 1, + }; + LayerSettings caster{ + .geometry = + Geometry{ + .boundaries = smallerRect, + .roundedCornersCrop = rect, + .roundedCornersRadius = 50.f, + }, + .source = + PixelSource{ + .solidColor = half3(0.f, 0.f, 0.f), + }, + .alpha = 1, }; - auto layers = std::vector<const LayerSettings*>{&layer}; - // The identity matrix will generate the fast shader - renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd(), - nullptr); - // This matrix, which has different scales for x and y, will - // generate the slower (more general case) version, which has variants for translucent - // casters and rounded rects. - layer.geometry.positionTransform = kScaleAsymmetric; - for (auto translucent : {false, true}) { - layer.shadow.casterIsTranslucent = translucent; - renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, - base::unique_fd(), nullptr); + auto layers = std::vector<const LayerSettings*>{&layer, &caster}; + // When sourceDataspace matches dest, the general shadow fragment shader doesn't + // have color correction added. + // independently, when it is not srgb, the *vertex* shader has color correction added. + // This may be a bug, but the shader still needs to be cached as it is triggered + // during youtube pip. + for (auto dataspace : {kDestDataSpace, kOtherDataSpace}) { + layer.sourceDataspace = dataspace; + // The 2nd matrix, which has different scales for x and y, will + // generate the slower (more general case) shadow shader + for (auto transform : {mat4(), kScaleAndTranslate, kFlip}) { + layer.geometry.positionTransform = transform; + caster.geometry.positionTransform = transform; + for (bool translucent : {false, true}){ + layer.shadow.casterIsTranslucent = translucent; + renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, + base::unique_fd(), nullptr); + } + } } } @@ -115,6 +141,8 @@ static void drawImageLayers(SkiaRenderEngine* renderengine, const DisplaySetting auto layers = std::vector<const LayerSettings*>{&layer}; for (auto dataspace : {kDestDataSpace, kOtherDataSpace}) { layer.sourceDataspace = dataspace; + // Cache shaders for both rects and round rects. + // In reduced shader mode, all non-zero round rect radii get the same code path. for (float roundedCornersRadius : {0.0f, 50.0f}) { // roundedCornersCrop is always set, but the radius triggers the behavior layer.geometry.roundedCornersRadius = roundedCornersRadius; @@ -217,11 +245,9 @@ static void drawClippedLayers(SkiaRenderEngine* renderengine, const DisplaySetti layer.source = pixelSource; for (auto dataspace : {kDestDataSpace, kOtherDataSpace}) { layer.sourceDataspace = dataspace; - // Produce a CircularRRect clip and an EllipticalRRect clip + // Produce a CircularRRect clip and an EllipticalRRect clip. for (auto transform : {kScaleAndTranslate, kScaleAsymmetric}) { layer.geometry.positionTransform = transform; - // In real use, I saw alpha of 1.0 and 0.999, probably a mistake, but cache both - // shaders. for (float alpha : {0.5f, 1.f}) { layer.alpha = alpha, renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, @@ -232,6 +258,69 @@ static void drawClippedLayers(SkiaRenderEngine* renderengine, const DisplaySetti } } +static void drawPIPImageLayer(SkiaRenderEngine* renderengine, const DisplaySettings& display, + const std::shared_ptr<ExternalTexture>& dstTexture, + const std::shared_ptr<ExternalTexture>& srcTexture) { + const Rect& displayRect = display.physicalDisplay; + FloatRect rect(0, 0, displayRect.width(), displayRect.height()); + LayerSettings layer{ + .geometry = + Geometry{ + // Note that this flip matrix only makes a difference when clipping, + // which happens in this layer because the roundrect crop is just a bit + // larger than the layer bounds. + .positionTransform = kFlip, + .boundaries = rect, + .roundedCornersRadius = 94.2551, + .roundedCornersCrop = FloatRect( + -93.75, 0, displayRect.width() + 93.75, displayRect.height()), + }, + .source = PixelSource{.buffer = + Buffer{ + .buffer = srcTexture, + .maxLuminanceNits = 1000.f, + .isOpaque = 0, + .usePremultipliedAlpha = 1, + }}, + .sourceDataspace = kOtherDataSpace, + .alpha = 1, + + }; + + auto layers = std::vector<const LayerSettings*>{&layer}; + renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, + base::unique_fd(), nullptr); +} + +static void drawHolePunchLayer(SkiaRenderEngine* renderengine, const DisplaySettings& display, + const std::shared_ptr<ExternalTexture>& dstTexture) { + const Rect& displayRect = display.physicalDisplay; + FloatRect rect(0, 0, displayRect.width(), displayRect.height()); + FloatRect small(0, 0, displayRect.width()-20, displayRect.height()+20); + LayerSettings layer{ + .geometry = + Geometry{ + .positionTransform = kScaleAndTranslate, + // the boundaries have to be smaller than the rounded crop so that + // clipRRect is used instead of drawRRect + .boundaries = small, + .roundedCornersRadius = 50.f, + .roundedCornersCrop = rect, + }, + .source = PixelSource{ + .solidColor = half3(0.f, 0.f, 0.f), + }, + .sourceDataspace = kDestDataSpace, + .alpha = 0, + .disableBlending = true, + + }; + + auto layers = std::vector<const LayerSettings*>{&layer}; + renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, + base::unique_fd(), nullptr); +} + // // The collection of shaders cached here were found by using perfetto to record shader compiles // during actions that involve RenderEngine, logging the layer settings, and the shader code @@ -243,8 +332,6 @@ static void drawClippedLayers(SkiaRenderEngine* renderengine, const DisplaySetti // kFlushAfterEveryLayer = true // in external/skia/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp // gPrintSKSL = true -// -// TODO(b/184631553) cache the shader involved in youtube pip return. void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { const int previousCount = renderengine->reportShadersCompiled(); if (previousCount) { @@ -264,6 +351,12 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { .maxLuminance = 500, .outputDataspace = kDestDataSpace, }; + DisplaySettings p3Display{ + .physicalDisplay = displayRect, + .clip = displayRect, + .maxLuminance = 500, + .outputDataspace = kOtherDataSpace, + }; const int64_t usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; @@ -286,9 +379,10 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { std::make_shared<ExternalTexture>(srcBuffer, *renderengine, ExternalTexture::Usage::READABLE | ExternalTexture::Usage::WRITEABLE); - + drawHolePunchLayer(renderengine, display, dstTexture); drawSolidLayers(renderengine, display, dstTexture); drawShadowLayers(renderengine, display, srcTexture); + drawShadowLayers(renderengine, p3Display, srcTexture); if (renderengine->supportsBackgroundBlur()) { drawBlurLayers(renderengine, display, dstTexture); @@ -313,12 +407,20 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { // The majority of shaders are related to sampling images. // These need to be generated with various source textures - for (auto texture : {srcTexture, externalTexture, f16ExternalTexture}) { + // The F16 texture may not be usable on all devices, so check first that it was created with + // the requested usage bit. + auto textures = {srcTexture, externalTexture}; + auto texturesWithF16 = {srcTexture, externalTexture, f16ExternalTexture}; + bool canUsef16 = f16ExternalBuffer->getUsage() & GRALLOC_USAGE_HW_TEXTURE; + + for (auto texture : canUsef16 ? texturesWithF16 : textures) { drawImageLayers(renderengine, display, dstTexture, texture); // Draw layers for b/185569240. drawClippedLayers(renderengine, display, dstTexture, texture); } + drawPIPImageLayer(renderengine, display, dstTexture, externalTexture); + const nsecs_t timeAfter = systemTime(); const float compileTimeMs = static_cast<float>(timeAfter - timeBefore) / 1.0E6; const int shadersCompiled = renderengine->reportShadersCompiled(); diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp index c7356ea728..3c59f11395 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -320,7 +320,8 @@ SkiaGLRenderEngine::SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGL options.fReducedShaderVariations = true; options.fPersistentCache = &mSkSLCacheMonitor; mGrContext = GrDirectContext::MakeGL(glInterface, options); - if (useProtectedContext(true)) { + if (supportsProtectedContent()) { + useProtectedContext(true); mProtectedGrContext = GrDirectContext::MakeGL(glInterface, options); useProtectedContext(false); } @@ -373,12 +374,10 @@ GrDirectContext* SkiaGLRenderEngine::getActiveGrContext() const { return mInProtectedContext ? mProtectedGrContext.get() : mGrContext.get(); } -bool SkiaGLRenderEngine::useProtectedContext(bool useProtectedContext) { - if (useProtectedContext == mInProtectedContext) { - return true; - } - if (useProtectedContext && !supportsProtectedContent()) { - return false; +void SkiaGLRenderEngine::useProtectedContext(bool useProtectedContext) { + if (useProtectedContext == mInProtectedContext || + (useProtectedContext && !supportsProtectedContent())) { + return; } // release any scratch resources before switching into a new mode @@ -389,9 +388,8 @@ bool SkiaGLRenderEngine::useProtectedContext(bool useProtectedContext) { const EGLSurface surface = useProtectedContext ? mProtectedPlaceholderSurface : mPlaceholderSurface; const EGLContext context = useProtectedContext ? mProtectedEGLContext : mEGLContext; - const bool success = eglMakeCurrent(mEGLDisplay, surface, surface, context) == EGL_TRUE; - if (success) { + if (eglMakeCurrent(mEGLDisplay, surface, surface, context) == EGL_TRUE) { mInProtectedContext = useProtectedContext; // given that we are sharing the same thread between two GrContexts we need to // make sure that the thread state is reset when switching between the two. @@ -399,7 +397,6 @@ bool SkiaGLRenderEngine::useProtectedContext(bool useProtectedContext) { getActiveGrContext()->resetContext(); } } - return success; } base::unique_fd SkiaGLRenderEngine::flush() { @@ -1413,10 +1410,12 @@ void SkiaGLRenderEngine::onPrimaryDisplaySizeChanged(ui::Size size) { getActiveGrContext()->setResourceCacheLimit(maxResourceBytes); // if it is possible to switch contexts then we will resize the other context - if (useProtectedContext(!mInProtectedContext)) { + const bool originalProtectedState = mInProtectedContext; + useProtectedContext(!mInProtectedContext); + if (mInProtectedContext != originalProtectedState) { getActiveGrContext()->setResourceCacheLimit(maxResourceBytes); // reset back to the initial context that was active when this method was called - useProtectedContext(!mInProtectedContext); + useProtectedContext(originalProtectedState); } } diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h index b30355bb67..a852bbcaf8 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.h +++ b/libs/renderengine/skia/SkiaGLRenderEngine.h @@ -64,7 +64,7 @@ public: int getContextPriority() override; bool isProtected() const override { return mInProtectedContext; } bool supportsProtectedContent() const override; - bool useProtectedContext(bool useProtectedContext) override; + void useProtectedContext(bool useProtectedContext) override; bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; } void assertShadersCompiled(int numShaders) override; void onPrimaryDisplaySizeChanged(ui::Size size) override; diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h index 31ad63e9ce..7cd9eca976 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.h +++ b/libs/renderengine/skia/SkiaRenderEngine.h @@ -44,7 +44,6 @@ public: virtual void deleteTextures(size_t /*count*/, uint32_t const* /*names*/) override{}; virtual bool isProtected() const override { return false; } // mInProtectedContext; } virtual bool supportsProtectedContent() const override { return false; }; - virtual bool useProtectedContext(bool /*useProtectedContext*/) override { return false; }; virtual status_t drawLayers(const DisplaySettings& /*display*/, const std::vector<const LayerSettings*>& /*layers*/, const std::shared_ptr<ExternalTexture>& /*buffer*/, diff --git a/libs/renderengine/skia/filters/LinearEffect.cpp b/libs/renderengine/skia/filters/LinearEffect.cpp index 9b044e1685..fc45af945b 100644 --- a/libs/renderengine/skia/filters/LinearEffect.cpp +++ b/libs/renderengine/skia/filters/LinearEffect.cpp @@ -167,13 +167,12 @@ static void generateToneMapInterpolation(ui::Dataspace inputDataspace, float nits = xyz.y; - // clamp to max input luminance - nits = clamp(nits, 0.0, maxInLumi); - - // scale [0.0, maxInLumi] to [0.0, maxOutLumi] + // if the max input luminance is less than what we can output then + // no tone mapping is needed as all color values will be in range. if (maxInLumi <= maxOutLumi) { - return xyz * (maxOutLumi / maxInLumi); + return xyz; } else { + // three control points const float x0 = 10.0; const float y0 = 17.0; diff --git a/libs/renderengine/tests/RenderEngineThreadedTest.cpp b/libs/renderengine/tests/RenderEngineThreadedTest.cpp index c65e731230..830f4630e5 100644 --- a/libs/renderengine/tests/RenderEngineThreadedTest.cpp +++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp @@ -118,16 +118,26 @@ TEST_F(RenderEngineThreadedTest, supportsProtectedContent_returnsTrue) { ASSERT_EQ(true, result); } -TEST_F(RenderEngineThreadedTest, useProtectedContext_returnsFalse) { - EXPECT_CALL(*mRenderEngine, useProtectedContext(false)).WillOnce(Return(false)); - status_t result = mThreadedRE->useProtectedContext(false); - ASSERT_EQ(false, result); +TEST_F(RenderEngineThreadedTest, useProtectedContext) { + EXPECT_CALL(*mRenderEngine, useProtectedContext(true)); + auto& ipExpect = EXPECT_CALL(*mRenderEngine, isProtected()).WillOnce(Return(false)); + EXPECT_CALL(*mRenderEngine, supportsProtectedContent()).WillOnce(Return(true)); + EXPECT_CALL(*mRenderEngine, isProtected()).After(ipExpect).WillOnce(Return(true)); + + mThreadedRE->useProtectedContext(true); + ASSERT_EQ(true, mThreadedRE->isProtected()); + + // call ANY synchronous function to ensure that useProtectedContext has completed. + mThreadedRE->getContextPriority(); + ASSERT_EQ(true, mThreadedRE->isProtected()); } -TEST_F(RenderEngineThreadedTest, useProtectedContext_returnsTrue) { - EXPECT_CALL(*mRenderEngine, useProtectedContext(false)).WillOnce(Return(true)); - status_t result = mThreadedRE->useProtectedContext(false); - ASSERT_EQ(true, result); +TEST_F(RenderEngineThreadedTest, useProtectedContext_quickReject) { + EXPECT_CALL(*mRenderEngine, useProtectedContext(false)).Times(0); + EXPECT_CALL(*mRenderEngine, isProtected()).WillOnce(Return(false)); + mThreadedRE->useProtectedContext(false); + // call ANY synchronous function to ensure that useProtectedContext has completed. + mThreadedRE->getContextPriority(); } TEST_F(RenderEngineThreadedTest, PostRenderCleanup_skipped) { diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp index ea3871f235..b9dabc1d05 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.cpp +++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp @@ -90,6 +90,7 @@ void RenderEngineThreaded::threadMain(CreateInstanceFactory factory) NO_THREAD_S } mRenderEngine = factory(); + mIsProtected = mRenderEngine->isProtected(); pthread_setname_np(pthread_self(), mThreadName); @@ -248,10 +249,8 @@ size_t RenderEngineThreaded::getMaxViewportDims() const { bool RenderEngineThreaded::isProtected() const { waitUntilInitialized(); - // ensure that useProtectedContext is not currently being changed by some - // other thread. std::lock_guard lock(mThreadMutex); - return mRenderEngine->isProtected(); + return mIsProtected; } bool RenderEngineThreaded::supportsProtectedContent() const { @@ -259,20 +258,28 @@ bool RenderEngineThreaded::supportsProtectedContent() const { return mRenderEngine->supportsProtectedContent(); } -bool RenderEngineThreaded::useProtectedContext(bool useProtectedContext) { - std::promise<bool> resultPromise; - std::future<bool> resultFuture = resultPromise.get_future(); +void RenderEngineThreaded::useProtectedContext(bool useProtectedContext) { + if (isProtected() == useProtectedContext || + (useProtectedContext && !supportsProtectedContent())) { + return; + } + { std::lock_guard lock(mThreadMutex); - mFunctionCalls.push( - [&resultPromise, useProtectedContext](renderengine::RenderEngine& instance) { - ATRACE_NAME("REThreaded::useProtectedContext"); - bool returnValue = instance.useProtectedContext(useProtectedContext); - resultPromise.set_value(returnValue); - }); + mFunctionCalls.push([useProtectedContext, this](renderengine::RenderEngine& instance) { + ATRACE_NAME("REThreaded::useProtectedContext"); + instance.useProtectedContext(useProtectedContext); + if (instance.isProtected() != useProtectedContext) { + ALOGE("Failed to switch RenderEngine context."); + // reset the cached mIsProtected value to a good state, but this does not + // prevent other callers of this method and isProtected from reading the + // invalid cached value. + mIsProtected = instance.isProtected(); + } + }); + mIsProtected = useProtectedContext; } mCondition.notify_one(); - return resultFuture.get(); } void RenderEngineThreaded::cleanupPostRender() { diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h index 9b523b2140..f2f5c0f7cd 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.h +++ b/libs/renderengine/threaded/RenderEngineThreaded.h @@ -53,7 +53,7 @@ public: bool isProtected() const override; bool supportsProtectedContent() const override; - bool useProtectedContext(bool useProtectedContext) override; + void useProtectedContext(bool useProtectedContext) override; void cleanupPostRender() override; status_t drawLayers(const DisplaySettings& display, @@ -100,6 +100,7 @@ private: * Render Engine */ std::unique_ptr<renderengine::RenderEngine> mRenderEngine; + std::atomic<bool> mIsProtected = false; }; } // namespace threaded } // namespace renderengine diff --git a/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl b/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl index f91f5b9017..9564cba60d 100644 --- a/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl +++ b/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl @@ -36,7 +36,7 @@ interface ISensorPrivacyManager { void setSensorPrivacy(boolean enable); - void setIndividualSensorPrivacy(int userId, int sensor, boolean enable); + void setIndividualSensorPrivacy(int userId, int source, int sensor, boolean enable); - void setIndividualSensorPrivacyForProfileGroup(int userId, int sensor, boolean enable); + void setIndividualSensorPrivacyForProfileGroup(int userId, int source, int sensor, boolean enable); } diff --git a/libs/ui/include/ui/Transform.h b/libs/ui/include/ui/Transform.h index a197b3b20e..33fbe05035 100644 --- a/libs/ui/include/ui/Transform.h +++ b/libs/ui/include/ui/Transform.h @@ -112,6 +112,7 @@ public: void dump(const char* name, const char* prefix = "") const; static constexpr RotationFlags toRotationFlags(Rotation); + static constexpr Rotation toRotation(RotationFlags); private: struct mat33 { @@ -151,5 +152,20 @@ inline constexpr Transform::RotationFlags Transform::toRotationFlags(Rotation ro } } +inline constexpr Rotation Transform::toRotation(Transform::RotationFlags rotationFlags) { + switch (rotationFlags) { + case ROT_0: + return ROTATION_0; + case ROT_90: + return ROTATION_90; + case ROT_180: + return ROTATION_180; + case ROT_270: + return ROTATION_270; + default: + return ROTATION_0; + } +} + } // namespace ui } // namespace android diff --git a/services/gpuservice/bpfprogs/gpu_mem.c b/services/gpuservice/bpfprogs/gpu_mem.c index c75213bbd4..16e1e8a1ef 100644 --- a/services/gpuservice/bpfprogs/gpu_mem.c +++ b/services/gpuservice/bpfprogs/gpu_mem.c @@ -72,4 +72,4 @@ DEFINE_BPF_PROG("tracepoint/gpu_mem/gpu_mem_total", AID_ROOT, AID_GRAPHICS, tp_g return 0; } -char _license[] SEC("license") = "Apache 2.0"; +LICENSE("Apache 2.0"); diff --git a/services/inputflinger/TEST_MAPPING b/services/inputflinger/TEST_MAPPING index dc0e60c858..3d85befaf8 100644 --- a/services/inputflinger/TEST_MAPPING +++ b/services/inputflinger/TEST_MAPPING @@ -27,7 +27,17 @@ "name": "CtsViewTestCases", "options": [ { - "include-filter": "android.view.cts.MotionEventTest" + "include-filter": "android.view.cts.MotionEventTest", + "include-filter": "android.view.cts.VerifyInputEventTest" + } + ] + }, + { + "name": "FrameworksCoreTests", + "options": [ + { + "include-filter": "android.view.VerifiedKeyEventTest", + "include-filter": "android.view.VerifiedMotionEventTest" } ] }, diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index c0010abf8a..1899c5f29d 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -3787,7 +3787,7 @@ void InputDispatcher::notifyKey(const NotifyKeyArgs* args) { if (shouldSendKeyToInputFilterLocked(args)) { mLock.unlock(); - policyFlags |= POLICY_FLAG_FILTERED | POLICY_FLAG_INPUTFILTER_TRUSTED; + policyFlags |= POLICY_FLAG_FILTERED; if (!mPolicy->filterInputEvent(&event, policyFlags)) { return; // event was consumed by the filter } @@ -4010,16 +4010,14 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( } // For all injected events, set device id = VIRTUAL_KEYBOARD_ID. The only exception is events - // that have gone through the InputFilter. If the event passed through the InputFilter, - // but did not get modified, assign the provided device id. If the InputFilter modifies the - // events in any way, it is responsible for removing this flag. - // If the injected event originated from accessibility, assign the accessibility device id, - // so that it can be distinguished from regular injected events. + // that have gone through the InputFilter. If the event passed through the InputFilter, assign + // the provided device id. If the InputFilter is accessibility, and it modifies or synthesizes + // the injected event, it is responsible for setting POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY. + // For those events, we will set FLAG_IS_ACCESSIBILITY_EVENT to allow apps to distinguish them + // from events that originate from actual hardware. int32_t resolvedDeviceId = VIRTUAL_KEYBOARD_ID; - if (policyFlags & POLICY_FLAG_INPUTFILTER_TRUSTED) { + if (policyFlags & POLICY_FLAG_FILTERED) { resolvedDeviceId = event->getDeviceId(); - } else if (policyFlags & POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY) { - resolvedDeviceId = ACCESSIBILITY_DEVICE_ID; } std::queue<std::unique_ptr<EventEntry>> injectedEntries; @@ -4032,6 +4030,9 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( } int32_t flags = incomingKey.getFlags(); + if (policyFlags & POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY) { + flags |= AKEY_EVENT_FLAG_IS_ACCESSIBILITY_EVENT; + } int32_t keyCode = incomingKey.getKeyCode(); int32_t metaState = incomingKey.getMetaState(); accelerateMetaShortcuts(resolvedDeviceId, action, @@ -4073,6 +4074,7 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( size_t pointerCount = motionEvent.getPointerCount(); const PointerProperties* pointerProperties = motionEvent.getPointerProperties(); int32_t actionButton = motionEvent.getActionButton(); + int32_t flags = motionEvent.getFlags(); int32_t displayId = motionEvent.getDisplayId(); if (!validateMotionEvent(action, actionButton, pointerCount, pointerProperties)) { return InputEventInjectionResult::FAILED; @@ -4088,6 +4090,10 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( } } + if (policyFlags & POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY) { + flags |= AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT; + } + mLock.lock(); const nsecs_t* sampleEventTimes = motionEvent.getSampleEventTimes(); const PointerCoords* samplePointerCoords = motionEvent.getSamplePointerCoords(); @@ -4095,8 +4101,7 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( std::make_unique<MotionEntry>(motionEvent.getId(), *sampleEventTimes, resolvedDeviceId, motionEvent.getSource(), motionEvent.getDisplayId(), policyFlags, action, - actionButton, motionEvent.getFlags(), - motionEvent.getMetaState(), + actionButton, flags, motionEvent.getMetaState(), motionEvent.getButtonState(), motionEvent.getClassification(), motionEvent.getEdgeFlags(), @@ -4116,7 +4121,7 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( std::make_unique<MotionEntry>(motionEvent.getId(), *sampleEventTimes, resolvedDeviceId, motionEvent.getSource(), motionEvent.getDisplayId(), policyFlags, - action, actionButton, motionEvent.getFlags(), + action, actionButton, flags, motionEvent.getMetaState(), motionEvent.getButtonState(), motionEvent.getClassification(), diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp index ca43123d28..fab7f4ca14 100644 --- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp @@ -104,36 +104,37 @@ void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) { #endif } else { Slot* slot = &mSlots[mCurrentSlot]; + // If mUsingSlotsProtocol is true, it means the raw pointer has axis info of + // ABS_MT_TRACKING_ID and ABS_MT_SLOT, so driver should send a valid trackingId while + // updating the slot. + if (!mUsingSlotsProtocol) { + slot->mInUse = true; + } switch (rawEvent->code) { case ABS_MT_POSITION_X: - slot->mInUse = true; slot->mAbsMTPositionX = rawEvent->value; + warnIfNotInUse(*rawEvent, *slot); break; case ABS_MT_POSITION_Y: - slot->mInUse = true; slot->mAbsMTPositionY = rawEvent->value; + warnIfNotInUse(*rawEvent, *slot); break; case ABS_MT_TOUCH_MAJOR: - slot->mInUse = true; slot->mAbsMTTouchMajor = rawEvent->value; break; case ABS_MT_TOUCH_MINOR: - slot->mInUse = true; slot->mAbsMTTouchMinor = rawEvent->value; slot->mHaveAbsMTTouchMinor = true; break; case ABS_MT_WIDTH_MAJOR: - slot->mInUse = true; slot->mAbsMTWidthMajor = rawEvent->value; break; case ABS_MT_WIDTH_MINOR: - slot->mInUse = true; slot->mAbsMTWidthMinor = rawEvent->value; slot->mHaveAbsMTWidthMinor = true; break; case ABS_MT_ORIENTATION: - slot->mInUse = true; slot->mAbsMTOrientation = rawEvent->value; break; case ABS_MT_TRACKING_ID: @@ -147,15 +148,12 @@ void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) { } break; case ABS_MT_PRESSURE: - slot->mInUse = true; slot->mAbsMTPressure = rawEvent->value; break; case ABS_MT_DISTANCE: - slot->mInUse = true; slot->mAbsMTDistance = rawEvent->value; break; case ABS_MT_TOOL_TYPE: - slot->mInUse = true; slot->mAbsMTToolType = rawEvent->value; slot->mHaveAbsMTToolType = true; break; @@ -177,6 +175,13 @@ bool MultiTouchMotionAccumulator::hasStylus() const { return mHaveStylus; } +void MultiTouchMotionAccumulator::warnIfNotInUse(const RawEvent& event, const Slot& slot) { + if (!slot.mInUse) { + ALOGW("Received unexpected event (0x%0x, 0x%0x) for slot %i with tracking id %i", + event.code, event.value, mCurrentSlot, slot.mAbsMTTrackingId); + } +} + // --- MultiTouchMotionAccumulator::Slot --- MultiTouchMotionAccumulator::Slot::Slot() { diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h index ea6f2078d7..225ad49363 100644 --- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h +++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h @@ -87,6 +87,7 @@ private: bool mHaveStylus; void clearSlots(int32_t initialSlot); + void warnIfNotInUse(const RawEvent& event, const Slot& slot); }; class MultiTouchInputMapper : public TouchInputMapper { diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index 60502384a3..962d8d2935 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -1471,6 +1471,13 @@ void TouchInputMapper::sync(nsecs_t when, nsecs_t readTime) { next.rawPointerData.canceledIdBits.value); #endif + if (!next.rawPointerData.touchingIdBits.isEmpty() && + !next.rawPointerData.hoveringIdBits.isEmpty() && + last.rawPointerData.hoveringIdBits != next.rawPointerData.hoveringIdBits) { + ALOGI("Multi-touch contains some hovering ids 0x%08x", + next.rawPointerData.hoveringIdBits.value); + } + processRawTouches(false /*timeout*/); } diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 77ca12c5dc..3a9dede89b 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -3171,7 +3171,8 @@ protected: mWindow->consumeFocusEvent(true); } - void testInjectedKey(int32_t policyFlags, int32_t injectedDeviceId, int32_t resolvedDeviceId) { + void testInjectedKey(int32_t policyFlags, int32_t injectedDeviceId, int32_t resolvedDeviceId, + int32_t flags) { KeyEvent event; const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC); @@ -3188,6 +3189,45 @@ protected: InputEvent* received = mWindow->consume(); ASSERT_NE(nullptr, received); ASSERT_EQ(resolvedDeviceId, received->getDeviceId()); + ASSERT_EQ(received->getType(), AINPUT_EVENT_TYPE_KEY); + KeyEvent& keyEvent = static_cast<KeyEvent&>(*received); + ASSERT_EQ(flags, keyEvent.getFlags()); + } + + void testInjectedMotion(int32_t policyFlags, int32_t injectedDeviceId, int32_t resolvedDeviceId, + int32_t flags) { + MotionEvent event; + PointerProperties pointerProperties[1]; + PointerCoords pointerCoords[1]; + pointerProperties[0].clear(); + pointerProperties[0].id = 0; + pointerCoords[0].clear(); + pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 300); + pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 400); + + ui::Transform identityTransform; + const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC); + event.initialize(InputEvent::nextId(), injectedDeviceId, AINPUT_SOURCE_TOUCHSCREEN, + DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, + AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, MotionClassification::NONE, + identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, + 0 /*AMOTION_EVENT_INVALID_DISPLAY_SIZE*/, + 0 /*AMOTION_EVENT_INVALID_DISPLAY_SIZE*/, eventTime, eventTime, + /*pointerCount*/ 1, pointerProperties, pointerCoords); + + const int32_t additionalPolicyFlags = POLICY_FLAG_PASS_TO_USER; + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, + InputEventInjectionSync::WAIT_FOR_RESULT, 10ms, + policyFlags | additionalPolicyFlags)); + + InputEvent* received = mWindow->consume(); + ASSERT_NE(nullptr, received); + ASSERT_EQ(resolvedDeviceId, received->getDeviceId()); + ASSERT_EQ(received->getType(), AINPUT_EVENT_TYPE_MOTION); + MotionEvent& motionEvent = static_cast<MotionEvent&>(*received); + ASSERT_EQ(flags, motionEvent.getFlags()); } private: @@ -3195,20 +3235,29 @@ private: }; TEST_F(InputFilterInjectionPolicyTest, TrustedFilteredEvents_KeepOriginalDeviceId) { - // We don't need POLICY_FLAG_FILTERED here, but it will be set in practice, so keep it to make - // the test more closely resemble the real usage - testInjectedKey(POLICY_FLAG_FILTERED | POLICY_FLAG_INPUTFILTER_TRUSTED, 3 /*injectedDeviceId*/, - 3 /*resolvedDeviceId*/); + // Must have POLICY_FLAG_FILTERED here to indicate that the event has gone through the input + // filter. Without it, the event will no different from a regularly injected event, and the + // injected device id will be overwritten. + testInjectedKey(POLICY_FLAG_FILTERED, 3 /*injectedDeviceId*/, 3 /*resolvedDeviceId*/, + 0 /*flags*/); } -TEST_F(InputFilterInjectionPolicyTest, EventsInjectedFromAccessibility_HaveAccessibilityDeviceId) { +TEST_F(InputFilterInjectionPolicyTest, KeyEventsInjectedFromAccessibility_HaveAccessibilityFlag) { testInjectedKey(POLICY_FLAG_FILTERED | POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY, - 3 /*injectedDeviceId*/, ACCESSIBILITY_DEVICE_ID /*resolvedDeviceId*/); + 3 /*injectedDeviceId*/, 3 /*resolvedDeviceId*/, + AKEY_EVENT_FLAG_IS_ACCESSIBILITY_EVENT); +} + +TEST_F(InputFilterInjectionPolicyTest, + MotionEventsInjectedFromAccessibility_HaveAccessibilityFlag) { + testInjectedMotion(POLICY_FLAG_FILTERED | POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY, + 3 /*injectedDeviceId*/, 3 /*resolvedDeviceId*/, + AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT); } TEST_F(InputFilterInjectionPolicyTest, RegularInjectedEvents_ReceiveVirtualDeviceId) { testInjectedKey(0 /*policyFlags*/, 3 /*injectedDeviceId*/, - VIRTUAL_KEYBOARD_ID /*resolvedDeviceId*/); + VIRTUAL_KEYBOARD_ID /*resolvedDeviceId*/, 0 /*flags*/); } class InputDispatcherOnPointerDownOutsideFocus : public InputDispatcherTest { diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 73198bc5a1..997cbe88a1 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -2276,6 +2276,7 @@ TEST_F(TouchIntegrationTest, InputEvent_ProcessSingleTouch) { const Point centerPoint = mDevice->getCenterPoint(); // ACTION_DOWN + mDevice->sendTrackingId(FIRST_TRACKING_ID); mDevice->sendDown(centerPoint); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); @@ -2296,6 +2297,8 @@ TEST_F(TouchIntegrationTest, InputEvent_ProcessMultiTouch) { const Point centerPoint = mDevice->getCenterPoint(); // ACTION_DOWN + mDevice->sendSlot(FIRST_SLOT); + mDevice->sendTrackingId(FIRST_TRACKING_ID); mDevice->sendDown(centerPoint); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); @@ -8217,6 +8220,70 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_KeepFirstPoin ASSERT_NE(AMOTION_EVENT_FLAG_CANCELED, motionArgs.flags); } +/** + * Test multi-touch should sent ACTION_POINTER_UP/ACTION_UP when received the INVALID_TRACKING_ID, + * to prevent the driver side may send unexpected data after set tracking id as INVALID_TRACKING_ID + * cause slot be valid again. + */ +TEST_F(MultiTouchInputMapperTest, Process_MultiTouch_WithInvalidTrackingId) { + addConfigurationProperty("touch.deviceType", "touchScreen"); + prepareDisplay(DISPLAY_ORIENTATION_0); + prepareAxes(POSITION | ID | SLOT | PRESSURE); + MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); + + NotifyMotionArgs motionArgs; + + constexpr int32_t x1 = 100, y1 = 200, x2 = 0, y2 = 0; + // First finger down. + processId(mapper, FIRST_TRACKING_ID); + processPosition(mapper, x1, y1); + processPressure(mapper, RAW_PRESSURE_MAX); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); + ASSERT_EQ(uint32_t(1), motionArgs.pointerCount); + + // First finger move. + processId(mapper, FIRST_TRACKING_ID); + processPosition(mapper, x1 + 1, y1 + 1); + processPressure(mapper, RAW_PRESSURE_MAX); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(uint32_t(1), motionArgs.pointerCount); + + // Second finger down. + processSlot(mapper, SECOND_SLOT); + processId(mapper, SECOND_TRACKING_ID); + processPosition(mapper, x2, y2); + processPressure(mapper, RAW_PRESSURE_MAX); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + motionArgs.action); + ASSERT_EQ(uint32_t(2), motionArgs.pointerCount); + + // second finger up with some unexpected data. + processSlot(mapper, SECOND_SLOT); + processId(mapper, INVALID_TRACKING_ID); + processPosition(mapper, x2, y2); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + motionArgs.action); + ASSERT_EQ(uint32_t(2), motionArgs.pointerCount); + + // first finger up with some unexpected data. + processSlot(mapper, FIRST_SLOT); + processId(mapper, INVALID_TRACKING_ID); + processPosition(mapper, x2, y2); + processPressure(mapper, RAW_PRESSURE_MAX); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); + ASSERT_EQ(uint32_t(1), motionArgs.pointerCount); +} + // --- MultiTouchInputMapperTest_ExternalDevice --- class MultiTouchInputMapperTest_ExternalDevice : public MultiTouchInputMapperTest { diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 645e883364..032ff9a572 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -590,6 +590,7 @@ bool BufferStateLayer::setTransactionCompletedListeners( } bool BufferStateLayer::setTransparentRegionHint(const Region& transparent) { + mDrawingState.sequence++; mDrawingState.transparentRegionHint = transparent; mDrawingState.modified = true; setTransactionFlags(eTransactionNeeded); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h index 2bf931cb3d..2e7a377feb 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h @@ -65,7 +65,9 @@ public: size_t getLayerCount() const { return mLayers.size(); } const Layer& getFirstLayer() const { return mLayers[0]; } const Rect& getBounds() const { return mBounds; } - Rect getTextureBounds() const { return mOutputSpace.content; } + Rect getTextureBounds() const { + return mTexture ? mTexture->get()->getBuffer()->getBounds() : Rect::INVALID_RECT; + } const Region& getVisibleRegion() const { return mVisibleRegion; } size_t getAge() const { return mAge; } std::shared_ptr<renderengine::ExternalTexture> getBuffer() const { diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 742b155c9f..ee73cfc0c1 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -3487,7 +3487,7 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifDisplayIsNotSecure) mLayer2.mLayerFEState.hasProtectedContent = true; EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(true)); EXPECT_CALL(mRenderEngine, isProtected).WillOnce(Return(true)); - EXPECT_CALL(mRenderEngine, useProtectedContext(false)).WillOnce(Return(true)); + EXPECT_CALL(mRenderEngine, useProtectedContext(false)); mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); } diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp index 7f0e186692..b05a594a92 100644 --- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp @@ -355,7 +355,7 @@ TEST_F(CachedSetTest, render) { expectReadyBuffer(cachedSet); EXPECT_EQ(mOutputState.framebufferSpace, cachedSet.getOutputSpace()); - EXPECT_EQ(mOutputState.framebufferSpace.content, cachedSet.getTextureBounds()); + EXPECT_EQ(Rect(kOutputSize.width, kOutputSize.height), cachedSet.getTextureBounds()); // Now check that appending a new cached set properly cleans up RenderEngine resources. CachedSet::Layer& layer3 = *mTestLayers[2]->cachedSetLayer.get(); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index ad31b3fcad..00e043289a 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -177,6 +177,9 @@ Layer::~Layer() { if (mDrawingState.sidebandStream != nullptr) { mFlinger->mTunnelModeEnabledReporter->decrementTunnelModeCount(); } + if (mHadClonedChild) { + mFlinger->mNumClones--; + } } LayerCreationArgs::LayerCreationArgs(SurfaceFlinger* flinger, sp<Client> client, std::string name, @@ -254,6 +257,7 @@ void Layer::addToCurrentState() { if (mRemovedFromDrawingState) { mRemovedFromDrawingState = false; mFlinger->mScheduler->registerLayer(this); + mFlinger->removeFromOffscreenLayers(this); } for (const auto& child : mCurrentChildren) { @@ -2535,6 +2539,12 @@ bool Layer::getPrimaryDisplayOnly() const { return parent == nullptr ? false : parent->getPrimaryDisplayOnly(); } +void Layer::setClonedChild(const sp<Layer>& clonedChild) { + mClonedChild = clonedChild; + mHadClonedChild = true; + mFlinger->mNumClones++; +} + // --------------------------------------------------------------------------- std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index ec9bb7c27f..e726d379d6 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -863,6 +863,8 @@ public: // The layers in the cloned hierarchy will match the lifetime of the real layers. That is // if the real layer is destroyed, then the clone layer will also be destroyed. sp<Layer> mClonedChild; + bool mHadClonedChild = false; + void setClonedChild(const sp<Layer>& mClonedChild); mutable bool contentDirty{false}; Region surfaceDamageRegion; diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 653aca6cde..aa2fec56ad 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -287,33 +287,12 @@ void RegionSamplingThread::captureSample() { descriptors.emplace_back(descriptor); } - auto dx = 0; - auto dy = 0; - switch (orientation) { - case ui::Transform::ROT_90: - dx = displaySize.getWidth(); - break; - case ui::Transform::ROT_180: - dx = displaySize.getWidth(); - dy = displaySize.getHeight(); - break; - case ui::Transform::ROT_270: - dy = displaySize.getHeight(); - break; - default: - break; - } - - ui::Transform t(orientation); - auto screencapRegion = t.transform(sampleRegion); - screencapRegion = screencapRegion.translate(dx, dy); - const Rect sampledBounds = sampleRegion.bounds(); + constexpr bool kUseIdentityTransform = false; SurfaceFlinger::RenderAreaFuture renderAreaFuture = ftl::defer([=] { - return DisplayRenderArea::create(displayWeak, screencapRegion.bounds(), - sampledBounds.getSize(), ui::Dataspace::V0_SRGB, - orientation); + return DisplayRenderArea::create(displayWeak, sampledBounds, sampledBounds.getSize(), + ui::Dataspace::V0_SRGB, kUseIdentityTransform); }); std::unordered_set<sp<IRegionSamplingListener>, SpHash<IRegionSamplingListener>> listeners; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 8df0852a3e..2650fa0583 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -45,6 +45,7 @@ #include <compositionengine/OutputLayer.h> #include <compositionengine/RenderSurface.h> #include <compositionengine/impl/OutputCompositionState.h> +#include <compositionengine/impl/OutputLayerCompositionState.h> #include <configstore/Utils.h> #include <cutils/compiler.h> #include <cutils/properties.h> @@ -2309,21 +2310,24 @@ void SurfaceFlinger::postComposition() { HdrLayerInfoReporter::HdrLayerInfo info; int32_t maxArea = 0; mDrawingState.traverse([&, compositionDisplay = compositionDisplay](Layer* layer) { - if (layer->isVisible() && - compositionDisplay->belongsInOutput(layer->getCompositionEngineLayerFE())) { + const auto layerFe = layer->getCompositionEngineLayerFE(); + if (layer->isVisible() && compositionDisplay->belongsInOutput(layerFe)) { const Dataspace transfer = static_cast<Dataspace>(layer->getDataSpace() & Dataspace::TRANSFER_MASK); const bool isHdr = (transfer == Dataspace::TRANSFER_ST2084 || transfer == Dataspace::TRANSFER_HLG); if (isHdr) { - info.numberOfHdrLayers++; - auto bufferRect = layer->getCompositionState()->geomBufferSize; - int32_t area = bufferRect.width() * bufferRect.height(); - if (area > maxArea) { - maxArea = area; - info.maxW = bufferRect.width(); - info.maxH = bufferRect.height(); + const auto* outputLayer = compositionDisplay->getOutputLayerForLayer(layerFe); + if (outputLayer) { + info.numberOfHdrLayers++; + const auto displayFrame = outputLayer->getState().displayFrame; + const int32_t area = displayFrame.width() * displayFrame.height(); + if (area > maxArea) { + maxArea = area; + info.maxW = displayFrame.width(); + info.maxH = displayFrame.height(); + } } } } @@ -3254,19 +3258,10 @@ void SurfaceFlinger::commitTransactionLocked() { } } - // TODO(b/163019109): See if this traversal is needed at all... - if (!mOffscreenLayers.empty()) { - mDrawingState.traverse([&](Layer* layer) { - // If the layer can be reached when traversing mDrawingState, then the layer is no - // longer offscreen. Remove the layer from the offscreenLayer set. - if (mOffscreenLayers.count(layer)) { - mOffscreenLayers.erase(layer); - } - }); - } - commitOffscreenLayers(); - mDrawingState.traverse([&](Layer* layer) { layer->updateMirrorInfo(); }); + if (mNumClones > 0) { + mDrawingState.traverse([&](Layer* layer) { layer->updateMirrorInfo(); }); + } } void SurfaceFlinger::commitOffscreenLayers() { @@ -3372,7 +3367,9 @@ bool SurfaceFlinger::handlePageFlip() { mBootStage = BootStage::BOOTANIMATION; } - mDrawingState.traverse([&](Layer* layer) { layer->updateCloneBufferInfo(); }); + if (mNumClones > 0) { + mDrawingState.traverse([&](Layer* layer) { layer->updateCloneBufferInfo(); }); + } // Only continue with the refresh if there is actually new work to do return !mLayersWithQueuedFrames.empty() && newDataLatched; @@ -4257,7 +4254,7 @@ status_t SurfaceFlinger::mirrorLayer(const sp<Client>& client, const sp<IBinder> return result; } - mirrorLayer->mClonedChild = mirrorFrom->createClone(); + mirrorLayer->setClonedChild(mirrorFrom->createClone()); } *outLayerId = mirrorLayer->sequence; @@ -6623,7 +6620,7 @@ void SurfaceFlinger::onLayerFirstRef(Layer* layer) { void SurfaceFlinger::onLayerDestroyed(Layer* layer) { mNumLayers--; - removeFromOffscreenLayers(layer); + removeHierarchyFromOffscreenLayers(layer); if (!layer->isRemovedFromCurrentState()) { mScheduler->deregisterLayer(layer); } @@ -6636,13 +6633,17 @@ void SurfaceFlinger::onLayerDestroyed(Layer* layer) { // from dangling children layers such that they are not reachable from the // Drawing state nor the offscreen layer list // See b/141111965 -void SurfaceFlinger::removeFromOffscreenLayers(Layer* layer) { +void SurfaceFlinger::removeHierarchyFromOffscreenLayers(Layer* layer) { for (auto& child : layer->getCurrentChildren()) { mOffscreenLayers.emplace(child.get()); } mOffscreenLayers.erase(layer); } +void SurfaceFlinger::removeFromOffscreenLayers(Layer* layer) { + mOffscreenLayers.erase(layer); +} + status_t SurfaceFlinger::setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor, float lightPosY, float lightPosZ, float lightRadius) { @@ -6861,7 +6862,7 @@ int SurfaceFlinger::getMaxAcquiredBufferCountForRefreshRate(Fps refreshRate) con void SurfaceFlinger::TransactionState::traverseStatesWithBuffers( std::function<void(const layer_state_t&)> visitor) { for (const auto& state : states) { - if (state.state.hasBufferChanges() && (state.state.surface)) { + if (state.state.hasBufferChanges() && state.state.hasValidBuffer() && state.state.surface) { visitor(state.state); } } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 644f76f65a..b9b26db260 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -313,8 +313,12 @@ public: void onLayerFirstRef(Layer*); void onLayerDestroyed(Layer*); + void removeHierarchyFromOffscreenLayers(Layer* layer); void removeFromOffscreenLayers(Layer* layer); + // TODO: Remove atomic if move dtor to main thread CL lands + std::atomic<uint32_t> mNumClones; + TransactionCallbackInvoker& getTransactionCallbackInvoker() { return mTransactionCallbackInvoker; } |