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