SF: Add utility class for dumpsys formatting
The Dumper class automates stringifying (a minimal set of types for now)
and indenting.
Bug: 241285876
Test: dumpsys SurfaceFlinger --displays
Change-Id: I5581cd9cb4235e2c710e303b6ab634847554cc30
diff --git a/services/surfaceflinger/Display/DisplaySnapshot.cpp b/services/surfaceflinger/Display/DisplaySnapshot.cpp
index b4f104a..fca3a3d 100644
--- a/services/surfaceflinger/Display/DisplaySnapshot.cpp
+++ b/services/surfaceflinger/Display/DisplaySnapshot.cpp
@@ -41,18 +41,11 @@
.transform(&ftl::to_key<DisplayModes>);
}
-void DisplaySnapshot::dump(std::string& out) const {
- using namespace std::string_literals;
+void DisplaySnapshot::dump(utils::Dumper& dumper) const {
+ using namespace std::string_view_literals;
- out += " connectionType="s;
- out += ftl::enum_string(mConnectionType);
-
- out += "\n deviceProductInfo="s;
- if (mDeviceProductInfo) {
- mDeviceProductInfo->dump(out);
- } else {
- out += "{}"s;
- }
+ dumper.dump("connectionType"sv, ftl::enum_string(mConnectionType));
+ dumper.dump("deviceProductInfo"sv, mDeviceProductInfo);
}
} // namespace android::display
diff --git a/services/surfaceflinger/Display/DisplaySnapshot.h b/services/surfaceflinger/Display/DisplaySnapshot.h
index 0279220..3f34e39 100644
--- a/services/surfaceflinger/Display/DisplaySnapshot.h
+++ b/services/surfaceflinger/Display/DisplaySnapshot.h
@@ -17,12 +17,12 @@
#pragma once
#include <optional>
-#include <string>
#include <ui/DisplayId.h>
#include <ui/StaticDisplayInfo.h>
-#include "../DisplayHardware/DisplayMode.h"
+#include "DisplayHardware/DisplayMode.h"
+#include "Utils/Dumper.h"
namespace android::display {
@@ -43,7 +43,7 @@
const auto& displayModes() const { return mDisplayModes; }
const auto& deviceProductInfo() const { return mDeviceProductInfo; }
- void dump(std::string&) const;
+ void dump(utils::Dumper&) const;
private:
const PhysicalDisplayId mDisplayId;
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index a25296c..eeab0cd 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -338,17 +338,16 @@
return name + ", \""s + mDisplayName + "\")"s;
}
-void DisplayDevice::dump(std::string& result) const {
- using namespace std::string_literals;
+void DisplayDevice::dump(utils::Dumper& dumper) const {
+ using namespace std::string_view_literals;
- result += getDebugName();
+ dumper.dump({}, getDebugName());
- result += "\n powerMode="s;
- result += mPowerMode.has_value() ? to_string(mPowerMode.value()) : "OFF(reset)";
- result += '\n';
+ utils::Dumper::Indent indent(dumper);
+ dumper.dump("powerMode"sv, mPowerMode);
if (mRefreshRateConfigs) {
- mRefreshRateConfigs->dump(result);
+ mRefreshRateConfigs->dump(dumper);
}
}
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 0f52aff..1de8147 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -47,6 +47,7 @@
#include "Scheduler/RefreshRateConfigs.h"
#include "ThreadContext.h"
#include "TracedOrdinal.h"
+#include "Utils/Dumper.h"
namespace android {
@@ -248,7 +249,7 @@
* Debugging
*/
std::string getDebugName() const;
- void dump(std::string& result) const;
+ void dump(utils::Dumper&) const;
private:
const sp<SurfaceFlinger> mFlinger;
diff --git a/services/surfaceflinger/DisplayHardware/Hal.h b/services/surfaceflinger/DisplayHardware/Hal.h
index 4737034..33a7bca 100644
--- a/services/surfaceflinger/DisplayHardware/Hal.h
+++ b/services/surfaceflinger/DisplayHardware/Hal.h
@@ -177,6 +177,9 @@
return to_string(static_cast<hardware::graphics::composer::hal::V2_4::Error>(error));
}
+// For utils::Dumper ADL.
+namespace hardware::graphics::composer::V2_2 {
+
inline std::string to_string(hardware::graphics::composer::hal::PowerMode mode) {
switch (mode) {
case hardware::graphics::composer::hal::PowerMode::OFF:
@@ -194,6 +197,8 @@
}
}
+} // namespace hardware::graphics::composer::V2_2
+
inline std::string to_string(hardware::graphics::composer::hal::Vsync vsync) {
switch (vsync) {
case hardware::graphics::composer::hal::Vsync::ENABLE:
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 3cb052c..fb50588 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -1037,47 +1037,45 @@
isApproxEqual(bigger, Fps::fromValue(smaller.getValue() * multiplier * kCoef));
}
-void RefreshRateConfigs::dump(std::string& result) const {
- using namespace std::string_literals;
+void RefreshRateConfigs::dump(utils::Dumper& dumper) const {
+ using namespace std::string_view_literals;
std::lock_guard lock(mLock);
const auto activeModeId = getActiveModeItLocked()->first;
- result += " activeModeId="s;
- result += std::to_string(activeModeId.value());
+ dumper.dump("activeModeId"sv, std::to_string(activeModeId.value()));
- result += "\n displayModes=\n"s;
- for (const auto& [id, mode] : mDisplayModes) {
- result += " "s;
- result += to_string(*mode);
- result += '\n';
+ dumper.dump("displayModes"sv);
+ {
+ utils::Dumper::Indent indent(dumper);
+ for (const auto& [id, mode] : mDisplayModes) {
+ dumper.dump({}, to_string(*mode));
+ }
}
- base::StringAppendF(&result, " displayManagerPolicy=%s\n",
- mDisplayManagerPolicy.toString().c_str());
+ dumper.dump("displayManagerPolicy"sv, mDisplayManagerPolicy.toString());
if (const Policy& currentPolicy = *getCurrentPolicyLocked();
mOverridePolicy && currentPolicy != mDisplayManagerPolicy) {
- base::StringAppendF(&result, " overridePolicy=%s\n", currentPolicy.toString().c_str());
+ dumper.dump("overridePolicy"sv, currentPolicy.toString());
}
- base::StringAppendF(&result, " supportsFrameRateOverrideByContent=%s\n",
- mSupportsFrameRateOverrideByContent ? "true" : "false");
+ dumper.dump("supportsFrameRateOverrideByContent"sv, mSupportsFrameRateOverrideByContent);
- result += " idleTimer="s;
+ std::string idleTimer;
if (mIdleTimer) {
- result += mIdleTimer->dump();
+ idleTimer = mIdleTimer->dump();
} else {
- result += "off"s;
+ idleTimer = "off"sv;
}
if (const auto controller = mConfig.kernelIdleTimerController) {
- base::StringAppendF(&result, " (kernel via %s)", ftl::enum_string(*controller).c_str());
+ base::StringAppendF(&idleTimer, " (kernel via %s)", ftl::enum_string(*controller).c_str());
} else {
- result += " (platform)"s;
+ idleTimer += " (platform)"sv;
}
- result += '\n';
+ dumper.dump("idleTimer"sv, idleTimer);
}
std::chrono::milliseconds RefreshRateConfigs::getIdleTimerTimeout() {
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 0642fcb..8b89104 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -32,6 +32,7 @@
#include "Scheduler/OneShotTimer.h"
#include "Scheduler/StrongTyping.h"
#include "ThreadContext.h"
+#include "Utils/Dumper.h"
namespace android::scheduler {
@@ -336,7 +337,7 @@
mIdleTimer->reset();
}
- void dump(std::string& result) const EXCLUDES(mLock);
+ void dump(utils::Dumper&) const EXCLUDES(mLock);
std::chrono::milliseconds getIdleTimerTimeout();
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index f3551ae..896eebf 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -142,6 +142,7 @@
#include "SurfaceInterceptor.h"
#include "TimeStats/TimeStats.h"
#include "TunnelModeEnabledReporter.h"
+#include "Utils/Dumper.h"
#include "WindowInfosListenerInvoker.h"
#include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h>
@@ -5077,18 +5078,22 @@
}
void SurfaceFlinger::dumpDisplays(std::string& result) const {
+ utils::Dumper dumper{result};
+
for (const auto& [id, display] : mPhysicalDisplays) {
if (const auto device = getDisplayDeviceLocked(id)) {
- device->dump(result);
+ device->dump(dumper);
}
- display.snapshot().dump(result);
- result += '\n';
+
+ utils::Dumper::Indent indent(dumper);
+ display.snapshot().dump(dumper);
+ dumper.eol();
}
for (const auto& [token, display] : mDisplays) {
if (display->isVirtual()) {
- display->dump(result);
- result += '\n';
+ display->dump(dumper);
+ dumper.eol();
}
}
}
diff --git a/services/surfaceflinger/Utils/Dumper.h b/services/surfaceflinger/Utils/Dumper.h
new file mode 100644
index 0000000..3761f9e
--- /dev/null
+++ b/services/surfaceflinger/Utils/Dumper.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2022 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 <optional>
+#include <string>
+#include <string_view>
+
+namespace android::utils {
+
+// Dumps variables by appending their name and value to the output string. A variable is formatted
+// as "name=value". If the name or value is empty, the format is "value" or "name=", respectively.
+// A value of user-defined type T is stringified via `std::string to_string(const T&)`, which must
+// be defined in the same namespace as T per the rules of ADL (argument-dependent lookup).
+//
+// TODO(b/249828573): Consolidate with <compositionengine/impl/DumpHelpers.h>
+class Dumper {
+public:
+ explicit Dumper(std::string& out) : mOut(out) {}
+
+ void eol() { mOut += '\n'; }
+
+ void dump(std::string_view name, std::string_view value = {}) {
+ using namespace std::string_view_literals;
+
+ for (int i = mIndent; i-- > 0;) mOut += " "sv;
+ mOut += name;
+ if (!name.empty()) mOut += '=';
+ mOut += value;
+ eol();
+ }
+
+ void dump(std::string_view name, bool value) {
+ using namespace std::string_view_literals;
+ dump(name, value ? "true"sv : "false"sv);
+ }
+
+ template <typename T>
+ void dump(std::string_view name, const std::optional<T>& value) {
+ using namespace std::string_view_literals;
+ using std::to_string;
+ dump(name, value ? to_string(*value) : "nullopt"sv);
+ }
+
+ struct Indent {
+ explicit Indent(Dumper& dumper) : dumper(dumper) { dumper.mIndent++; }
+ ~Indent() { dumper.mIndent--; }
+
+ Dumper& dumper;
+ };
+
+private:
+ std::string& mOut;
+ int mIndent = 0;
+};
+
+} // namespace android::utils