Add SF side tunnel mode listener
This CL adds a TunnelModeStateReporter, which monitors if there are
any layers with a sideband stream in SurfaceFlinger. If any of the
layers have a sideband stream, it informs all the registered listeners
that tunnel mode is enabled. When no layers have a sideband stream, it
notifies the listeners that tunnel mode is disabled.
Bug: 171457637
Test: atest TunnelModeStateListenerTest
Test: atest TunnelModeStateReporterTest
Change-Id: Ie54b34dbd9b6253d7142e9b0f690c8469374604d
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 53721cf..71e18a9 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -824,6 +824,36 @@
return error;
}
+ virtual status_t addTunnelModeEnabledListener(
+ const sp<gui::ITunnelModeEnabledListener>& listener) {
+ Parcel data, reply;
+ SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
+ SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener));
+
+ const status_t error =
+ remote()->transact(BnSurfaceComposer::ADD_TUNNEL_MODE_ENABLED_LISTENER, data,
+ &reply);
+ if (error != NO_ERROR) {
+ ALOGE("addTunnelModeEnabledListener: Failed to transact");
+ }
+ return error;
+ }
+
+ virtual status_t removeTunnelModeEnabledListener(
+ const sp<gui::ITunnelModeEnabledListener>& listener) {
+ Parcel data, reply;
+ SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
+ SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener));
+
+ const status_t error =
+ remote()->transact(BnSurfaceComposer::REMOVE_TUNNEL_MODE_ENABLED_LISTENER, data,
+ &reply);
+ if (error != NO_ERROR) {
+ ALOGE("removeTunnelModeEnabledListener: Failed to transact");
+ }
+ return error;
+ }
+
status_t setDesiredDisplayModeSpecs(const sp<IBinder>& displayToken,
ui::DisplayModeId defaultMode, bool allowGroupSwitching,
float primaryRefreshRateMin, float primaryRefreshRateMax,
@@ -1740,6 +1770,26 @@
}
return removeFpsListener(listener);
}
+ case ADD_TUNNEL_MODE_ENABLED_LISTENER: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<gui::ITunnelModeEnabledListener> listener;
+ status_t result = data.readNullableStrongBinder(&listener);
+ if (result != NO_ERROR) {
+ ALOGE("addTunnelModeEnabledListener: Failed to read listener");
+ return result;
+ }
+ return addTunnelModeEnabledListener(listener);
+ }
+ case REMOVE_TUNNEL_MODE_ENABLED_LISTENER: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<gui::ITunnelModeEnabledListener> listener;
+ status_t result = data.readNullableStrongBinder(&listener);
+ if (result != NO_ERROR) {
+ ALOGE("removeTunnelModeEnabledListener: Failed to read listener");
+ return result;
+ }
+ return removeTunnelModeEnabledListener(listener);
+ }
case SET_DESIRED_DISPLAY_MODE_SPECS: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> displayToken = data.readStrongBinder();
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index aa93808..80ff653 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -2077,6 +2077,16 @@
return ComposerService::getComposerService()->removeFpsListener(listener);
}
+status_t SurfaceComposerClient::addTunnelModeEnabledListener(
+ const sp<gui::ITunnelModeEnabledListener>& listener) {
+ return ComposerService::getComposerService()->addTunnelModeEnabledListener(listener);
+}
+
+status_t SurfaceComposerClient::removeTunnelModeEnabledListener(
+ const sp<gui::ITunnelModeEnabledListener>& listener) {
+ return ComposerService::getComposerService()->removeTunnelModeEnabledListener(listener);
+}
+
bool SurfaceComposerClient::getDisplayBrightnessSupport(const sp<IBinder>& displayToken) {
bool support = false;
ComposerService::getComposerService()->getDisplayBrightnessSupport(displayToken, &support);
diff --git a/libs/gui/aidl/android/gui/ITunnelModeEnabledListener.aidl b/libs/gui/aidl/android/gui/ITunnelModeEnabledListener.aidl
new file mode 100644
index 0000000..2a89cca
--- /dev/null
+++ b/libs/gui/aidl/android/gui/ITunnelModeEnabledListener.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2021 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 */
+oneway interface ITunnelModeEnabledListener {
+
+ /**
+ * Called when tunnel mode status has changed. Tunnel mode is:
+ * - enabled when there is a sideband stream attached to one of the layers in
+ * surface flinger
+ * - disabled when there is no layer with a sideband stream
+ */
+ void onTunnelModeEnabledChanged(boolean enabled);
+}
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index cb04689..439d90a 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -21,6 +21,7 @@
#include <android/gui/IHdrLayerInfoListener.h>
#include <android/gui/IScreenCaptureListener.h>
#include <android/gui/ITransactionTraceListener.h>
+#include <android/gui/ITunnelModeEnabledListener.h>
#include <binder/IBinder.h>
#include <binder/IInterface.h>
#include <gui/FrameTimelineInfo.h>
@@ -377,6 +378,21 @@
*/
virtual status_t removeFpsListener(const sp<gui::IFpsListener>& listener) = 0;
+ /* Registers a listener to receive tunnel mode enabled updates from SurfaceFlinger.
+ *
+ * Requires ACCESS_SURFACE_FLINGER permission.
+ */
+ virtual status_t addTunnelModeEnabledListener(
+ const sp<gui::ITunnelModeEnabledListener>& listener) = 0;
+
+ /*
+ * Removes a listener that was receiving tunnel mode enabled updates from SurfaceFlinger.
+ *
+ * Requires ACCESS_SURFACE_FLINGER permission.
+ */
+ virtual status_t removeTunnelModeEnabledListener(
+ const sp<gui::ITunnelModeEnabledListener>& listener) = 0;
+
/* Sets the refresh rate boundaries for the display.
*
* The primary refresh rate range represents display manager's general guidance on the display
@@ -607,6 +623,8 @@
ADD_HDR_LAYER_INFO_LISTENER,
REMOVE_HDR_LAYER_INFO_LISTENER,
ON_PULL_ATOM,
+ ADD_TUNNEL_MODE_ENABLED_LISTENER,
+ REMOVE_TUNNEL_MODE_ENABLED_LISTENER,
// Always append new enum to the end.
};
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 0940e9d..2582882 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -50,6 +50,7 @@
class ISurfaceComposerClient;
class IGraphicBufferProducer;
class IRegionSamplingListener;
+class ITunnelModeEnabledListener;
class Region;
struct SurfaceControlStats {
@@ -610,6 +611,10 @@
static status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener);
static status_t addFpsListener(int32_t taskId, const sp<gui::IFpsListener>& listener);
static status_t removeFpsListener(const sp<gui::IFpsListener>& listener);
+ static status_t addTunnelModeEnabledListener(
+ const sp<gui::ITunnelModeEnabledListener>& listener);
+ static status_t removeTunnelModeEnabledListener(
+ const sp<gui::ITunnelModeEnabledListener>& listener);
private:
virtual void onFirstRef();
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index ea8c295..b8d34c3 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -845,6 +845,16 @@
return NO_ERROR;
}
status_t removeFpsListener(const sp<gui::IFpsListener>& /*listener*/) { return NO_ERROR; }
+
+ status_t addTunnelModeEnabledListener(const sp<gui::ITunnelModeEnabledListener>& /*listener*/) {
+ return NO_ERROR;
+ }
+
+ status_t removeTunnelModeEnabledListener(
+ const sp<gui::ITunnelModeEnabledListener>& /*listener*/) {
+ return NO_ERROR;
+ }
+
status_t setDesiredDisplayModeSpecs(const sp<IBinder>& /*displayToken*/,
ui::DisplayModeId /*defaultMode*/,
bool /*allowGroupSwitching*/,
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index f20bfe1..e669e45 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -188,6 +188,7 @@
"SurfaceInterceptor.cpp",
"SurfaceTracing.cpp",
"TransactionCallbackInvoker.cpp",
+ "TunnelModeEnabledReporter.cpp",
],
}
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 0e222ab..881ee5b 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -130,6 +130,7 @@
#include "SurfaceFlingerProperties.h"
#include "SurfaceInterceptor.h"
#include "TimeStats/TimeStats.h"
+#include "TunnelModeEnabledReporter.h"
#include "android-base/parseint.h"
#include "android-base/stringprintf.h"
#include "android-base/strings.h"
@@ -1468,6 +1469,26 @@
return NO_ERROR;
}
+status_t SurfaceFlinger::addTunnelModeEnabledListener(
+ const sp<gui::ITunnelModeEnabledListener>& listener) {
+ if (!listener) {
+ return BAD_VALUE;
+ }
+
+ mTunnelModeEnabledReporter->addListener(listener);
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::removeTunnelModeEnabledListener(
+ const sp<gui::ITunnelModeEnabledListener>& listener) {
+ if (!listener) {
+ return BAD_VALUE;
+ }
+
+ mTunnelModeEnabledReporter->removeListener(listener);
+ return NO_ERROR;
+}
+
status_t SurfaceFlinger::getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
bool* outSupport) const {
if (!displayToken || !outSupport) {
@@ -2191,6 +2212,10 @@
if (mFpsReporter) {
mFpsReporter->dispatchLayerFps();
}
+
+ if (mTunnelModeEnabledReporter) {
+ mTunnelModeEnabledReporter->updateTunnelModeStatus();
+ }
hdrInfoListeners.reserve(mHdrLayerInfoListeners.size());
for (auto& [key, value] : mHdrLayerInfoListeners) {
if (value && value->hasListeners()) {
@@ -3067,6 +3092,7 @@
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.
@@ -5072,6 +5098,8 @@
case GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES:
case SET_DISPLAY_CONTENT_SAMPLING_ENABLED:
case GET_DISPLAYED_CONTENT_SAMPLE:
+ case ADD_TUNNEL_MODE_ENABLED_LISTENER:
+ case REMOVE_TUNNEL_MODE_ENABLED_LISTENER:
case NOTIFY_POWER_BOOST:
case SET_GLOBAL_SHADOW_SETTINGS:
case ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN: {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index cb8d312..c382005 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -90,6 +90,7 @@
class Client;
class EventThread;
class FpsReporter;
+class TunnelModeEnabledReporter;
class HdrLayerInfoReporter;
class HWComposer;
struct SetInputWindowsListener;
@@ -359,6 +360,7 @@
friend class BufferStateLayer;
friend class Client;
friend class FpsReporter;
+ friend class TunnelModeEnabledReporter;
friend class Layer;
friend class MonitoredProducer;
friend class RefreshRateOverlay;
@@ -673,6 +675,10 @@
status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) override;
status_t addFpsListener(int32_t taskId, const sp<gui::IFpsListener>& listener) override;
status_t removeFpsListener(const sp<gui::IFpsListener>& listener) override;
+ status_t addTunnelModeEnabledListener(
+ const sp<gui::ITunnelModeEnabledListener>& listener) override;
+ status_t removeTunnelModeEnabledListener(
+ const sp<gui::ITunnelModeEnabledListener>& listener) override;
status_t setDesiredDisplayModeSpecs(const sp<IBinder>& displayToken,
ui::DisplayModeId displayModeId, bool allowGroupSwitching,
float primaryRefreshRateMin, float primaryRefreshRateMax,
@@ -1368,6 +1374,7 @@
bool mLumaSampling = true;
sp<RegionSamplingThread> mRegionSamplingThread;
sp<FpsReporter> mFpsReporter;
+ sp<TunnelModeEnabledReporter> mTunnelModeEnabledReporter;
ui::DisplayPrimaries mInternalDisplayPrimaries;
const float mInternalDisplayDensity;
diff --git a/services/surfaceflinger/TunnelModeEnabledReporter.cpp b/services/surfaceflinger/TunnelModeEnabledReporter.cpp
new file mode 100644
index 0000000..1b3ddf7
--- /dev/null
+++ b/services/surfaceflinger/TunnelModeEnabledReporter.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2021 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "TunnelModeEnabledReporter"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include <algorithm>
+
+#include "Layer.h"
+#include "SurfaceFlinger.h"
+#include "TunnelModeEnabledReporter.h"
+
+namespace android {
+
+TunnelModeEnabledReporter::TunnelModeEnabledReporter(SurfaceFlinger& flinger) : mFlinger(flinger) {}
+
+void TunnelModeEnabledReporter::updateTunnelModeStatus() {
+ bool tunnelModeEnabled = false;
+ mFlinger.mCurrentState.traverse([&](Layer* layer) {
+ auto& currentState = layer->getCurrentState();
+ if (currentState.sidebandStream != nullptr) {
+ tunnelModeEnabled = true;
+ return;
+ }
+ });
+ dispatchTunnelModeEnabled(tunnelModeEnabled);
+}
+
+void TunnelModeEnabledReporter::dispatchTunnelModeEnabled(bool tunnelModeEnabled) {
+ std::vector<sp<gui::ITunnelModeEnabledListener>> localListeners;
+ {
+ std::scoped_lock lock(mMutex);
+ if (mTunnelModeEnabled == tunnelModeEnabled) {
+ return;
+ }
+ mTunnelModeEnabled = tunnelModeEnabled;
+
+ std::transform(mListeners.begin(), mListeners.end(), std::back_inserter(localListeners),
+ [](const std::pair<wp<IBinder>, sp<gui::ITunnelModeEnabledListener>>&
+ entry) { return entry.second; });
+ }
+
+ for (sp<gui::ITunnelModeEnabledListener>& listener : localListeners) {
+ listener->onTunnelModeEnabledChanged(tunnelModeEnabled);
+ }
+}
+
+void TunnelModeEnabledReporter::binderDied(const wp<IBinder>& who) {
+ std::scoped_lock lock(mMutex);
+ mListeners.erase(who);
+}
+
+void TunnelModeEnabledReporter::addListener(const sp<gui::ITunnelModeEnabledListener>& listener) {
+ sp<IBinder> asBinder = IInterface::asBinder(listener);
+ asBinder->linkToDeath(this);
+ bool tunnelModeEnabled = false;
+ {
+ std::scoped_lock lock(mMutex);
+ mListeners.emplace(wp<IBinder>(asBinder), listener);
+ tunnelModeEnabled = mTunnelModeEnabled;
+ }
+ listener->onTunnelModeEnabledChanged(tunnelModeEnabled);
+}
+
+void TunnelModeEnabledReporter::removeListener(
+ const sp<gui::ITunnelModeEnabledListener>& listener) {
+ std::lock_guard lock(mMutex);
+ mListeners.erase(wp<IBinder>(IInterface::asBinder(listener)));
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/TunnelModeEnabledReporter.h b/services/surfaceflinger/TunnelModeEnabledReporter.h
new file mode 100644
index 0000000..d55507a
--- /dev/null
+++ b/services/surfaceflinger/TunnelModeEnabledReporter.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2021 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.
+ */
+
+#pragma once
+
+#include <android-base/thread_annotations.h>
+#include <android/gui/ITunnelModeEnabledListener.h>
+#include <binder/IBinder.h>
+
+#include <unordered_map>
+
+namespace android {
+
+class Layer;
+class SurfaceFlinger;
+
+class TunnelModeEnabledReporter : public IBinder::DeathRecipient {
+public:
+ TunnelModeEnabledReporter(SurfaceFlinger& flinger);
+
+ // 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
+ // This method performs layer stack traversals, so mStateLock must be held when calling this
+ // method.
+ void updateTunnelModeStatus();
+
+ // Dispatches tunnelModeEnabled to all registered listeners
+ void dispatchTunnelModeEnabled(bool tunnelModeEnabled);
+
+ // Override for IBinder::DeathRecipient
+ void binderDied(const wp<IBinder>&) override;
+
+ // Registers a TunnelModeEnabled listener
+ void addListener(const sp<gui::ITunnelModeEnabledListener>& listener);
+
+ // Deregisters a TunnelModeEnabled listener
+ void removeListener(const sp<gui::ITunnelModeEnabledListener>& listener);
+
+private:
+ mutable std::mutex mMutex;
+ struct WpHash {
+ size_t operator()(const wp<IBinder>& p) const {
+ return std::hash<IBinder*>()(p.unsafe_get());
+ }
+ };
+
+ SurfaceFlinger& mFlinger;
+ std::unordered_map<wp<IBinder>, sp<gui::ITunnelModeEnabledListener>, WpHash> mListeners
+ GUARDED_BY(mMutex);
+ bool mTunnelModeEnabled GUARDED_BY(mMutex) = false;
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index b33434e..1b25a36 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -86,6 +86,7 @@
"TransactionApplicationTest.cpp",
"TransactionFrameTracerTest.cpp",
"TransactionSurfaceFrameTest.cpp",
+ "TunnelModeEnabledReporterTest.cpp",
"StrongTypingTest.cpp",
"VSyncDispatchTimerQueueTest.cpp",
"VSyncDispatchRealtimeTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index d004b9d..a551248 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -276,6 +276,7 @@
static void setLayerSidebandStream(const sp<Layer>& layer,
const sp<NativeHandle>& sidebandStream) {
layer->mDrawingState.sidebandStream = sidebandStream;
+ layer->mCurrentState.sidebandStream = sidebandStream;
layer->mSidebandStream = sidebandStream;
layer->editCompositionState()->sidebandStream = sidebandStream;
}
diff --git a/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp b/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp
new file mode 100644
index 0000000..d7d7ea7
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2021 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "TunnelModeEnabledReporterTest"
+
+#include <android/gui/BnTunnelModeEnabledListener.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <gui/LayerMetadata.h>
+
+#include "BufferStateLayer.h"
+#include "TestableSurfaceFlinger.h"
+#include "TunnelModeEnabledReporter.h"
+#include "mock/DisplayHardware/MockComposer.h"
+#include "mock/MockEventThread.h"
+
+namespace android {
+
+using testing::_;
+using testing::Mock;
+using testing::Return;
+
+using android::Hwc2::IComposer;
+using android::Hwc2::IComposerClient;
+
+using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
+
+constexpr int DEFAULT_SIDEBAND_STREAM = 51;
+
+struct TestableTunnelModeEnabledListener : public gui::BnTunnelModeEnabledListener {
+ TestableTunnelModeEnabledListener() {}
+
+ bool mTunnelModeEnabled = false;
+
+ binder::Status onTunnelModeEnabledChanged(bool tunnelModeEnabled) override {
+ mTunnelModeEnabled = tunnelModeEnabled;
+ return binder::Status::ok();
+ }
+};
+
+class TunnelModeEnabledReporterTest : public testing::Test {
+public:
+ TunnelModeEnabledReporterTest();
+ ~TunnelModeEnabledReporterTest() override;
+
+protected:
+ static constexpr uint32_t WIDTH = 100;
+ static constexpr uint32_t HEIGHT = 100;
+ static constexpr uint32_t LAYER_FLAGS = 0;
+
+ void setupScheduler();
+ void setupComposer(uint32_t virtualDisplayCount);
+ sp<BufferStateLayer> createBufferStateLayer(LayerMetadata metadata);
+
+ TestableSurfaceFlinger mFlinger;
+ Hwc2::mock::Composer* mComposer = nullptr;
+ sp<TestableTunnelModeEnabledListener> mTunnelModeEnabledListener =
+ new TestableTunnelModeEnabledListener();
+ sp<TunnelModeEnabledReporter> mTunnelModeEnabledReporter =
+ new TunnelModeEnabledReporter(*(mFlinger.flinger()));
+};
+
+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());
+ setupScheduler();
+ mFlinger.setupComposer(std::make_unique<Hwc2::mock::Composer>());
+ mTunnelModeEnabledReporter->dispatchTunnelModeEnabled(false);
+}
+
+TunnelModeEnabledReporterTest::~TunnelModeEnabledReporterTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+ mTunnelModeEnabledReporter->dispatchTunnelModeEnabled(false);
+ mTunnelModeEnabledReporter->removeListener(mTunnelModeEnabledListener);
+}
+
+sp<BufferStateLayer> TunnelModeEnabledReporterTest::createBufferStateLayer(
+ LayerMetadata metadata = {}) {
+ sp<Client> client;
+ LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", WIDTH, HEIGHT,
+ LAYER_FLAGS, metadata);
+ return new BufferStateLayer(args);
+}
+
+void TunnelModeEnabledReporterTest::setupScheduler() {
+ auto eventThread = std::make_unique<mock::EventThread>();
+ auto sfEventThread = std::make_unique<mock::EventThread>();
+
+ EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
+ EXPECT_CALL(*eventThread, createEventConnection(_, _))
+ .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0,
+ ResyncCallback())));
+
+ EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
+ EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
+ .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0,
+ ResyncCallback())));
+
+ auto vsyncController = std::make_unique<mock::VsyncController>();
+ auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
+
+ EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
+ EXPECT_CALL(*vsyncTracker, currentPeriod())
+ .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
+ EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
+ mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker),
+ std::move(eventThread), std::move(sfEventThread));
+}
+
+namespace {
+
+TEST_F(TunnelModeEnabledReporterTest, callsAddedListeners) {
+ mTunnelModeEnabledReporter->addListener(mTunnelModeEnabledListener);
+
+ bool expectedTunnelModeEnabled = false;
+ mTunnelModeEnabledReporter->dispatchTunnelModeEnabled(expectedTunnelModeEnabled);
+ EXPECT_EQ(expectedTunnelModeEnabled, mTunnelModeEnabledListener->mTunnelModeEnabled);
+
+ expectedTunnelModeEnabled = true;
+ mTunnelModeEnabledReporter->dispatchTunnelModeEnabled(expectedTunnelModeEnabled);
+ EXPECT_EQ(expectedTunnelModeEnabled, mTunnelModeEnabledListener->mTunnelModeEnabled);
+
+ mTunnelModeEnabledReporter->removeListener(mTunnelModeEnabledListener);
+
+ mTunnelModeEnabledReporter->dispatchTunnelModeEnabled(false);
+ EXPECT_EQ(expectedTunnelModeEnabled, mTunnelModeEnabledListener->mTunnelModeEnabled);
+}
+
+TEST_F(TunnelModeEnabledReporterTest, callsNewListenerImmediately) {
+ bool expectedTunnelModeEnabled = false;
+ mTunnelModeEnabledReporter->dispatchTunnelModeEnabled(expectedTunnelModeEnabled);
+
+ mTunnelModeEnabledReporter->addListener(mTunnelModeEnabledListener);
+ EXPECT_EQ(expectedTunnelModeEnabled, mTunnelModeEnabledListener->mTunnelModeEnabled);
+}
+
+TEST_F(TunnelModeEnabledReporterTest, callsNewListenerWithFreshInformation) {
+ sp<Layer> layer = createBufferStateLayer();
+ sp<NativeHandle> stream =
+ NativeHandle::create(reinterpret_cast<native_handle_t*>(DEFAULT_SIDEBAND_STREAM),
+ false);
+ mFlinger.setLayerSidebandStream(layer, stream);
+ mFlinger.mutableCurrentState().layersSortedByZ.add(layer);
+ mTunnelModeEnabledReporter->updateTunnelModeStatus();
+ mTunnelModeEnabledReporter->addListener(mTunnelModeEnabledListener);
+ EXPECT_EQ(true, mTunnelModeEnabledListener->mTunnelModeEnabled);
+ mTunnelModeEnabledReporter->removeListener(mTunnelModeEnabledListener);
+
+ mFlinger.mutableCurrentState().layersSortedByZ.remove(layer);
+ mTunnelModeEnabledReporter->updateTunnelModeStatus();
+ mTunnelModeEnabledReporter->addListener(mTunnelModeEnabledListener);
+ EXPECT_EQ(false, mTunnelModeEnabledListener->mTunnelModeEnabled);
+}
+
+TEST_F(TunnelModeEnabledReporterTest, layerWithSidebandStreamTriggersUpdate) {
+ mTunnelModeEnabledReporter->addListener(mTunnelModeEnabledListener);
+ EXPECT_EQ(false, mTunnelModeEnabledListener->mTunnelModeEnabled);
+
+ sp<Layer> simpleLayer = createBufferStateLayer();
+ sp<Layer> layerWithSidebandStream = createBufferStateLayer();
+ sp<NativeHandle> stream =
+ NativeHandle::create(reinterpret_cast<native_handle_t*>(DEFAULT_SIDEBAND_STREAM),
+ false);
+ mFlinger.setLayerSidebandStream(layerWithSidebandStream, stream);
+
+ mFlinger.mutableCurrentState().layersSortedByZ.add(simpleLayer);
+ mFlinger.mutableCurrentState().layersSortedByZ.add(layerWithSidebandStream);
+ mTunnelModeEnabledReporter->updateTunnelModeStatus();
+ EXPECT_EQ(true, mTunnelModeEnabledListener->mTunnelModeEnabled);
+
+ mFlinger.mutableCurrentState().layersSortedByZ.remove(layerWithSidebandStream);
+ mTunnelModeEnabledReporter->updateTunnelModeStatus();
+ EXPECT_EQ(false, mTunnelModeEnabledListener->mTunnelModeEnabled);
+}
+
+} // namespace
+} // namespace android