1 // Copyright 2014 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef BASE_TRACE_EVENT_TRACED_VALUE_H_ 6 #define BASE_TRACE_EVENT_TRACED_VALUE_H_ 7 8 #include <stddef.h> 9 10 #include <memory> 11 #include <sstream> 12 #include <string> 13 #include <string_view> 14 #include <vector> 15 16 #include "base/base_export.h" 17 #include "base/memory/raw_ptr.h" 18 #include "base/memory/raw_ptr_exclusion.h" 19 #include "base/trace_event/trace_arguments.h" 20 21 namespace base { 22 23 class Value; 24 25 namespace trace_event { 26 27 class TraceEventMemoryOverhead; 28 29 class BASE_EXPORT TracedValue : public ConvertableToTraceFormat { 30 public: 31 // TODO(oysteine): |capacity| is not used in any production code. Consider 32 // removing it. 33 explicit TracedValue(size_t capacity = 0); 34 TracedValue(const TracedValue&) = delete; 35 TracedValue& operator=(const TracedValue&) = delete; 36 ~TracedValue() override; 37 38 void EndDictionary(); 39 void EndArray(); 40 41 // These methods assume that |name| is a long lived "quoted" string. 42 void SetInteger(const char* name, int value); 43 void SetDouble(const char* name, double value); 44 void SetBoolean(const char* name, bool value); 45 void SetString(const char* name, std::string_view value); 46 void SetValue(const char* name, TracedValue* value); 47 void SetPointer(const char* name, const void* value); 48 void BeginDictionary(const char* name); 49 void BeginArray(const char* name); 50 51 // These, instead, can be safely passed a temporary string. 52 void SetIntegerWithCopiedName(std::string_view name, int value); 53 void SetDoubleWithCopiedName(std::string_view name, double value); 54 void SetBooleanWithCopiedName(std::string_view name, bool value); 55 void SetStringWithCopiedName(std::string_view name, std::string_view value); 56 void SetValueWithCopiedName(std::string_view name, TracedValue* value); 57 void SetPointerWithCopiedName(std::string_view name, const void* value); 58 void BeginDictionaryWithCopiedName(std::string_view name); 59 void BeginArrayWithCopiedName(std::string_view name); 60 61 void AppendInteger(int); 62 void AppendDouble(double); 63 void AppendBoolean(bool); 64 void AppendString(std::string_view); 65 void AppendPointer(const void*); 66 void BeginArray(); 67 void BeginDictionary(); 68 69 // ConvertableToTraceFormat implementation. 70 void AppendAsTraceFormat(std::string* out) const override; 71 bool AppendToProto(ProtoAppender* appender) const override; 72 73 void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead) override; 74 75 // Helper to auto-close an array. The call to |ArrayScope::~ArrayScope| closes 76 // the array. 77 // 78 // To be constructed using: 79 // |TracedValue::AppendArrayScoped| 80 // |TracedValue::BeginArrayScoped| 81 // |TracedValue::BeginArrayScopedWithCopiedName| 82 // 83 // |ArrayScope| holds a |TracedValue| pointer which should remain a valid 84 // pointer until |ArrayScope::~ArrayScope| is called. 85 // 86 // |ArrayScope::~ArrayScope| calls |TracedValue::EndArray| (which checks if 87 // the held |TracedValue*| is in array state). 88 // 89 // Example: 90 // std::unique_ptr<TracedValue> value(new TracedValue()); 91 // { 92 // auto scope = value->BeginArrayScoped("array_name"); 93 // value->AppendBoolean(false); 94 // } 95 class BASE_EXPORT ArrayScope { 96 public: 97 ArrayScope(const ArrayScope&) = delete; 98 ArrayScope(ArrayScope&&) = default; 99 ArrayScope& operator=(const ArrayScope&) = delete; 100 ArrayScope& operator=(ArrayScope&&) = default; 101 ~ArrayScope(); 102 103 private: 104 explicit ArrayScope(TracedValue* value); 105 106 raw_ptr<TracedValue> value_; 107 108 friend class TracedValue; 109 }; 110 111 // Call |BeginArray| or |BeginArrayWithCopiedName| with no / the same 112 // parameter and return an |ArrayScope| holding |this|. 113 [[nodiscard]] ArrayScope AppendArrayScoped(); 114 [[nodiscard]] ArrayScope BeginArrayScoped(const char* name); 115 [[nodiscard]] ArrayScope BeginArrayScopedWithCopiedName( 116 std::string_view name); 117 118 // Helper to auto-close a dictionary. The call to 119 // |DictionaryScope::~DictionaryScope| closes the dictionary. 120 // 121 // To be constructed using: 122 // |TracedValue::AppendDictionaryScoped| 123 // |TracedValue::BeginDictionaryScoped| 124 // |TracedValue::BeginDictionaryScopedWithCopiedName| 125 // 126 // |DictionaryScope| holds a |TracedValue| pointer which should remain a valid 127 // pointer until |DictionaryScope::~DictionaryScope| is called. 128 // 129 // |DictionaryScope::~DictionaryScope| calls |TracedValue::EndDictionary| 130 // (which checks if the held |TracedValue*| is in dictionary state). 131 // 132 // Example: 133 // std::unique_ptr<TracedValue> value(new TracedValue()); 134 // { 135 // auto scope = value->BeginDictionaryScoped("dictionary_name"); 136 // value->SetBoolean("my_boolean", false); 137 // } 138 class BASE_EXPORT DictionaryScope { 139 public: 140 DictionaryScope(const DictionaryScope&) = delete; 141 DictionaryScope(DictionaryScope&&) = default; 142 DictionaryScope& operator=(const DictionaryScope&) = delete; 143 DictionaryScope& operator=(DictionaryScope&&) = default; 144 ~DictionaryScope(); 145 146 private: 147 explicit DictionaryScope(TracedValue* value); 148 149 raw_ptr<TracedValue> value_; 150 151 friend class TracedValue; 152 }; 153 154 // Call |BeginDictionary| or |BeginDictionaryWithCopiedName| with no / the 155 // same parameter and return a |DictionaryScope| holding |this|. 156 [[nodiscard]] DictionaryScope AppendDictionaryScoped(); 157 [[nodiscard]] DictionaryScope BeginDictionaryScoped(const char* name); 158 [[nodiscard]] DictionaryScope BeginDictionaryScopedWithCopiedName( 159 std::string_view name); 160 161 class BASE_EXPORT Array; 162 class BASE_EXPORT Dictionary; 163 class BASE_EXPORT ValueHolder; 164 class BASE_EXPORT ArrayItem; 165 class BASE_EXPORT DictionaryItem; 166 167 // Helper to enable easier initialization of |TracedValue|. This is intended 168 // for quick local debugging as there is overhead of creating 169 // |std::initializer_list| of name-value objects (in the case of containers 170 // the value is also a |std::initializer_list|). Generally the helper types 171 // |TracedValue::Dictionary|, |TracedValue::Array|, 172 // |TracedValue::DictionaryItem|, |TracedValue::ArrayItem| must be valid as 173 // well as their internals (e.g., |std::string_view| data should be valid 174 // when |TracedValue::Build| is called; |TracedValue::Array| or 175 // |TracedValue::Dictionary| holds a |std::initializer_list| whose underlying 176 // array needs to be valid when calling |TracedValue::Build|). 177 // 178 // Example: 179 // auto value = TracedValue::Build({ 180 // {"int_var_name", 42}, 181 // {"double_var_name", 3.14}, 182 // {"string_var_name", "hello world"}, 183 // {"empty_array", TracedValue::Array({})}, 184 // {"dictionary", TracedValue::Dictionary({ 185 // {"my_ptr", static_cast<void*>(my_ptr)}, 186 // {"nested_array", TracedValue::Array({1, false, 0.5})}, 187 // })}, 188 // }); 189 static std::unique_ptr<TracedValue> Build( 190 const std::initializer_list<DictionaryItem> items); 191 192 // An |Array| instance represents an array of |ArrayItem| objects. This is a 193 // helper to allow initializer list like construction of arrays using 194 // |TracedValue::Build|. 195 // 196 // An instance holds an |std::initializer_list<TracedValue::ArrayItem>| and is 197 // cheap to copy (copying the initializer_list does not copy the underlying 198 // objects). The underlying array must exist at the time when 199 // |TracedValue::Build| is called. 200 class Array { 201 public: 202 // This constructor expects that the initializer_list is valid when 203 // |TracedValue::Build| is called. 204 Array(const std::initializer_list<ArrayItem> items); 205 Array(Array&&); 206 void WriteToValue(TracedValue* value) const; 207 208 private: 209 std::initializer_list<ArrayItem> items_; 210 }; 211 212 // A helper to hold a dictionary. Similar to |TracedValue::Array|. 213 class Dictionary { 214 public: 215 // This constructor expects that the initializer_list is valid when 216 // |TracedValue::Build| is called. 217 Dictionary(const std::initializer_list<DictionaryItem> items); 218 Dictionary(Dictionary&&); 219 void WriteToValue(TracedValue* value) const; 220 221 private: 222 std::initializer_list<DictionaryItem> items_; 223 }; 224 225 // A |ValueHolder| holds a single value or a container (int, double... or an 226 // |Array| / |Dictionary|). Not to be used outside of the context of 227 // |TracedValue::Build| (has one parameter implicit constructors). 228 // 229 // Base class for |TracedValue::ArrayItem| and |TracedValue::DictionaryItem|. 230 class ValueHolder { 231 public: 232 // Implicit constructors allow constructing |DictionaryItem| without having 233 // to write |{"name", TracedValue::ValueHolder(1)}|. 234 ValueHolder(int value); // NOLINT(google-explicit-constructor) 235 ValueHolder(double value); // NOLINT(google-explicit-constructor) 236 ValueHolder(bool value); // NOLINT(google-explicit-constructor) 237 ValueHolder(void* value); // NOLINT(google-explicit-constructor) 238 // std::string_view's backing storage / const char* pointer needs to remain 239 // valid until TracedValue::Build is called. 240 // NOLINTNEXTLINE(google-explicit-constructor) 241 ValueHolder(std::string_view value); 242 // Create a copy to avoid holding a reference to a non-existing string: 243 // 244 // Example: 245 // TracedValue::Build({{"my_string", std::string("std::string value")}}); 246 // Explanation: 247 // 1. std::string temporary is passed to the constructor of |ValueHolder|. 248 // 2. |ValueHolder| is passed to the constructor of |DictionaryItem|. 249 // 3. |Build| iterates initializer_list of |DictionaryItems|. 250 // 251 // If the original |ValueHolder| kept just a reference to the string (or 252 // a |std::string_view|) then |Build| is undefined behaviour, as it is 253 // passing a reference to an out-of-scope temporary to 254 // |TracedValue::SetString|. 255 // NOLINTNEXTLINE(google-explicit-constructor) 256 ValueHolder(std::string value); 257 // Define an explicit overload for const char* to resolve the ambiguity 258 // between the std::string_view, void*, and bool constructors for string 259 // literals. 260 ValueHolder(const char* value); // NOLINT(google-explicit-constructor) 261 ValueHolder(Array& value); // NOLINT(google-explicit-constructor) 262 ValueHolder(Dictionary& value); // NOLINT(google-explicit-constructor) 263 ValueHolder(ValueHolder&&); 264 265 protected: 266 void WriteToValue(TracedValue* value) const; 267 void WriteToValue(const char* name, TracedValue* value) const; 268 269 private: 270 union KeptValue { 271 // Copy is handled by the holder (based on 272 // |TracedValue::ValueHolder::kept_value_type_|). 273 int int_value; 274 double double_value; 275 bool bool_value; 276 std::string_view string_piece_value; 277 std::string std_string_value; 278 // This field is not a raw_ptr<> because it was filtered by the rewriter 279 // for: #union 280 RAW_PTR_EXCLUSION void* void_ptr_value; 281 Array array_value; 282 Dictionary dictionary_value; 283 284 // Default constructor is implicitly deleted because union field has a 285 // non-trivial default constructor. KeptValue()286 KeptValue() {} // NOLINT(modernize-use-equals-default) ~KeptValue()287 ~KeptValue() {} // NOLINT(modernize-use-equals-default) 288 }; 289 290 // Reimplementing a subset of C++17 std::variant. 291 enum class KeptValueType { 292 kIntType, 293 kDoubleType, 294 kBoolType, 295 kStringPieceType, 296 kStdStringType, 297 kVoidPtrType, 298 kArrayType, 299 kDictionaryType, 300 }; 301 302 KeptValue kept_value_; 303 KeptValueType kept_value_type_; 304 }; 305 306 // |ArrayItem| is a |ValueHolder| which can be used to construct an |Array|. 307 class ArrayItem : public ValueHolder { 308 public: 309 // Implicit constructors allow calling |TracedValue::Array({1, true, 3.14})| 310 // instead of |TracedValue::Array({TracedValue::ArrayItem(1), 311 // TracedValue::ArrayItem(true), TracedValue::ArrayItem(3.14)})|. 312 template <typename T> 313 // NOLINTNEXTLINE(google-explicit-constructor) ArrayItem(T value)314 ArrayItem(T value) : ValueHolder(value) {} 315 316 void WriteToValue(TracedValue* value) const; 317 }; 318 319 // |DictionaryItem| instance represents a single name-value pair. 320 // 321 // |name| is assumed to be a long lived "quoted" string. 322 class DictionaryItem : public ValueHolder { 323 public: 324 // These constructors assume that |name| is a long lived "quoted" string. 325 template <typename T> DictionaryItem(const char * name,T value)326 DictionaryItem(const char* name, T value) 327 : ValueHolder(value), name_(name) {} 328 329 void WriteToValue(TracedValue* value) const; 330 331 private: 332 const char* name_; 333 }; 334 335 // A custom serialization class can be supplied by implementing the 336 // Writer interface and supplying a factory class to SetWriterFactoryCallback. 337 // Primarily used by Perfetto to write TracedValues directly into its proto 338 // format, which lets us do a direct memcpy() in AppendToProto() rather than 339 // a JSON serialization step in AppendAsTraceFormat. 340 class BASE_EXPORT Writer { 341 public: 342 virtual ~Writer() = default; 343 344 virtual void BeginArray() = 0; 345 virtual void BeginDictionary() = 0; 346 virtual void EndDictionary() = 0; 347 virtual void EndArray() = 0; 348 349 // These methods assume that |name| is a long lived "quoted" string. 350 virtual void SetInteger(const char* name, int value) = 0; 351 virtual void SetDouble(const char* name, double value) = 0; 352 virtual void SetBoolean(const char* name, bool value) = 0; 353 virtual void SetString(const char* name, std::string_view value) = 0; 354 virtual void SetValue(const char* name, Writer* value) = 0; 355 virtual void BeginDictionary(const char* name) = 0; 356 virtual void BeginArray(const char* name) = 0; 357 358 // These, instead, can be safely passed a temporary string. 359 virtual void SetIntegerWithCopiedName(std::string_view name, int value) = 0; 360 virtual void SetDoubleWithCopiedName(std::string_view name, 361 double value) = 0; 362 virtual void SetBooleanWithCopiedName(std::string_view name, 363 bool value) = 0; 364 virtual void SetStringWithCopiedName(std::string_view name, 365 std::string_view value) = 0; 366 virtual void SetValueWithCopiedName(std::string_view name, 367 Writer* value) = 0; 368 virtual void BeginDictionaryWithCopiedName(std::string_view name) = 0; 369 virtual void BeginArrayWithCopiedName(std::string_view name) = 0; 370 371 virtual void AppendInteger(int) = 0; 372 virtual void AppendDouble(double) = 0; 373 virtual void AppendBoolean(bool) = 0; 374 virtual void AppendString(std::string_view) = 0; 375 376 virtual void AppendAsTraceFormat(std::string* out) const = 0; 377 378 virtual bool AppendToProto(ProtoAppender* appender); 379 380 virtual void EstimateTraceMemoryOverhead( 381 TraceEventMemoryOverhead* overhead) = 0; 382 383 virtual bool IsPickleWriter() const = 0; 384 virtual bool IsProtoWriter() const = 0; 385 }; 386 387 typedef std::unique_ptr<Writer> (*WriterFactoryCallback)(size_t capacity); 388 static void SetWriterFactoryCallback(WriterFactoryCallback callback); 389 390 protected: 391 TracedValue(size_t capacity, bool forced_json); 392 393 std::unique_ptr<base::Value> ToBaseValue() const; 394 395 private: 396 mutable std::unique_ptr<Writer> writer_; 397 398 #ifndef NDEBUG 399 // In debug builds checks the pairings of {Start,End}{Dictionary,Array} 400 std::vector<bool> nesting_stack_; 401 #endif 402 }; 403 404 // TracedValue that is convertable to JSON format. This has lower performance 405 // than the default TracedValue in production code, and should be used only for 406 // testing and debugging. Should be avoided in tracing. It's for 407 // testing/debugging code calling value dumping function designed for tracing, 408 // like the following: 409 // 410 // TracedValueJSON value; 411 // AsValueInto(&value); // which is designed for tracing. 412 // return value.ToJSON(); 413 // 414 // If the code is merely for testing/debugging, base::Value should be used 415 // instead. 416 class BASE_EXPORT TracedValueJSON : public TracedValue { 417 public: 418 explicit TracedValueJSON(size_t capacity = 0) TracedValue(capacity,true)419 : TracedValue(capacity, /*forced_josn*/ true) {} 420 421 using TracedValue::ToBaseValue; 422 423 // Converts the value into a JSON string without formatting. Suitable for 424 // printing a simple value or printing a value in a single line context. 425 std::string ToJSON() const; 426 427 // Converts the value into a formatted JSON string, with indentation, spaces 428 // and new lines for better human readability of complex values. 429 std::string ToFormattedJSON() const; 430 }; 431 432 } // namespace trace_event 433 } // namespace base 434 435 #endif // BASE_TRACE_EVENT_TRACED_VALUE_H_ 436