Merge changes from topic "cherrypicker-L15700000962481002:N29300001395174087" into udc-qpr-dev
* changes:
Use a single otapreopt_chroot invocation for all otapreopt runs.
Remove 1s sleep between each package in the A/B OTA postinstall dexopt process.
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 3c8df2b..b9a8fb6 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -62,6 +62,7 @@
name: "guiconstants_aidl",
srcs: [
"android/gui/DropInputMode.aidl",
+ "android/gui/StalledTransactionInfo.aidl",
"android/**/TouchOcclusionMode.aidl",
],
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 48a97b2..180ed09 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -59,7 +59,7 @@
#include <private/gui/ComposerServiceAIDL.h>
// This server size should always be smaller than the server cache size
-#define BUFFER_CACHE_MAX_SIZE 64
+#define BUFFER_CACHE_MAX_SIZE 4096
namespace android {
@@ -1302,6 +1302,13 @@
return status.isOk() ? display : nullptr;
}
+std::optional<gui::StalledTransactionInfo> SurfaceComposerClient::getStalledTransactionInfo(
+ pid_t pid) {
+ std::optional<gui::StalledTransactionInfo> result;
+ ComposerServiceAIDL::getComposerService()->getStalledTransactionInfo(pid, &result);
+ return result;
+}
+
void SurfaceComposerClient::Transaction::setAnimationTransaction() {
mAnimation = true;
}
diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
index 539a1c1..7e652ac 100644
--- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
+++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
@@ -46,6 +46,7 @@
import android.gui.OverlayProperties;
import android.gui.PullAtomData;
import android.gui.ARect;
+import android.gui.StalledTransactionInfo;
import android.gui.StaticDisplayInfo;
import android.gui.WindowInfosListenerInfo;
@@ -507,4 +508,10 @@
void removeWindowInfosListener(IWindowInfosListener windowInfosListener);
OverlayProperties getOverlaySupport();
+
+ /**
+ * Returns an instance of StalledTransaction if a transaction from the passed pid has not been
+ * applied in SurfaceFlinger due to an unsignaled fence. Otherwise, null is returned.
+ */
+ @nullable StalledTransactionInfo getStalledTransactionInfo(int pid);
}
diff --git a/libs/gui/android/gui/StalledTransactionInfo.aidl b/libs/gui/android/gui/StalledTransactionInfo.aidl
new file mode 100644
index 0000000..e6aa9bd
--- /dev/null
+++ b/libs/gui/android/gui/StalledTransactionInfo.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.gui;
+
+/** @hide */
+parcelable StalledTransactionInfo {
+ String layerName;
+ long bufferId;
+ long frameNumber;
+}
\ No newline at end of file
diff --git a/libs/gui/fuzzer/libgui_fuzzer_utils.h b/libs/gui/fuzzer/libgui_fuzzer_utils.h
index 4c7d056..c70197c 100644
--- a/libs/gui/fuzzer/libgui_fuzzer_utils.h
+++ b/libs/gui/fuzzer/libgui_fuzzer_utils.h
@@ -158,6 +158,8 @@
MOCK_METHOD(binder::Status, removeWindowInfosListener, (const sp<gui::IWindowInfosListener>&),
(override));
MOCK_METHOD(binder::Status, getOverlaySupport, (gui::OverlayProperties*), (override));
+ MOCK_METHOD(binder::Status, getStalledTransactionInfo,
+ (int32_t, std::optional<gui::StalledTransactionInfo>*), (override));
};
class FakeBnSurfaceComposerClient : public gui::BnSurfaceComposerClient {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 3cf57b1..dbcbd3b 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -371,6 +371,10 @@
//! Get token for a physical display given its stable ID
static sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId);
+ // Returns StalledTransactionInfo if a transaction from the provided pid has not been applied
+ // due to an unsignaled fence.
+ static std::optional<gui::StalledTransactionInfo> getStalledTransactionInfo(pid_t pid);
+
struct SCHash {
std::size_t operator()(const sp<SurfaceControl>& sc) const {
return std::hash<SurfaceControl *>{}(sc.get());
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 567604d..d7910d2 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -1016,6 +1016,11 @@
return binder::Status::ok();
}
+ binder::Status getStalledTransactionInfo(
+ int32_t /*pid*/, std::optional<gui::StalledTransactionInfo>* /*result*/) override {
+ return binder::Status::ok();
+ }
+
protected:
IBinder* onAsBinder() override { return nullptr; }
diff --git a/libs/input/InputVerifier.cpp b/libs/input/InputVerifier.cpp
index 32b4ca0..9745e89 100644
--- a/libs/input/InputVerifier.cpp
+++ b/libs/input/InputVerifier.cpp
@@ -29,7 +29,7 @@
// --- InputVerifier ---
InputVerifier::InputVerifier(const std::string& name)
- : mVerifier(android::input::verifier::create(name)){};
+ : mVerifier(android::input::verifier::create(rust::String::lossy(name))){};
Result<void> InputVerifier::processMovement(int32_t deviceId, int32_t action, uint32_t pointerCount,
const PointerProperties* pointerProperties,
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index cadac88..86b996b 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -18,6 +18,7 @@
"InputDevice_test.cpp",
"InputEvent_test.cpp",
"InputPublisherAndConsumer_test.cpp",
+ "InputVerifier_test.cpp",
"MotionPredictor_test.cpp",
"RingBuffer_test.cpp",
"TfLiteMotionPredictor_test.cpp",
diff --git a/libs/input/tests/InputVerifier_test.cpp b/libs/input/tests/InputVerifier_test.cpp
new file mode 100644
index 0000000..e24fa6e
--- /dev/null
+++ b/libs/input/tests/InputVerifier_test.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <input/InputVerifier.h>
+#include <string>
+
+namespace android {
+
+TEST(InputVerifierTest, CreationWithInvalidUtfStringDoesNotCrash) {
+ constexpr char bytes[] = {static_cast<char>(0xC0), static_cast<char>(0x80)};
+ const std::string name(bytes, sizeof(bytes));
+ InputVerifier verifier(name);
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/ClientCache.h b/services/surfaceflinger/ClientCache.h
index b56b252..fefc040 100644
--- a/services/surfaceflinger/ClientCache.h
+++ b/services/surfaceflinger/ClientCache.h
@@ -29,7 +29,9 @@
#include <set>
#include <unordered_map>
-#define BUFFER_CACHE_MAX_SIZE 64
+// 4096 is based on 64 buffers * 64 layers. Once this limit is reached, the least recently used
+// buffer is uncached before the new buffer is cached.
+#define BUFFER_CACHE_MAX_SIZE 4096
namespace android {
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index b021dd1..195d90c 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -213,10 +213,7 @@
ATRACE_INT(mRenderFrameRateFPSTrace.c_str(), renderFps.getIntValue());
mRefreshRateSelector->setActiveMode(modeId, renderFps);
-
- if (mRefreshRateOverlay) {
- mRefreshRateOverlay->changeRefreshRate(displayFps, renderFps);
- }
+ updateRefreshRateOverlayRate(displayFps, renderFps);
}
status_t DisplayDevice::initiateModeChange(const ActiveModeInfo& info,
@@ -446,7 +443,7 @@
mRefreshRateOverlay = std::make_unique<RefreshRateOverlay>(fpsRange, features);
mRefreshRateOverlay->setLayerStack(getLayerStack());
mRefreshRateOverlay->setViewport(getSize());
- updateRefreshRateOverlayRate(getActiveMode().modePtr->getFps(), getActiveMode().fps);
+ updateRefreshRateOverlayRate(getActiveMode().modePtr->getFps(), getActiveMode().fps, setByHwc);
}
void DisplayDevice::updateRefreshRateOverlayRate(Fps displayFps, Fps renderFps, bool setByHwc) {
diff --git a/services/surfaceflinger/FrontEnd/TransactionHandler.cpp b/services/surfaceflinger/FrontEnd/TransactionHandler.cpp
index fa8eb3c..6e78e93 100644
--- a/services/surfaceflinger/FrontEnd/TransactionHandler.cpp
+++ b/services/surfaceflinger/FrontEnd/TransactionHandler.cpp
@@ -186,21 +186,36 @@
}
void TransactionHandler::onTransactionQueueStalled(uint64_t transactionId,
- sp<ITransactionCompletedListener>& listener,
- const std::string& reason) {
- if (std::find(mStalledTransactions.begin(), mStalledTransactions.end(), transactionId) !=
- mStalledTransactions.end()) {
- return;
- }
-
- mStalledTransactions.push_back(transactionId);
- listener->onTransactionQueueStalled(String8(reason.c_str()));
+ StalledTransactionInfo stalledTransactionInfo) {
+ std::lock_guard lock{mStalledMutex};
+ mStalledTransactions.emplace(transactionId, std::move(stalledTransactionInfo));
}
-void TransactionHandler::removeFromStalledTransactions(uint64_t id) {
- auto it = std::find(mStalledTransactions.begin(), mStalledTransactions.end(), id);
- if (it != mStalledTransactions.end()) {
- mStalledTransactions.erase(it);
+void TransactionHandler::removeFromStalledTransactions(uint64_t transactionId) {
+ std::lock_guard lock{mStalledMutex};
+ mStalledTransactions.erase(transactionId);
+}
+
+std::optional<TransactionHandler::StalledTransactionInfo>
+TransactionHandler::getStalledTransactionInfo(pid_t pid) {
+ std::lock_guard lock{mStalledMutex};
+ for (auto [_, stalledTransactionInfo] : mStalledTransactions) {
+ if (pid == stalledTransactionInfo.pid) {
+ return stalledTransactionInfo;
+ }
+ }
+ return std::nullopt;
+}
+
+void TransactionHandler::onLayerDestroyed(uint32_t layerId) {
+ std::lock_guard lock{mStalledMutex};
+ for (auto it = mStalledTransactions.begin(); it != mStalledTransactions.end();) {
+ if (it->second.layerId == layerId) {
+ it = mStalledTransactions.erase(it);
+ } else {
+ it++;
+ }
}
}
+
} // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/FrontEnd/TransactionHandler.h b/services/surfaceflinger/FrontEnd/TransactionHandler.h
index 865835f..ff54dc5 100644
--- a/services/surfaceflinger/FrontEnd/TransactionHandler.h
+++ b/services/surfaceflinger/FrontEnd/TransactionHandler.h
@@ -18,6 +18,7 @@
#include <semaphore.h>
#include <cstdint>
+#include <optional>
#include <vector>
#include <LocklessQueue.h>
@@ -61,9 +62,18 @@
std::vector<TransactionState> flushTransactions();
void addTransactionReadyFilter(TransactionFilter&&);
void queueTransaction(TransactionState&&);
- void onTransactionQueueStalled(uint64_t transactionId, sp<ITransactionCompletedListener>&,
- const std::string& reason);
+
+ struct StalledTransactionInfo {
+ pid_t pid;
+ uint32_t layerId;
+ std::string layerName;
+ uint64_t bufferId;
+ uint64_t frameNumber;
+ };
+ void onTransactionQueueStalled(uint64_t transactionId, StalledTransactionInfo);
void removeFromStalledTransactions(uint64_t transactionId);
+ std::optional<StalledTransactionInfo> getStalledTransactionInfo(pid_t pid);
+ void onLayerDestroyed(uint32_t layerId);
private:
// For unit tests
@@ -79,7 +89,10 @@
LocklessQueue<TransactionState> mLocklessTransactionQueue;
std::atomic<size_t> mPendingTransactionCount = 0;
ftl::SmallVector<TransactionFilter, 2> mTransactionReadyFilters;
- std::vector<uint64_t> mStalledTransactions;
+
+ std::mutex mStalledMutex;
+ std::unordered_map<uint64_t /* transactionId */, StalledTransactionInfo> mStalledTransactions
+ GUARDED_BY(mStalledMutex);
};
} // namespace surfaceflinger::frontend
} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index dddc9b5..39ea248 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -4369,9 +4369,13 @@
(flushState.queueProcessTime - transaction.postTime) >
std::chrono::nanoseconds(4s).count()) {
mTransactionHandler
- .onTransactionQueueStalled(transaction.id, listener,
- "Buffer processing hung up due to stuck "
- "fence. Indicates GPU hang");
+ .onTransactionQueueStalled(transaction.id,
+ {.pid = layer->getOwnerPid(),
+ .layerId = static_cast<uint32_t>(
+ layer->getSequence()),
+ .layerName = layer->getDebugName(),
+ .bufferId = s.bufferData->getId(),
+ .frameNumber = s.bufferData->frameNumber});
}
ATRACE_FORMAT("fence unsignaled %s", layer->getDebugName());
return TraverseBuffersReturnValues::STOP_TRAVERSAL;
@@ -5395,6 +5399,8 @@
mDestroyedHandles.emplace_back(layerId);
}
+ mTransactionHandler.onLayerDestroyed(layerId);
+
Mutex::Autolock lock(mStateLock);
markLayerPendingRemovalLocked(layer);
layer->onHandleDestroyed();
@@ -5522,18 +5528,22 @@
// Turn off the display
if (displayId == mActiveDisplayId) {
- if (setSchedFifo(false) != NO_ERROR) {
- ALOGW("Failed to set SCHED_OTHER after powering off active display: %s",
- strerror(errno));
- }
- if (setSchedAttr(false) != NO_ERROR) {
- ALOGW("Failed set uclamp.min after powering off active display: %s",
- strerror(errno));
- }
+ if (const auto display = getActivatableDisplay()) {
+ onActiveDisplayChangedLocked(activeDisplay.get(), *display);
+ } else {
+ if (setSchedFifo(false) != NO_ERROR) {
+ ALOGW("Failed to set SCHED_OTHER after powering off active display: %s",
+ strerror(errno));
+ }
+ if (setSchedAttr(false) != NO_ERROR) {
+ ALOGW("Failed set uclamp.min after powering off active display: %s",
+ strerror(errno));
+ }
- if (*currentModeOpt != hal::PowerMode::DOZE_SUSPEND) {
- mScheduler->disableHardwareVsync(displayId, true);
- mScheduler->enableSyntheticVsync();
+ if (*currentModeOpt != hal::PowerMode::DOZE_SUSPEND) {
+ mScheduler->disableHardwareVsync(displayId, true);
+ mScheduler->enableSyntheticVsync();
+ }
}
}
@@ -7826,19 +7836,22 @@
bool setByHwc = getHwComposer().hasCapability(Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG);
for (const auto& [id, display] : mPhysicalDisplays) {
if (display.snapshot().connectionType() == ui::DisplayConnectionType::Internal) {
- if (setByHwc) {
- const auto status =
- getHwComposer().setRefreshRateChangedCallbackDebugEnabled(id, enable);
- if (status != NO_ERROR) {
- ALOGE("Error updating the refresh rate changed callback debug enabled");
- return;
- }
- }
-
if (const auto device = getDisplayDeviceLocked(id)) {
- device->enableRefreshRateOverlay(enable, setByHwc, mRefreshRateOverlaySpinner,
- mRefreshRateOverlayRenderRate,
- mRefreshRateOverlayShowInMiddle);
+ const auto enableOverlay = [&](const bool setByHwc) FTL_FAKE_GUARD(
+ kMainThreadContext) {
+ device->enableRefreshRateOverlay(enable, setByHwc, mRefreshRateOverlaySpinner,
+ mRefreshRateOverlayRenderRate,
+ mRefreshRateOverlayShowInMiddle);
+ };
+ enableOverlay(setByHwc);
+ if (setByHwc) {
+ const auto status =
+ getHwComposer().setRefreshRateChangedCallbackDebugEnabled(id, enable);
+ if (status != NO_ERROR) {
+ ALOGE("Error updating the refresh rate changed callback debug enabled");
+ enableOverlay(/*setByHwc*/ false);
+ }
+ }
}
}
}
@@ -7948,6 +7961,20 @@
getRenderEngine().onActiveDisplaySizeChanged(activeDisplay.getSize());
}
+sp<DisplayDevice> SurfaceFlinger::getActivatableDisplay() const {
+ if (mPhysicalDisplays.size() == 1) return nullptr;
+
+ // TODO(b/255635821): Choose the pacesetter display, considering both internal and external
+ // displays. For now, pick the other internal display, assuming a dual-display foldable.
+ return findDisplay([this](const DisplayDevice& display) REQUIRES(mStateLock) {
+ const auto idOpt = PhysicalDisplayId::tryCast(display.getId());
+ return idOpt && *idOpt != mActiveDisplayId && display.isPoweredOn() &&
+ mPhysicalDisplays.get(*idOpt)
+ .transform(&PhysicalDisplay::isInternal)
+ .value_or(false);
+ });
+}
+
void SurfaceFlinger::onActiveDisplayChangedLocked(const DisplayDevice* inactiveDisplayPtr,
const DisplayDevice& activeDisplay) {
ATRACE_CALL();
@@ -7996,6 +8023,12 @@
return NO_ERROR;
}
+status_t SurfaceFlinger::getStalledTransactionInfo(
+ int pid, std::optional<TransactionHandler::StalledTransactionInfo>& result) {
+ result = mTransactionHandler.getStalledTransactionInfo(pid);
+ return NO_ERROR;
+}
+
std::shared_ptr<renderengine::ExternalTexture> SurfaceFlinger::getExternalTextureFromBufferData(
BufferData& bufferData, const char* layerName, uint64_t transactionId) {
if (bufferData.buffer &&
@@ -9100,6 +9133,28 @@
return binderStatusFromStatusT(status);
}
+binder::Status SurfaceComposerAIDL::getStalledTransactionInfo(
+ int pid, std::optional<gui::StalledTransactionInfo>* outInfo) {
+ const int callingPid = IPCThreadState::self()->getCallingPid();
+ const int callingUid = IPCThreadState::self()->getCallingUid();
+ if (!checkPermission(sAccessSurfaceFlinger, callingPid, callingUid)) {
+ return binderStatusFromStatusT(PERMISSION_DENIED);
+ }
+
+ std::optional<TransactionHandler::StalledTransactionInfo> stalledTransactionInfo;
+ status_t status = mFlinger->getStalledTransactionInfo(pid, stalledTransactionInfo);
+ if (stalledTransactionInfo) {
+ gui::StalledTransactionInfo result;
+ result.layerName = String16{stalledTransactionInfo->layerName.c_str()},
+ result.bufferId = stalledTransactionInfo->bufferId,
+ result.frameNumber = stalledTransactionInfo->frameNumber,
+ outInfo->emplace(std::move(result));
+ } else {
+ outInfo->reset();
+ }
+ return binderStatusFromStatusT(status);
+}
+
status_t SurfaceComposerAIDL::checkAccessPermission(bool usePermissionCache) {
if (!mFlinger->callingThreadHasUnscopedSurfaceFlingerAccess(usePermissionCache)) {
IPCThreadState* ipc = IPCThreadState::self();
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index db1c342..e3e72ed 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -618,6 +618,9 @@
status_t removeWindowInfosListener(
const sp<gui::IWindowInfosListener>& windowInfosListener) const;
+ status_t getStalledTransactionInfo(
+ int pid, std::optional<TransactionHandler::StalledTransactionInfo>& result);
+
// Implements IBinder::DeathRecipient.
void binderDied(const wp<IBinder>& who) override;
@@ -934,7 +937,8 @@
template <typename Predicate>
sp<DisplayDevice> findDisplay(Predicate p) const REQUIRES(mStateLock) {
const auto it = std::find_if(mDisplays.begin(), mDisplays.end(),
- [&](const auto& pair) { return p(*pair.second); });
+ [&](const auto& pair)
+ REQUIRES(mStateLock) { return p(*pair.second); });
return it == mDisplays.end() ? nullptr : it->second;
}
@@ -1047,6 +1051,9 @@
VirtualDisplayId acquireVirtualDisplay(ui::Size, ui::PixelFormat) REQUIRES(mStateLock);
void releaseVirtualDisplay(VirtualDisplayId);
+ // Returns a display other than `mActiveDisplayId` that can be activated, if any.
+ sp<DisplayDevice> getActivatableDisplay() const REQUIRES(mStateLock, kMainThreadContext);
+
void onActiveDisplayChangedLocked(const DisplayDevice* inactiveDisplayPtr,
const DisplayDevice& activeDisplay)
REQUIRES(mStateLock, kMainThreadContext);
@@ -1541,6 +1548,8 @@
gui::WindowInfosListenerInfo* outInfo) override;
binder::Status removeWindowInfosListener(
const sp<gui::IWindowInfosListener>& windowInfosListener) override;
+ binder::Status getStalledTransactionInfo(int pid,
+ std::optional<gui::StalledTransactionInfo>* outInfo);
private:
static const constexpr bool kUsePermissionCache = true;
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_FoldableTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_FoldableTest.cpp
index bd2344c..ed8d909 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_FoldableTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_FoldableTest.cpp
@@ -55,13 +55,17 @@
sp<DisplayDevice> mInnerDisplay, mOuterDisplay;
};
-TEST_F(FoldableTest, foldUnfold) {
+TEST_F(FoldableTest, promotesPacesetterOnBoot) {
// When the device boots, the inner display should be the pacesetter.
ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId);
// ...and should still be after powering on.
mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId);
+}
+
+TEST_F(FoldableTest, promotesPacesetterOnFoldUnfold) {
+ mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
// The outer display should become the pacesetter after folding.
mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::OFF);
@@ -72,6 +76,10 @@
mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::OFF);
mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId);
+}
+
+TEST_F(FoldableTest, promotesPacesetterOnConcurrentPowerOn) {
+ mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
// The inner display should stay the pacesetter if both are powered on.
// TODO(b/255635821): The pacesetter should depend on the displays' refresh rates.
@@ -81,6 +89,28 @@
// The outer display should become the pacesetter if designated.
mFlinger.scheduler()->setPacesetterDisplay(kOuterDisplayId);
ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kOuterDisplayId);
+
+ // The inner display should become the pacesetter if designated.
+ mFlinger.scheduler()->setPacesetterDisplay(kInnerDisplayId);
+ ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId);
+}
+
+TEST_F(FoldableTest, promotesPacesetterOnConcurrentPowerOff) {
+ mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
+ mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::ON);
+
+ // The outer display should become the pacesetter if the inner display powers off.
+ mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::OFF);
+ ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kOuterDisplayId);
+
+ // The outer display should stay the pacesetter if both are powered on.
+ // TODO(b/255635821): The pacesetter should depend on the displays' refresh rates.
+ mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
+ ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kOuterDisplayId);
+
+ // The inner display should become the pacesetter if the outer display powers off.
+ mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::OFF);
+ ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId);
}
TEST_F(FoldableTest, doesNotRequestHardwareVsyncIfPoweredOff) {
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index d21deef..bdba27e 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -763,6 +763,17 @@
continue;
}
+ // Ignore duplicate extensions (see: b/288929054)
+ bool duplicate_entry = false;
+ for (uint32_t j = 0; j < filter.name_count; j++) {
+ if (strcmp(name, filter.names[j]) == 0) {
+ duplicate_entry = true;
+ break;
+ }
+ }
+ if (duplicate_entry == true)
+ continue;
+
filter.names[filter.name_count++] = name;
if (ext_bit != ProcHook::EXTENSION_UNKNOWN) {
if (ext_bit == ProcHook::ANDROID_native_buffer)