diff options
26 files changed, 440 insertions, 111 deletions
diff --git a/cmds/installd/run_dex2oat.cpp b/cmds/installd/run_dex2oat.cpp index a27fd103a4..e847626a14 100644 --- a/cmds/installd/run_dex2oat.cpp +++ b/cmds/installd/run_dex2oat.cpp @@ -324,6 +324,12 @@ void RunDex2Oat::PrepareCompilerRuntimeAndPerfConfigFlags(bool post_bootcomplete AddRuntimeArg(MapPropertyToArg("dalvik.vm.dex2oat-Xms", "-Xms%s")); AddRuntimeArg(MapPropertyToArg("dalvik.vm.dex2oat-Xmx", "-Xmx%s")); + + // Enable compiling dex files in isolation on low ram devices. + // It takes longer but reduces the memory footprint. + if (GetBoolProperty("ro.config.low_ram", false)) { + AddArg("--compile-individually"); + } } void RunDex2Oat::Exec(int exit_code) { diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 52d3fa33f0..364c939c18 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -151,6 +151,7 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceCont 1, false); static int32_t id = 0; auto consumerName = mName + "(BLAST Consumer)" + std::to_string(id); + mPendingBufferTrace = "PendingBuffer - " + mName + "BLAST#" + std::to_string(id); id++; mBufferItemConsumer->setName(String8(consumerName.c_str())); mBufferItemConsumer->setFrameAvailableListener(this); @@ -168,7 +169,6 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceCont .setFlags(surface, layer_state_t::eEnableBackpressure, layer_state_t::eEnableBackpressure) .apply(); - mNumAcquired = 0; mNumFrameAvailable = 0; } @@ -205,6 +205,11 @@ void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, applyTransaction = true; } + if (mSurfaceControl != nullptr) { + mTransformHint = mSurfaceControl->getTransformHint(); + mBufferItemConsumer->setTransformHint(mTransformHint); + } + ui::Size newSize(width, height); if (mRequestedSize != newSize) { mRequestedSize.set(newSize); @@ -259,15 +264,18 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence mTransformHint = stat.transformHint; mBufferItemConsumer->setTransformHint(mTransformHint); - mBufferItemConsumer - ->updateFrameTimestamps(stat.frameEventStats.frameNumber, - stat.frameEventStats.refreshStartTime, - stat.frameEventStats.gpuCompositionDoneFence, - stat.presentFence, stat.previousReleaseFence, - stat.frameEventStats.compositorTiming, - stat.latchTime, - stat.frameEventStats.dequeueReadyTime); - + // Update frametime stamps if the frame was latched and presented, indicated by a + // valid latch time. + if (stat.latchTime > 0) { + mBufferItemConsumer + ->updateFrameTimestamps(stat.frameEventStats.frameNumber, + stat.frameEventStats.refreshStartTime, + stat.frameEventStats.gpuCompositionDoneFence, + stat.presentFence, stat.previousReleaseFence, + stat.frameEventStats.compositorTiming, + stat.latchTime, + stat.frameEventStats.dequeueReadyTime); + } currFrameNumber = stat.frameEventStats.frameNumber; if (mTransactionCompleteCallback && @@ -361,6 +369,7 @@ void BLASTBufferQueue::releaseBufferCallback(uint64_t graphicBufferId, ATRACE_INT("PendingRelease", mPendingRelease.size()); mNumAcquired--; + ATRACE_INT(mPendingBufferTrace.c_str(), mNumFrameAvailable + mNumAcquired); processNextBufferLocked(false /* useNextTransaction */); mCallbackCV.notify_all(); } @@ -529,6 +538,7 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) { } // add to shadow queue mNumFrameAvailable++; + ATRACE_INT(mPendingBufferTrace.c_str(), mNumFrameAvailable + mNumAcquired); BQA_LOGV("onFrameAvailable framenumber=%" PRIu64 " nextTransactionSet=%s", item.mFrameNumber, toString(nextTransactionSet)); diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 0981e760a5..cb0e65e409 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -125,6 +125,7 @@ private: static PixelFormat convertBufferFormat(PixelFormat& format); std::string mName; + std::string mPendingBufferTrace; sp<SurfaceControl> mSurfaceControl; std::mutex mMutex; diff --git a/libs/gui/include/gui/FrameTimestamps.h b/libs/gui/include/gui/FrameTimestamps.h index 0750080e1c..dd3de58844 100644 --- a/libs/gui/include/gui/FrameTimestamps.h +++ b/libs/gui/include/gui/FrameTimestamps.h @@ -131,6 +131,7 @@ public: // Public for testing. static nsecs_t snapToNextTick( nsecs_t timestamp, nsecs_t tickPhase, nsecs_t tickInterval); + nsecs_t getReportedCompositeDeadline() const { return mCompositorTiming.deadline; }; nsecs_t getNextCompositeDeadline(const nsecs_t now) const; nsecs_t getCompositeInterval() const { return mCompositorTiming.interval; } diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index 06660b8b50..6ff67aa7cb 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -948,21 +948,22 @@ TEST_F(BLASTBufferQueueTransformTest, setTransform_ROT_270) { class BLASTFrameEventHistoryTest : public BLASTBufferQueueTest { public: void setUpAndQueueBuffer(const sp<IGraphicBufferProducer>& igbProducer, - nsecs_t* requestedPresentTime, nsecs_t* postedTime, + nsecs_t* outRequestedPresentTime, nsecs_t* postedTime, IGraphicBufferProducer::QueueBufferOutput* qbOutput, - bool getFrameTimestamps, nsecs_t requestedPresentTimeDelay = 0) { + bool getFrameTimestamps, nsecs_t requestedPresentTime = systemTime()) { int slot; sp<Fence> fence; sp<GraphicBuffer> buf; auto ret = igbProducer->dequeueBuffer(&slot, &fence, mDisplayWidth, mDisplayHeight, PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr, nullptr); - ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret); - ASSERT_EQ(OK, igbProducer->requestBuffer(slot, &buf)); + if (IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION == ret) { + ASSERT_EQ(OK, igbProducer->requestBuffer(slot, &buf)); + } - nsecs_t requestedTime = systemTime() + requestedPresentTimeDelay; - if (requestedPresentTime) *requestedPresentTime = requestedTime; - IGraphicBufferProducer::QueueBufferInput input(requestedTime, false, HAL_DATASPACE_UNKNOWN, + *outRequestedPresentTime = requestedPresentTime; + IGraphicBufferProducer::QueueBufferInput input(requestedPresentTime, false, + HAL_DATASPACE_UNKNOWN, Rect(mDisplayWidth, mDisplayHeight), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE, /*sticky*/ 0, @@ -1034,9 +1035,11 @@ TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_DroppedFrame) { IGraphicBufferProducer::QueueBufferOutput qbOutput; nsecs_t requestedPresentTimeA = 0; nsecs_t postedTimeA = 0; - nsecs_t presentTimeDelay = std::chrono::nanoseconds(500ms).count(); + // Present the frame sometime in the future so we can add two frames to the queue so the older + // one will be dropped. + nsecs_t presentTime = systemTime() + std::chrono::nanoseconds(500ms).count(); setUpAndQueueBuffer(igbProducer, &requestedPresentTimeA, &postedTimeA, &qbOutput, true, - presentTimeDelay); + presentTime); history.applyDelta(qbOutput.frameTimestamps); FrameEvents* events = nullptr; @@ -1049,7 +1052,10 @@ TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_DroppedFrame) { // queue another buffer so the first can be dropped nsecs_t requestedPresentTimeB = 0; nsecs_t postedTimeB = 0; - setUpAndQueueBuffer(igbProducer, &requestedPresentTimeB, &postedTimeB, &qbOutput, true); + adapter.setTransactionCompleteCallback(2); + presentTime = systemTime() + std::chrono::nanoseconds(1ms).count(); + setUpAndQueueBuffer(igbProducer, &requestedPresentTimeB, &postedTimeB, &qbOutput, true, + presentTime); history.applyDelta(qbOutput.frameTimestamps); events = history.getFrame(1); ASSERT_NE(nullptr, events); @@ -1059,20 +1065,75 @@ TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_DroppedFrame) { ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime); ASSERT_GE(events->postedTime, postedTimeA); - // a valid latchtime should not be set + // a valid latchtime and pre and post composition info should not be set for the dropped frame ASSERT_FALSE(events->hasLatchInfo()); ASSERT_FALSE(events->hasDequeueReadyInfo()); + ASSERT_FALSE(events->hasGpuCompositionDoneInfo()); + ASSERT_FALSE(events->hasDisplayPresentInfo()); + ASSERT_FALSE(events->hasReleaseInfo()); - ASSERT_NE(nullptr, events->gpuCompositionDoneFence); - ASSERT_NE(nullptr, events->displayPresentFence); - ASSERT_NE(nullptr, events->releaseFence); + // wait for the last transaction to be completed. + adapter.waitForCallback(2); - // we should also have gotten the initial values for the next frame + // queue another buffer so we query for frame event deltas + nsecs_t requestedPresentTimeC = 0; + nsecs_t postedTimeC = 0; + setUpAndQueueBuffer(igbProducer, &requestedPresentTimeC, &postedTimeC, &qbOutput, true); + history.applyDelta(qbOutput.frameTimestamps); + + // frame number, requestedPresentTime, and postTime should not have changed + ASSERT_EQ(1, events->frameNumber); + ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime); + ASSERT_GE(events->postedTime, postedTimeA); + + // a valid latchtime and pre and post composition info should not be set for the dropped frame + ASSERT_FALSE(events->hasLatchInfo()); + ASSERT_FALSE(events->hasDequeueReadyInfo()); + ASSERT_FALSE(events->hasGpuCompositionDoneInfo()); + ASSERT_FALSE(events->hasDisplayPresentInfo()); + ASSERT_FALSE(events->hasReleaseInfo()); + + // we should also have gotten values for the presented frame events = history.getFrame(2); ASSERT_NE(nullptr, events); ASSERT_EQ(2, events->frameNumber); ASSERT_EQ(requestedPresentTimeB, events->requestedPresentTime); ASSERT_GE(events->postedTime, postedTimeB); + ASSERT_GE(events->latchTime, postedTimeB); + ASSERT_GE(events->dequeueReadyTime, events->latchTime); + ASSERT_NE(nullptr, events->gpuCompositionDoneFence); + ASSERT_NE(nullptr, events->displayPresentFence); + ASSERT_NE(nullptr, events->releaseFence); + + // wait for any callbacks that have not been received + adapter.waitForCallbacks(); +} + +TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_CompositorTimings) { + BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); + sp<IGraphicBufferProducer> igbProducer; + ProducerFrameEventHistory history; + setUpProducer(adapter, igbProducer); + + IGraphicBufferProducer::QueueBufferOutput qbOutput; + nsecs_t requestedPresentTimeA = 0; + nsecs_t postedTimeA = 0; + adapter.setTransactionCompleteCallback(1); + setUpAndQueueBuffer(igbProducer, &requestedPresentTimeA, &postedTimeA, &qbOutput, true); + history.applyDelta(qbOutput.frameTimestamps); + adapter.waitForCallback(1); + + // queue another buffer so we query for frame event deltas + nsecs_t requestedPresentTimeB = 0; + nsecs_t postedTimeB = 0; + setUpAndQueueBuffer(igbProducer, &requestedPresentTimeB, &postedTimeB, &qbOutput, true); + history.applyDelta(qbOutput.frameTimestamps); + + // check for a valid compositor deadline + ASSERT_NE(0, history.getReportedCompositeDeadline()); + + // wait for any callbacks that have not been received + adapter.waitForCallbacks(); } } // namespace android diff --git a/services/inputflinger/dispatcher/FocusResolver.cpp b/services/inputflinger/dispatcher/FocusResolver.cpp index 2db8c13a67..fb194355ba 100644 --- a/services/inputflinger/dispatcher/FocusResolver.cpp +++ b/services/inputflinger/dispatcher/FocusResolver.cpp @@ -216,4 +216,9 @@ std::string FocusResolver::dump() const { return dump; } +void FocusResolver::displayRemoved(int32_t displayId) { + mFocusRequestByDisplay.erase(displayId); + mLastFocusResultByDisplay.erase(displayId); +} + } // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/FocusResolver.h b/services/inputflinger/dispatcher/FocusResolver.h index dc5eeebb4e..afe16b3b45 100644 --- a/services/inputflinger/dispatcher/FocusResolver.h +++ b/services/inputflinger/dispatcher/FocusResolver.h @@ -62,6 +62,9 @@ public: std::optional<FocusResolver::FocusChanges> setFocusedWindow( const FocusRequest& request, const std::vector<sp<InputWindowHandle>>& windows); + // Display has been removed from the system, clean up old references. + void displayRemoved(int32_t displayId); + // exposed for debugging bool hasFocusedWindowTokens() const { return !mFocusedWindowTokenByDisplay.empty(); } std::string dumpFocusedWindows() const; diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index d2b8739f96..c0010abf8a 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -4613,28 +4613,32 @@ void InputDispatcher::setFocusedApplication( } { // acquire lock std::scoped_lock _l(mLock); + setFocusedApplicationLocked(displayId, inputApplicationHandle); + } // release lock - std::shared_ptr<InputApplicationHandle> oldFocusedApplicationHandle = - getValueByKey(mFocusedApplicationHandlesByDisplay, displayId); + // Wake up poll loop since it may need to make new input dispatching choices. + mLooper->wake(); +} - if (sharedPointersEqual(oldFocusedApplicationHandle, inputApplicationHandle)) { - return; // This application is already focused. No need to wake up or change anything. - } +void InputDispatcher::setFocusedApplicationLocked( + int32_t displayId, const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle) { + std::shared_ptr<InputApplicationHandle> oldFocusedApplicationHandle = + getValueByKey(mFocusedApplicationHandlesByDisplay, displayId); - // Set the new application handle. - if (inputApplicationHandle != nullptr) { - mFocusedApplicationHandlesByDisplay[displayId] = inputApplicationHandle; - } else { - mFocusedApplicationHandlesByDisplay.erase(displayId); - } + if (sharedPointersEqual(oldFocusedApplicationHandle, inputApplicationHandle)) { + return; // This application is already focused. No need to wake up or change anything. + } - // No matter what the old focused application was, stop waiting on it because it is - // no longer focused. - resetNoFocusedWindowTimeoutLocked(); - } // release lock + // Set the new application handle. + if (inputApplicationHandle != nullptr) { + mFocusedApplicationHandlesByDisplay[displayId] = inputApplicationHandle; + } else { + mFocusedApplicationHandlesByDisplay.erase(displayId); + } - // Wake up poll loop since it may need to make new input dispatching choices. - mLooper->wake(); + // No matter what the old focused application was, stop waiting on it because it is + // no longer focused. + resetNoFocusedWindowTimeoutLocked(); } /** @@ -6208,4 +6212,19 @@ void InputDispatcher::doSetPointerCaptureLockedInterruptible( mLock.lock(); } +void InputDispatcher::displayRemoved(int32_t displayId) { + { // acquire lock + std::scoped_lock _l(mLock); + // Set an empty list to remove all handles from the specific display. + setInputWindowsLocked(/* window handles */ {}, displayId); + setFocusedApplicationLocked(displayId, nullptr); + // Call focus resolver to clean up stale requests. This must be called after input windows + // have been removed for the removed display. + mFocusResolver.displayRemoved(displayId); + } // release lock + + // Wake up poll loop since it may need to make new input dispatching choices. + mLooper->wake(); +} + } // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index bb3f3e6dfc..9edf41c9c0 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -139,6 +139,8 @@ public: std::array<uint8_t, 32> sign(const VerifiedInputEvent& event) const; + void displayRemoved(int32_t displayId) override; + private: enum class DropReason { NOT_DROPPED, @@ -343,6 +345,9 @@ private: std::unordered_map<int32_t, TouchState> mTouchStatesByDisplay GUARDED_BY(mLock); std::unique_ptr<DragState> mDragState GUARDED_BY(mLock); + void setFocusedApplicationLocked( + int32_t displayId, + const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle) REQUIRES(mLock); // Focused applications. std::unordered_map<int32_t, std::shared_ptr<InputApplicationHandle>> mFocusedApplicationHandlesByDisplay GUARDED_BY(mLock); diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h index 7f85e5393b..43428a0130 100644 --- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h +++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h @@ -209,6 +209,11 @@ public: * Returns true on success. */ virtual bool flushSensor(int deviceId, InputDeviceSensorType sensorType) = 0; + + /** + * Called when a display has been removed from the system. + */ + virtual void displayRemoved(int32_t displayId) = 0; }; } // namespace android diff --git a/services/inputflinger/tests/FocusResolver_test.cpp b/services/inputflinger/tests/FocusResolver_test.cpp index 17efb5b99f..9051ff12c2 100644 --- a/services/inputflinger/tests/FocusResolver_test.cpp +++ b/services/inputflinger/tests/FocusResolver_test.cpp @@ -256,5 +256,37 @@ TEST(FocusResolverTest, ConditionalFocusRequestsAreNotPersistent) { // dropped. ASSERT_FALSE(changes); } +TEST(FocusResolverTest, FocusRequestsAreClearedWhenWindowIsRemoved) { + sp<IBinder> windowToken = new BBinder(); + std::vector<sp<InputWindowHandle>> windows; + + sp<FakeWindowHandle> window = new FakeWindowHandle("Test Window", windowToken, + true /* focusable */, true /* visible */); + windows.push_back(window); + + FocusRequest request; + request.displayId = 42; + request.token = windowToken; + FocusResolver focusResolver; + std::optional<FocusResolver::FocusChanges> changes = + focusResolver.setFocusedWindow(request, windows); + ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken); + ASSERT_EQ(request.displayId, changes->displayId); + + // Start with a focused window + window->setFocusable(true); + changes = focusResolver.setInputWindows(request.displayId, windows); + ASSERT_FOCUS_CHANGE(changes, /*from*/ nullptr, /*to*/ windowToken); + + // When a display is removed, all windows are removed from the display + // and our focused window loses focus + changes = focusResolver.setInputWindows(request.displayId, {}); + ASSERT_FOCUS_CHANGE(changes, /*from*/ windowToken, /*to*/ nullptr); + focusResolver.displayRemoved(request.displayId); + + // When a display is readded, the window does not get focus since the request was cleared. + changes = focusResolver.setInputWindows(request.displayId, windows); + ASSERT_FALSE(changes); +} } // namespace android::inputdispatcher diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index d51acce4b2..77ca12c5dc 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -2688,6 +2688,23 @@ TEST_F(InputDispatcherTest, SetFocusedWindow_DeferInvisibleWindow) { window->consumeKeyDown(ADISPLAY_ID_DEFAULT); } +TEST_F(InputDispatcherTest, DisplayRemoved) { + std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); + sp<FakeWindowHandle> window = + new FakeWindowHandle(application, mDispatcher, "window", ADISPLAY_ID_DEFAULT); + mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); + + // window is granted focus. + window->setFocusable(true); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + setFocusedWindow(window); + window->consumeFocusEvent(true); + + // When a display is removed window loses focus. + mDispatcher->displayRemoved(ADISPLAY_ID_DEFAULT); + window->consumeFocusEvent(false); +} + /** * Launch two windows, with different owners. One window (slipperyExitWindow) has Flag::SLIPPERY, * and overlaps the other window, slipperyEnterWindow. The window 'slipperyExitWindow' is on top diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index a3b7b13d4c..6b5cf04536 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -540,10 +540,16 @@ bool BufferStateLayer::setApi(int32_t api) { bool BufferStateLayer::setSidebandStream(const sp<NativeHandle>& sidebandStream) { if (mDrawingState.sidebandStream == sidebandStream) return false; + + if (mDrawingState.sidebandStream != nullptr && sidebandStream == nullptr) { + mFlinger->mTunnelModeEnabledReporter->decrementTunnelModeCount(); + } else if (sidebandStream != nullptr) { + mFlinger->mTunnelModeEnabledReporter->incrementTunnelModeCount(); + } + mDrawingState.sidebandStream = sidebandStream; mDrawingState.modified = true; setTransactionFlags(eTransactionNeeded); - if (!mSidebandStreamChanged.exchange(true)) { // mSidebandStreamChanged was false mFlinger->signalLayerUpdate(); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index b819dbe7ce..ad31b3fcad 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -70,6 +70,7 @@ #include "MonitoredProducer.h" #include "SurfaceFlinger.h" #include "TimeStats/TimeStats.h" +#include "TunnelModeEnabledReporter.h" #include "input/InputWindow.h" #define DEBUG_RESIZE 0 @@ -172,6 +173,10 @@ Layer::~Layer() { mFrameTracker.logAndResetStats(mName); mFlinger->onLayerDestroyed(this); + + if (mDrawingState.sidebandStream != nullptr) { + mFlinger->mTunnelModeEnabledReporter->decrementTunnelModeCount(); + } } LayerCreationArgs::LayerCreationArgs(SurfaceFlinger* flinger, sp<Client> client, std::string name, @@ -679,11 +684,6 @@ bool Layer::isSecure() const { uint32_t Layer::doTransaction(uint32_t flags) { ATRACE_CALL(); - if (mChildrenChanged) { - flags |= eVisibleRegion; - mChildrenChanged = false; - } - // TODO: This is unfortunate. mDrawingStateModified = mDrawingState.modified; mDrawingState.modified = false; @@ -705,11 +705,6 @@ uint32_t Layer::doTransaction(uint32_t flags) { mNeedsFiltering = getActiveTransform(s).needsBilinearFiltering(); } - if (mDrawingState.inputInfoChanged) { - flags |= eInputInfoChanged; - mDrawingState.inputInfoChanged = false; - } - commitTransaction(mDrawingState); return flags; @@ -782,6 +777,8 @@ bool Layer::setLayer(int32_t z) { mDrawingState.z = z; mDrawingState.modified = true; + mFlinger->mSomeChildrenChanged = true; + // Discard all relative layering. if (mDrawingState.zOrderRelativeOf != nullptr) { sp<Layer> strongRelative = mDrawingState.zOrderRelativeOf.promote(); @@ -832,6 +829,8 @@ bool Layer::setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t relati return false; } + mFlinger->mSomeChildrenChanged = true; + mDrawingState.sequence++; mDrawingState.modified = true; mDrawingState.z = relativeZ; @@ -1562,7 +1561,7 @@ void Layer::setGameModeForTree(int parentGameMode) { } void Layer::addChild(const sp<Layer>& layer) { - mChildrenChanged = true; + mFlinger->mSomeChildrenChanged = true; setTransactionFlags(eTransactionNeeded); mCurrentChildren.add(layer); @@ -1572,7 +1571,7 @@ void Layer::addChild(const sp<Layer>& layer) { } ssize_t Layer::removeChild(const sp<Layer>& layer) { - mChildrenChanged = true; + mFlinger->mSomeChildrenChanged = true; setTransactionFlags(eTransactionNeeded); layer->setParent(nullptr); @@ -1991,7 +1990,7 @@ void Layer::setInputInfo(const InputWindowInfo& info) { mDrawingState.inputInfo = info; mDrawingState.touchableRegionCrop = extractLayerFromBinder(info.touchableRegionCropHandle); mDrawingState.modified = true; - mDrawingState.inputInfoChanged = true; + mFlinger->mInputInfoChanged = true; setTransactionFlags(eTransactionNeeded); } diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 9b30fcb315..ec9bb7c27f 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -186,7 +186,6 @@ public: float cornerRadius; int backgroundBlurRadius; - bool inputInfoChanged; InputWindowInfo inputInfo; wp<Layer> touchableRegionCrop; @@ -997,15 +996,12 @@ protected: // This layer can be a cursor on some displays. bool mPotentialCursor{false}; - LayerVector mCurrentChildren{LayerVector::StateSet::Drawing}; + LayerVector mCurrentChildren{LayerVector::StateSet::Current}; LayerVector mDrawingChildren{LayerVector::StateSet::Drawing}; wp<Layer> mCurrentParent; wp<Layer> mDrawingParent; - // Can only be accessed with the SF state lock held. - bool mChildrenChanged{false}; - // Window types from WindowManager.LayoutParams const InputWindowInfo::Type mWindowType; diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp index 18a28918fd..6b2d745998 100644 --- a/services/surfaceflinger/MonitoredProducer.cpp +++ b/services/surfaceflinger/MonitoredProducer.cpp @@ -140,6 +140,11 @@ status_t MonitoredProducer::getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, outTransformMatrix); } +status_t MonitoredProducer::getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence, + Rect* outRect, uint32_t* outTransform) { + return mProducer->getLastQueuedBuffer(outBuffer, outFence, outRect, outTransform); +} + void MonitoredProducer::getFrameTimestamps(FrameEventHistoryDelta* outDelta) { mProducer->getFrameTimestamps(outDelta); } diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h index 788919b3da..3778277fd3 100644 --- a/services/surfaceflinger/MonitoredProducer.h +++ b/services/surfaceflinger/MonitoredProducer.h @@ -64,6 +64,8 @@ public: virtual status_t setLegacyBufferDrop(bool drop) override; virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence, float outTransformMatrix[16]) override; + virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence, + Rect* outRect, uint32_t* outTransform) override; virtual IBinder* onAsBinder(); virtual status_t setSharedBufferMode(bool sharedBufferMode) override; virtual status_t setAutoRefresh(bool autoRefresh) override; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index c6841ed6e6..a022a8e85f 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -342,6 +342,7 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag) mEventQueue(mFactory.createMessageQueue()), mCompositionEngine(mFactory.createCompositionEngine()), mHwcServiceName(base::GetProperty("debug.sf.hwc_service_name"s, "default"s)), + mTunnelModeEnabledReporter(new TunnelModeEnabledReporter()), mInternalDisplayDensity(getDensityFromProperty("ro.sf.lcd_density", true)), mEmulatedDisplayDensity(getDensityFromProperty("qemu.sf.lcd_density", false)) { ALOGI("Using HWComposer service: %s", mHwcServiceName.c_str()); @@ -2231,18 +2232,15 @@ void SurfaceFlinger::postComposition() { getBE().mDisplayTimeline.push(mPreviousPresentFences[0].fenceTime); + nsecs_t now = systemTime(); + // Set presentation information before calling Layer::releasePendingBuffer, such that jank // information from previous' frame classification is already available when sending jank info // to clients, so they get jank classification as early as possible. - mFrameTimeline->setSfPresent(systemTime(), mPreviousPresentFences[0].fenceTime, + mFrameTimeline->setSfPresent(/* sfPresentTime */ now, mPreviousPresentFences[0].fenceTime, glCompositionDoneFenceTime); - nsecs_t dequeueReadyTime = systemTime(); - for (const auto& layer : mLayersWithQueuedFrames) { - layer->releasePendingBuffer(dequeueReadyTime); - } - - const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(systemTime()); + const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(now); // We use the CompositionEngine::getLastFrameRefreshTimestamp() which might // be sampled a little later than when we started doing work for this frame, @@ -2259,6 +2257,7 @@ void SurfaceFlinger::postComposition() { const bool frameLatched = layer->onPostComposition(display, glCompositionDoneFenceTime, mPreviousPresentFences[0].fenceTime, compositorTiming); + layer->releasePendingBuffer(/*dequeueReadyTime*/ now); if (frameLatched) { recordBufferingStats(layer->getName(), layer->getOccupancyHistory(false)); } @@ -2859,7 +2858,9 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken, (currentState.orientedDisplaySpaceRect != drawingState.orientedDisplaySpaceRect)) { display->setProjection(currentState.orientation, currentState.layerStackSpaceRect, currentState.orientedDisplaySpaceRect); - mDefaultDisplayTransformHint = display->getTransformHint(); + if (display->isPrimary()) { + mDefaultDisplayTransformHint = display->getTransformHint(); + } } if (currentState.width != drawingState.width || currentState.height != drawingState.height) { @@ -2923,23 +2924,12 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) { processDisplayChangesLocked(); processDisplayHotplugEventsLocked(); } + mForceTraversal = false; + mForceTransactionDisplayChange = displayTransactionNeeded; - // Commit layer transactions. This needs to happen after display transactions are - // committed because some geometry logic relies on display orientation. - if ((transactionFlags & eTraversalNeeded) || mForceTraversal || displayTransactionNeeded) { - mForceTraversal = false; - mCurrentState.traverse([&](Layer* layer) { - uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded); - if (!trFlags && !displayTransactionNeeded) return; - - const uint32_t flags = layer->doTransaction(0); - if (flags & Layer::eVisibleRegion) - mVisibleRegionsDirty = true; - - if (flags & Layer::eInputInfoChanged) { - mInputInfoChanged = true; - } - }); + if (mSomeChildrenChanged) { + mVisibleRegionsDirty = true; + mSomeChildrenChanged = false; } // Update transform hint @@ -3164,7 +3154,6 @@ void SurfaceFlinger::initScheduler(const DisplayDeviceState& displayState) { mRegionSamplingThread = new RegionSamplingThread(*this, RegionSamplingThread::EnvironmentTimingTunables()); mFpsReporter = new FpsReporter(*mFrameTimeline, *this); - mTunnelModeEnabledReporter = new TunnelModeEnabledReporter(*this); // Dispatch a mode change request for the primary display on scheduler // initialization, so that the EventThreads always contain a reference to a // prior configuration. @@ -3235,9 +3224,12 @@ void SurfaceFlinger::commitTransactionLocked() { // clear the "changed" flags in current state mCurrentState.colorMatrixChanged = false; - for (const auto& rootLayer : mDrawingState.layersSortedByZ) { - rootLayer->commitChildList(); + if (mVisibleRegionsDirty) { + for (const auto& rootLayer : mDrawingState.layersSortedByZ) { + rootLayer->commitChildList(); + } } + // TODO(b/163019109): See if this traversal is needed at all... if (!mOffscreenLayers.empty()) { mDrawingState.traverse([&](Layer* layer) { @@ -3296,7 +3288,14 @@ bool SurfaceFlinger::handlePageFlip() { // Display is now waiting on Layer 1's frame, which is behind layer 0's // second frame. But layer 0's second frame could be waiting on display. mDrawingState.traverse([&](Layer* layer) { - if (layer->hasReadyFrame()) { + uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded); + if (trFlags || mForceTransactionDisplayChange) { + const uint32_t flags = layer->doTransaction(0); + if (flags & Layer::eVisibleRegion) + mVisibleRegionsDirty = true; + } + + if (layer->hasReadyFrame()) { frameQueued = true; if (layer->shouldPresentNow(expectedPresentTime)) { mLayersWithQueuedFrames.emplace(layer); @@ -3304,10 +3303,11 @@ bool SurfaceFlinger::handlePageFlip() { ATRACE_NAME("!layer->shouldPresentNow()"); layer->useEmptyDamage(); } - } else { + } else { layer->useEmptyDamage(); } }); + mForceTransactionDisplayChange = false; // The client can continue submitting buffers for offscreen layers, but they will not // be shown on screen. Therefore, we need to latch and release buffers of offscreen @@ -4468,10 +4468,11 @@ void SurfaceFlinger::onInitializeDisplays() { d.height = 0; displays.add(d); + nsecs_t now = systemTime(); // It should be on the main thread, apply it directly. applyTransactionState(FrameTimelineInfo{}, state, displays, 0, mInputWindowCommands, - systemTime(), true, {}, systemTime(), true, false, {}, getpid(), getuid(), - 0 /* Undefined transactionId */); + /* desiredPresentTime */ now, true, {}, /* postTime */ now, true, false, + {}, getpid(), getuid(), 0 /* Undefined transactionId */); setPowerModeInternal(display, hal::PowerMode::ON); const nsecs_t vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod(); @@ -6908,6 +6909,8 @@ sp<Layer> SurfaceFlinger::handleLayerCreatedLocked(const sp<IBinder>& handle, bo parent->addChild(layer); } + layer->updateTransformHint(mDefaultDisplayTransformHint); + if (state->initialProducer != nullptr) { mGraphicBufferProducerList.insert(state->initialProducer); LOG_ALWAYS_FATAL_IF(mGraphicBufferProducerList.size() > mMaxGraphicBufferProducerListSize, diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 22d17eb153..f33df86494 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -364,6 +364,7 @@ private: // For unit tests friend class TestableSurfaceFlinger; friend class TransactionApplicationTest; + friend class TunnelModeEnabledReporterTest; using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate; using VsyncModulator = scheduler::VsyncModulator; @@ -1228,8 +1229,14 @@ private: // don't need synchronization State mDrawingState{LayerVector::StateSet::Drawing}; bool mVisibleRegionsDirty = false; - // Set during transaction commit stage to track if the input info for a layer has changed. + + // Set during transaction application stage to track if the input info or children + // for a layer has changed. + // TODO: Also move visibleRegions over to a boolean system. bool mInputInfoChanged = false; + bool mSomeChildrenChanged; + bool mForceTransactionDisplayChange = false; + bool mGeometryInvalid = false; bool mAnimCompositionPending = false; diff --git a/services/surfaceflinger/TunnelModeEnabledReporter.cpp b/services/surfaceflinger/TunnelModeEnabledReporter.cpp index 48e321635b..4497cafa58 100644 --- a/services/surfaceflinger/TunnelModeEnabledReporter.cpp +++ b/services/surfaceflinger/TunnelModeEnabledReporter.cpp @@ -26,17 +26,10 @@ namespace android { -TunnelModeEnabledReporter::TunnelModeEnabledReporter(SurfaceFlinger& flinger) : mFlinger(flinger) {} +TunnelModeEnabledReporter::TunnelModeEnabledReporter() {} void TunnelModeEnabledReporter::updateTunnelModeStatus() { - bool tunnelModeEnabled = false; - mFlinger.mCurrentState.traverse([&](Layer* layer) { - auto& state = layer->getDrawingState(); - if (state.sidebandStream != nullptr) { - tunnelModeEnabled = true; - return; - } - }); + bool tunnelModeEnabled = mTunnelModeCount > 0; dispatchTunnelModeEnabled(tunnelModeEnabled); } diff --git a/services/surfaceflinger/TunnelModeEnabledReporter.h b/services/surfaceflinger/TunnelModeEnabledReporter.h index d55507a8e9..935502a6e1 100644 --- a/services/surfaceflinger/TunnelModeEnabledReporter.h +++ b/services/surfaceflinger/TunnelModeEnabledReporter.h @@ -29,7 +29,7 @@ class SurfaceFlinger; class TunnelModeEnabledReporter : public IBinder::DeathRecipient { public: - TunnelModeEnabledReporter(SurfaceFlinger& flinger); + TunnelModeEnabledReporter(); // Checks if there is a tunnel mode enabled state change and if so, dispatches the updated // tunnel mode enabled/disabled state to the registered listeners @@ -49,6 +49,9 @@ public: // Deregisters a TunnelModeEnabled listener void removeListener(const sp<gui::ITunnelModeEnabledListener>& listener); + inline void incrementTunnelModeCount() { mTunnelModeCount++; } + inline void decrementTunnelModeCount() { mTunnelModeCount--; } + private: mutable std::mutex mMutex; struct WpHash { @@ -57,10 +60,10 @@ private: } }; - SurfaceFlinger& mFlinger; std::unordered_map<wp<IBinder>, sp<gui::ITunnelModeEnabledListener>, WpHash> mListeners GUARDED_BY(mMutex); bool mTunnelModeEnabled GUARDED_BY(mMutex) = false; + uint32_t mTunnelModeCount = 0; }; } // namespace android diff --git a/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp b/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp index d7d7ea77d6..e4f74694f7 100644 --- a/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp +++ b/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp @@ -27,6 +27,7 @@ #include "TunnelModeEnabledReporter.h" #include "mock/DisplayHardware/MockComposer.h" #include "mock/MockEventThread.h" +#include "mock/MockMessageQueue.h" namespace android { @@ -71,15 +72,20 @@ protected: sp<TestableTunnelModeEnabledListener> mTunnelModeEnabledListener = new TestableTunnelModeEnabledListener(); sp<TunnelModeEnabledReporter> mTunnelModeEnabledReporter = - new TunnelModeEnabledReporter(*(mFlinger.flinger())); + new TunnelModeEnabledReporter(); + + mock::MessageQueue* mMessageQueue = new mock::MessageQueue(); }; TunnelModeEnabledReporterTest::TunnelModeEnabledReporterTest() { const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); + + mFlinger.mutableEventQueue().reset(mMessageQueue); setupScheduler(); mFlinger.setupComposer(std::make_unique<Hwc2::mock::Composer>()); + mFlinger.flinger()->mTunnelModeEnabledReporter = mTunnelModeEnabledReporter; mTunnelModeEnabledReporter->dispatchTunnelModeEnabled(false); } @@ -156,16 +162,18 @@ TEST_F(TunnelModeEnabledReporterTest, callsNewListenerWithFreshInformation) { sp<NativeHandle> stream = NativeHandle::create(reinterpret_cast<native_handle_t*>(DEFAULT_SIDEBAND_STREAM), false); - mFlinger.setLayerSidebandStream(layer, stream); + layer->setSidebandStream(stream); mFlinger.mutableCurrentState().layersSortedByZ.add(layer); mTunnelModeEnabledReporter->updateTunnelModeStatus(); mTunnelModeEnabledReporter->addListener(mTunnelModeEnabledListener); EXPECT_EQ(true, mTunnelModeEnabledListener->mTunnelModeEnabled); mTunnelModeEnabledReporter->removeListener(mTunnelModeEnabledListener); - mFlinger.mutableCurrentState().layersSortedByZ.remove(layer); + layer = nullptr; + mTunnelModeEnabledReporter->updateTunnelModeStatus(); mTunnelModeEnabledReporter->addListener(mTunnelModeEnabledListener); + EXPECT_EQ(false, mTunnelModeEnabledListener->mTunnelModeEnabled); } @@ -178,7 +186,7 @@ TEST_F(TunnelModeEnabledReporterTest, layerWithSidebandStreamTriggersUpdate) { sp<NativeHandle> stream = NativeHandle::create(reinterpret_cast<native_handle_t*>(DEFAULT_SIDEBAND_STREAM), false); - mFlinger.setLayerSidebandStream(layerWithSidebandStream, stream); + layerWithSidebandStream->setSidebandStream(stream); mFlinger.mutableCurrentState().layersSortedByZ.add(simpleLayer); mFlinger.mutableCurrentState().layersSortedByZ.add(layerWithSidebandStream); @@ -186,6 +194,7 @@ TEST_F(TunnelModeEnabledReporterTest, layerWithSidebandStreamTriggersUpdate) { EXPECT_EQ(true, mTunnelModeEnabledListener->mTunnelModeEnabled); mFlinger.mutableCurrentState().layersSortedByZ.remove(layerWithSidebandStream); + layerWithSidebandStream = nullptr; mTunnelModeEnabledReporter->updateTunnelModeStatus(); EXPECT_EQ(false, mTunnelModeEnabledListener->mTunnelModeEnabled); } diff --git a/services/vibratorservice/VibratorHalWrapper.cpp b/services/vibratorservice/VibratorHalWrapper.cpp index f15a963e44..a375808ce4 100644 --- a/services/vibratorservice/VibratorHalWrapper.cpp +++ b/services/vibratorservice/VibratorHalWrapper.cpp @@ -135,6 +135,18 @@ Info HalWrapper::getInfo() { if (mInfoCache.mSupportedBraking.isFailed()) { mInfoCache.mSupportedBraking = getSupportedBrakingInternal(); } + if (mInfoCache.mPrimitiveDelayMax.isFailed()) { + mInfoCache.mPrimitiveDelayMax = getPrimitiveDelayMaxInternal(); + } + if (mInfoCache.mPwlePrimitiveDurationMax.isFailed()) { + mInfoCache.mPwlePrimitiveDurationMax = getPrimitiveDurationMaxInternal(); + } + if (mInfoCache.mCompositionSizeMax.isFailed()) { + mInfoCache.mCompositionSizeMax = getCompositionSizeMaxInternal(); + } + if (mInfoCache.mPwleSizeMax.isFailed()) { + mInfoCache.mPwleSizeMax = getPwleSizeMaxInternal(); + } if (mInfoCache.mMinFrequency.isFailed()) { mInfoCache.mMinFrequency = getMinFrequencyInternal(); } @@ -209,6 +221,26 @@ HalResult<std::vector<milliseconds>> HalWrapper::getPrimitiveDurationsInternal( return HalResult<std::vector<milliseconds>>::unsupported(); } +HalResult<milliseconds> HalWrapper::getPrimitiveDelayMaxInternal() { + ALOGV("Skipped getPrimitiveDelayMaxInternal because it's not available in Vibrator HAL"); + return HalResult<milliseconds>::unsupported(); +} + +HalResult<milliseconds> HalWrapper::getPrimitiveDurationMaxInternal() { + ALOGV("Skipped getPrimitiveDurationMaxInternal because it's not available in Vibrator HAL"); + return HalResult<milliseconds>::unsupported(); +} + +HalResult<int32_t> HalWrapper::getCompositionSizeMaxInternal() { + ALOGV("Skipped getCompositionSizeMaxInternal because it's not available in Vibrator HAL"); + return HalResult<int32_t>::unsupported(); +} + +HalResult<int32_t> HalWrapper::getPwleSizeMaxInternal() { + ALOGV("Skipped getPwleSizeMaxInternal because it's not available in Vibrator HAL"); + return HalResult<int32_t>::unsupported(); +} + HalResult<float> HalWrapper::getMinFrequencyInternal() { ALOGV("Skipped getMinFrequency because it's not available in Vibrator HAL"); return HalResult<float>::unsupported(); @@ -383,6 +415,30 @@ HalResult<std::vector<milliseconds>> AidlHalWrapper::getPrimitiveDurationsIntern return HalResult<std::vector<milliseconds>>::ok(durations); } +HalResult<milliseconds> AidlHalWrapper::getPrimitiveDelayMaxInternal() { + int32_t delay = 0; + auto result = getHal()->getCompositionDelayMax(&delay); + return HalResult<milliseconds>::fromStatus(result, milliseconds(delay)); +} + +HalResult<milliseconds> AidlHalWrapper::getPrimitiveDurationMaxInternal() { + int32_t delay = 0; + auto result = getHal()->getPwlePrimitiveDurationMax(&delay); + return HalResult<milliseconds>::fromStatus(result, milliseconds(delay)); +} + +HalResult<int32_t> AidlHalWrapper::getCompositionSizeMaxInternal() { + int32_t size = 0; + auto result = getHal()->getCompositionSizeMax(&size); + return HalResult<int32_t>::fromStatus(result, size); +} + +HalResult<int32_t> AidlHalWrapper::getPwleSizeMaxInternal() { + int32_t size = 0; + auto result = getHal()->getPwleCompositionSizeMax(&size); + return HalResult<int32_t>::fromStatus(result, size); +} + HalResult<float> AidlHalWrapper::getMinFrequencyInternal() { float minFrequency = 0; auto result = getHal()->getFrequencyMinimum(&minFrequency); diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h index 87bc34e62a..68d6647ede 100644 --- a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h +++ b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h @@ -182,6 +182,10 @@ public: const HalResult<std::vector<hardware::vibrator::Braking>> supportedBraking; const HalResult<std::vector<hardware::vibrator::CompositePrimitive>> supportedPrimitives; const HalResult<std::vector<std::chrono::milliseconds>> primitiveDurations; + const HalResult<std::chrono::milliseconds> primitiveDelayMax; + const HalResult<std::chrono::milliseconds> pwlePrimitiveDurationMax; + const HalResult<int32_t> compositionSizeMax; + const HalResult<int32_t> pwleSizeMax; const HalResult<float> minFrequency; const HalResult<float> resonantFrequency; const HalResult<float> frequencyResolution; @@ -194,6 +198,10 @@ public: supportedBraking.checkAndLogFailure("getSupportedBraking") || supportedPrimitives.checkAndLogFailure("getSupportedPrimitives") || primitiveDurations.checkAndLogFailure("getPrimitiveDuration") || + primitiveDelayMax.checkAndLogFailure("getPrimitiveDelayMax") || + pwlePrimitiveDurationMax.checkAndLogFailure("getPwlePrimitiveDurationMax") || + compositionSizeMax.checkAndLogFailure("getCompositionSizeMax") || + pwleSizeMax.checkAndLogFailure("getPwleSizeMax") || minFrequency.checkAndLogFailure("getMinFrequency") || resonantFrequency.checkAndLogFailure("getResonantFrequency") || frequencyResolution.checkAndLogFailure("getFrequencyResolution") || @@ -205,9 +213,19 @@ public: class InfoCache { public: Info get() { - return {mCapabilities, mSupportedEffects, mSupportedBraking, - mSupportedPrimitives, mPrimitiveDurations, mMinFrequency, - mResonantFrequency, mFrequencyResolution, mQFactor, + return {mCapabilities, + mSupportedEffects, + mSupportedBraking, + mSupportedPrimitives, + mPrimitiveDurations, + mPrimitiveDelayMax, + mPwlePrimitiveDurationMax, + mCompositionSizeMax, + mPwleSizeMax, + mMinFrequency, + mResonantFrequency, + mFrequencyResolution, + mQFactor, mMaxAmplitudes}; } @@ -222,6 +240,12 @@ private: HalResult<std::vector<hardware::vibrator::CompositePrimitive>>::failed(MSG); HalResult<std::vector<std::chrono::milliseconds>> mPrimitiveDurations = HalResult<std::vector<std::chrono::milliseconds>>::failed(MSG); + HalResult<std::chrono::milliseconds> mPrimitiveDelayMax = + HalResult<std::chrono::milliseconds>::failed(MSG); + HalResult<std::chrono::milliseconds> mPwlePrimitiveDurationMax = + HalResult<std::chrono::milliseconds>::failed(MSG); + HalResult<int32_t> mCompositionSizeMax = HalResult<int>::failed(MSG); + HalResult<int32_t> mPwleSizeMax = HalResult<int>::failed(MSG); HalResult<float> mMinFrequency = HalResult<float>::failed(MSG); HalResult<float> mResonantFrequency = HalResult<float>::failed(MSG); HalResult<float> mFrequencyResolution = HalResult<float>::failed(MSG); @@ -285,6 +309,10 @@ protected: getSupportedPrimitivesInternal(); virtual HalResult<std::vector<std::chrono::milliseconds>> getPrimitiveDurationsInternal( const std::vector<hardware::vibrator::CompositePrimitive>& supportedPrimitives); + virtual HalResult<std::chrono::milliseconds> getPrimitiveDelayMaxInternal(); + virtual HalResult<std::chrono::milliseconds> getPrimitiveDurationMaxInternal(); + virtual HalResult<int32_t> getCompositionSizeMaxInternal(); + virtual HalResult<int32_t> getPwleSizeMaxInternal(); virtual HalResult<float> getMinFrequencyInternal(); virtual HalResult<float> getResonantFrequencyInternal(); virtual HalResult<float> getFrequencyResolutionInternal(); @@ -347,6 +375,10 @@ protected: HalResult<std::vector<std::chrono::milliseconds>> getPrimitiveDurationsInternal( const std::vector<hardware::vibrator::CompositePrimitive>& supportedPrimitives) override final; + HalResult<std::chrono::milliseconds> getPrimitiveDelayMaxInternal() override final; + HalResult<std::chrono::milliseconds> getPrimitiveDurationMaxInternal() override final; + HalResult<int32_t> getCompositionSizeMaxInternal() override final; + HalResult<int32_t> getPwleSizeMaxInternal() override final; HalResult<float> getMinFrequencyInternal() override final; HalResult<float> getResonantFrequencyInternal() override final; HalResult<float> getFrequencyResolutionInternal() override final; diff --git a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp index 78133031f6..03c9e77f3e 100644 --- a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp +++ b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp @@ -301,6 +301,10 @@ TEST_F(VibratorHalWrapperAidlTest, TestGetInfoDoesNotCacheFailedResult) { constexpr float F0 = 123.f; constexpr float F_RESOLUTION = 0.5f; constexpr float Q_FACTOR = 123.f; + constexpr int32_t COMPOSITION_SIZE_MAX = 10; + constexpr int32_t PWLE_SIZE_MAX = 20; + constexpr int32_t PRIMITIVE_DELAY_MAX = 100; + constexpr int32_t PWLE_DURATION_MAX = 200; std::vector<Effect> supportedEffects = {Effect::CLICK, Effect::TICK}; std::vector<CompositePrimitive> supportedPrimitives = {CompositePrimitive::CLICK}; std::vector<Braking> supportedBraking = {Braking::CLAB}; @@ -331,6 +335,22 @@ TEST_F(VibratorHalWrapperAidlTest, TestGetInfoDoesNotCacheFailedResult) { EXPECT_CALL(*mMockHal.get(), getPrimitiveDuration(Eq(CompositePrimitive::CLICK), _)) .Times(Exactly(1)) .WillRepeatedly(DoAll(SetArgPointee<1>(10), Return(Status()))); + EXPECT_CALL(*mMockHal.get(), getCompositionSizeMax(_)) + .Times(Exactly(2)) + .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY))) + .WillRepeatedly(DoAll(SetArgPointee<0>(COMPOSITION_SIZE_MAX), Return(Status()))); + EXPECT_CALL(*mMockHal.get(), getCompositionDelayMax(_)) + .Times(Exactly(2)) + .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY))) + .WillRepeatedly(DoAll(SetArgPointee<0>(PRIMITIVE_DELAY_MAX), Return(Status()))); + EXPECT_CALL(*mMockHal.get(), getPwlePrimitiveDurationMax(_)) + .Times(Exactly(2)) + .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY))) + .WillRepeatedly(DoAll(SetArgPointee<0>(PWLE_DURATION_MAX), Return(Status()))); + EXPECT_CALL(*mMockHal.get(), getPwleCompositionSizeMax(_)) + .Times(Exactly(2)) + .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY))) + .WillRepeatedly(DoAll(SetArgPointee<0>(PWLE_SIZE_MAX), Return(Status()))); EXPECT_CALL(*mMockHal.get(), getFrequencyMinimum(_)) .Times(Exactly(2)) .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY))) @@ -358,6 +378,10 @@ TEST_F(VibratorHalWrapperAidlTest, TestGetInfoDoesNotCacheFailedResult) { ASSERT_TRUE(failed.supportedBraking.isFailed()); ASSERT_TRUE(failed.supportedPrimitives.isFailed()); ASSERT_TRUE(failed.primitiveDurations.isFailed()); + ASSERT_TRUE(failed.primitiveDelayMax.isFailed()); + ASSERT_TRUE(failed.pwlePrimitiveDurationMax.isFailed()); + ASSERT_TRUE(failed.compositionSizeMax.isFailed()); + ASSERT_TRUE(failed.pwleSizeMax.isFailed()); ASSERT_TRUE(failed.minFrequency.isFailed()); ASSERT_TRUE(failed.resonantFrequency.isFailed()); ASSERT_TRUE(failed.frequencyResolution.isFailed()); @@ -370,6 +394,11 @@ TEST_F(VibratorHalWrapperAidlTest, TestGetInfoDoesNotCacheFailedResult) { ASSERT_EQ(supportedBraking, successful.supportedBraking.value()); ASSERT_EQ(supportedPrimitives, successful.supportedPrimitives.value()); ASSERT_EQ(primitiveDurations, successful.primitiveDurations.value()); + ASSERT_EQ(std::chrono::milliseconds(PRIMITIVE_DELAY_MAX), successful.primitiveDelayMax.value()); + ASSERT_EQ(std::chrono::milliseconds(PWLE_DURATION_MAX), + successful.pwlePrimitiveDurationMax.value()); + ASSERT_EQ(COMPOSITION_SIZE_MAX, successful.compositionSizeMax.value()); + ASSERT_EQ(PWLE_SIZE_MAX, successful.pwleSizeMax.value()); ASSERT_EQ(F_MIN, successful.minFrequency.value()); ASSERT_EQ(F0, successful.resonantFrequency.value()); ASSERT_EQ(F_RESOLUTION, successful.frequencyResolution.value()); @@ -380,6 +409,10 @@ TEST_F(VibratorHalWrapperAidlTest, TestGetInfoDoesNotCacheFailedResult) { TEST_F(VibratorHalWrapperAidlTest, TestGetInfoCachesResult) { constexpr float F_MIN = 100.f; constexpr float F0 = 123.f; + constexpr int32_t COMPOSITION_SIZE_MAX = 10; + constexpr int32_t PWLE_SIZE_MAX = 20; + constexpr int32_t PRIMITIVE_DELAY_MAX = 100; + constexpr int32_t PWLE_DURATION_MAX = 200; std::vector<Effect> supportedEffects = {Effect::CLICK, Effect::TICK}; EXPECT_CALL(*mMockHal.get(), getCapabilities(_)) @@ -395,6 +428,18 @@ TEST_F(VibratorHalWrapperAidlTest, TestGetInfoCachesResult) { EXPECT_CALL(*mMockHal.get(), getSupportedPrimitives(_)) .Times(Exactly(1)) .WillRepeatedly(Return(Status::fromStatusT(UNKNOWN_TRANSACTION))); + EXPECT_CALL(*mMockHal.get(), getCompositionSizeMax(_)) + .Times(Exactly(1)) + .WillRepeatedly(DoAll(SetArgPointee<0>(COMPOSITION_SIZE_MAX), Return(Status()))); + EXPECT_CALL(*mMockHal.get(), getCompositionDelayMax(_)) + .Times(Exactly(1)) + .WillRepeatedly(DoAll(SetArgPointee<0>(PRIMITIVE_DELAY_MAX), Return(Status()))); + EXPECT_CALL(*mMockHal.get(), getPwlePrimitiveDurationMax(_)) + .Times(Exactly(1)) + .WillRepeatedly(DoAll(SetArgPointee<0>(PWLE_DURATION_MAX), Return(Status()))); + EXPECT_CALL(*mMockHal.get(), getPwleCompositionSizeMax(_)) + .Times(Exactly(1)) + .WillRepeatedly(DoAll(SetArgPointee<0>(PWLE_SIZE_MAX), Return(Status()))); EXPECT_CALL(*mMockHal.get(), getFrequencyMinimum(_)) .Times(Exactly(1)) .WillRepeatedly(DoAll(SetArgPointee<0>(F_MIN), Return(Status()))); @@ -426,6 +471,10 @@ TEST_F(VibratorHalWrapperAidlTest, TestGetInfoCachesResult) { ASSERT_TRUE(info.supportedBraking.isUnsupported()); ASSERT_TRUE(info.supportedPrimitives.isUnsupported()); ASSERT_TRUE(info.primitiveDurations.isUnsupported()); + ASSERT_EQ(std::chrono::milliseconds(PRIMITIVE_DELAY_MAX), info.primitiveDelayMax.value()); + ASSERT_EQ(std::chrono::milliseconds(PWLE_DURATION_MAX), info.pwlePrimitiveDurationMax.value()); + ASSERT_EQ(COMPOSITION_SIZE_MAX, info.compositionSizeMax.value()); + ASSERT_EQ(PWLE_SIZE_MAX, info.pwleSizeMax.value()); ASSERT_EQ(F_MIN, info.minFrequency.value()); ASSERT_EQ(F0, info.resonantFrequency.value()); ASSERT_TRUE(info.frequencyResolution.isUnsupported()); diff --git a/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp b/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp index 96b2582f90..0c27fc73b1 100644 --- a/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp +++ b/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp @@ -206,6 +206,10 @@ TEST_F(VibratorHalWrapperHidlV1_0Test, TestGetInfoDoesNotCacheFailedResult) { ASSERT_TRUE(info.supportedBraking.isUnsupported()); ASSERT_TRUE(info.supportedPrimitives.isUnsupported()); ASSERT_TRUE(info.primitiveDurations.isUnsupported()); + ASSERT_TRUE(info.primitiveDelayMax.isUnsupported()); + ASSERT_TRUE(info.pwlePrimitiveDurationMax.isUnsupported()); + ASSERT_TRUE(info.compositionSizeMax.isUnsupported()); + ASSERT_TRUE(info.pwleSizeMax.isUnsupported()); ASSERT_TRUE(info.minFrequency.isUnsupported()); ASSERT_TRUE(info.resonantFrequency.isUnsupported()); ASSERT_TRUE(info.frequencyResolution.isUnsupported()); |