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/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