summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2021-06-23 02:24:07 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2021-06-23 02:24:07 +0000
commit135aa27ef577b31a642e61dec36f26446639b560 (patch)
treed06ae64defa48d15b8ffaeccefae305395803797
parent862f91b8767a200c202179837dd887bf2ac12aa3 (diff)
parentab3c8d659cf4319f2c0b9bf8f9e37cc4eaf8c729 (diff)
downloadnative-135aa27ef577b31a642e61dec36f26446639b560.tar.gz
Snap for 7483611 from ab3c8d659cf4319f2c0b9bf8f9e37cc4eaf8c729 to mainline-documentsui-releaseandroid-mainline-12.0.0_r26android-mainline-12.0.0_r2aml_doc_310851020android12-mainline-documentsui-release
Change-Id: I11ea8eefa1348d7b66569fd545aadb55a9cd494c
-rw-r--r--cmds/installd/run_dex2oat.cpp6
-rw-r--r--libs/gui/BLASTBufferQueue.cpp30
-rw-r--r--libs/gui/include/gui/BLASTBufferQueue.h1
-rw-r--r--libs/gui/include/gui/FrameTimestamps.h1
-rw-r--r--libs/gui/tests/BLASTBufferQueue_test.cpp91
-rw-r--r--services/inputflinger/dispatcher/FocusResolver.cpp5
-rw-r--r--services/inputflinger/dispatcher/FocusResolver.h3
-rw-r--r--services/inputflinger/dispatcher/InputDispatcher.cpp53
-rw-r--r--services/inputflinger/dispatcher/InputDispatcher.h5
-rw-r--r--services/inputflinger/dispatcher/include/InputDispatcherInterface.h5
-rw-r--r--services/inputflinger/tests/FocusResolver_test.cpp32
-rw-r--r--services/inputflinger/tests/InputDispatcher_test.cpp17
-rw-r--r--services/surfaceflinger/BufferStateLayer.cpp8
-rw-r--r--services/surfaceflinger/Layer.cpp25
-rw-r--r--services/surfaceflinger/Layer.h6
-rw-r--r--services/surfaceflinger/MonitoredProducer.cpp5
-rw-r--r--services/surfaceflinger/MonitoredProducer.h2
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp65
-rw-r--r--services/surfaceflinger/SurfaceFlinger.h9
-rw-r--r--services/surfaceflinger/TunnelModeEnabledReporter.cpp11
-rw-r--r--services/surfaceflinger/TunnelModeEnabledReporter.h7
-rw-r--r--services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp17
-rw-r--r--services/vibratorservice/VibratorHalWrapper.cpp56
-rw-r--r--services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h38
-rw-r--r--services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp49
-rw-r--r--services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp4
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());