• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "src/trace_processor/importers/json/json_utils.h"
18 
19 #include "perfetto/base/build_config.h"
20 
21 #include <limits>
22 
23 #if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
24 #include <json/reader.h>
25 #include "perfetto/ext/base/string_utils.h"
26 #endif
27 
28 namespace perfetto {
29 namespace trace_processor {
30 namespace json {
31 
IsJsonSupported()32 bool IsJsonSupported() {
33 #if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
34   return true;
35 #else
36   return false;
37 #endif
38 }
39 
CoerceToTs(const Json::Value & value)40 std::optional<int64_t> CoerceToTs(const Json::Value& value) {
41   PERFETTO_DCHECK(IsJsonSupported());
42 
43 #if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
44   switch (static_cast<size_t>(value.type())) {
45     case Json::realValue:
46       return static_cast<int64_t>(value.asDouble() * 1000.0);
47     case Json::uintValue:
48     case Json::intValue:
49       return value.asInt64() * 1000;
50     case Json::stringValue:
51       return CoerceToTs(value.asString());
52     default:
53       return std::nullopt;
54   }
55 #else
56   perfetto::base::ignore_result(value);
57   return std::nullopt;
58 #endif
59 }
60 
CoerceToTs(const std::string & s)61 std::optional<int64_t> CoerceToTs(const std::string& s) {
62   PERFETTO_DCHECK(IsJsonSupported());
63 
64 #if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
65   // 's' is formatted as a JSON Number, in microseconds
66   // goal: reformat 's' to be as an int, in nanoseconds
67   std::string s_as_ns = s;
68 
69   // detect and remove scientific notation's exponents
70   int32_t exp_shift = 0;
71   if (size_t exp_start = s.find_first_of("eE");
72       exp_start != std::string::npos) {
73     const std::string exp_s = s.substr(exp_start + 1, s.size());
74     const std::optional<int32_t> exp = base::StringToInt32(exp_s);
75     if (!exp.has_value()) {
76       return std::nullopt;
77     }
78     s_as_ns.erase(exp_start);
79     exp_shift = *exp;
80   }
81 
82   // detect and remove decimal separator
83   size_t int_size = s_as_ns.size();
84   if (size_t frac_start = s.find('.'); frac_start != std::string::npos) {
85     s_as_ns.erase(frac_start, 1);
86     int_size = frac_start;
87   }
88 
89   // expand or shrink to the new size
90   constexpr int us_to_ns_shift = 3;
91   const size_t s_as_ns_size = size_t(
92       std::max<ptrdiff_t>(1, ptrdiff_t(int_size) + exp_shift + us_to_ns_shift));
93   s_as_ns.resize(s_as_ns_size, '0');  // pads or truncates
94 
95   return base::StringToInt64(s_as_ns);
96 #else
97   perfetto::base::ignore_result(s);
98   return std::nullopt;
99 #endif
100 }
101 
CoerceToInt64(const Json::Value & value)102 std::optional<int64_t> CoerceToInt64(const Json::Value& value) {
103   PERFETTO_DCHECK(IsJsonSupported());
104 
105 #if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
106   switch (static_cast<size_t>(value.type())) {
107     case Json::realValue:
108     case Json::uintValue:
109       return static_cast<int64_t>(value.asUInt64());
110     case Json::intValue:
111       return value.asInt64();
112     case Json::stringValue: {
113       std::string s = value.asString();
114       char* end;
115       int64_t n = strtoll(s.c_str(), &end, 10);
116       if (end != s.data() + s.size())
117         return std::nullopt;
118       return n;
119     }
120     default:
121       return std::nullopt;
122   }
123 #else
124   perfetto::base::ignore_result(value);
125   return std::nullopt;
126 #endif
127 }
128 
CoerceToUint32(const Json::Value & value)129 std::optional<uint32_t> CoerceToUint32(const Json::Value& value) {
130   PERFETTO_DCHECK(IsJsonSupported());
131 
132 #if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
133   std::optional<int64_t> result = CoerceToInt64(value);
134   if (!result.has_value())
135     return std::nullopt;
136   int64_t n = result.value();
137   if (n < 0 || n > std::numeric_limits<uint32_t>::max())
138     return std::nullopt;
139   return static_cast<uint32_t>(n);
140 #else
141   perfetto::base::ignore_result(value);
142   return std::nullopt;
143 #endif
144 }
145 
ParseJsonString(base::StringView raw_string)146 std::optional<Json::Value> ParseJsonString(base::StringView raw_string) {
147   PERFETTO_DCHECK(IsJsonSupported());
148 
149 #if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
150   Json::CharReaderBuilder b;
151   auto reader = std::unique_ptr<Json::CharReader>(b.newCharReader());
152 
153   Json::Value value;
154   const char* begin = raw_string.data();
155   return reader->parse(begin, begin + raw_string.size(), &value, nullptr)
156              ? std::make_optional(std::move(value))
157              : std::nullopt;
158 #else
159   perfetto::base::ignore_result(raw_string);
160   return std::nullopt;
161 #endif
162 }
163 
AddJsonValueToArgs(const Json::Value & value,base::StringView flat_key,base::StringView key,TraceStorage * storage,ArgsTracker::BoundInserter * inserter)164 bool AddJsonValueToArgs(const Json::Value& value,
165                         base::StringView flat_key,
166                         base::StringView key,
167                         TraceStorage* storage,
168                         ArgsTracker::BoundInserter* inserter) {
169   PERFETTO_DCHECK(IsJsonSupported());
170 
171 #if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
172   if (value.isObject()) {
173     auto it = value.begin();
174     bool inserted = false;
175     for (; it != value.end(); ++it) {
176       std::string child_name = it.name();
177       std::string child_flat_key = flat_key.ToStdString() + "." + child_name;
178       std::string child_key = key.ToStdString() + "." + child_name;
179       inserted |=
180           AddJsonValueToArgs(*it, base::StringView(child_flat_key),
181                              base::StringView(child_key), storage, inserter);
182     }
183     return inserted;
184   }
185 
186   if (value.isArray()) {
187     auto it = value.begin();
188     bool inserted_any = false;
189     std::string array_key = key.ToStdString();
190     StringId array_key_id = storage->InternString(key);
191     for (; it != value.end(); ++it) {
192       size_t array_index = inserter->GetNextArrayEntryIndex(array_key_id);
193       std::string child_key =
194           array_key + "[" + std::to_string(array_index) + "]";
195       bool inserted = AddJsonValueToArgs(
196           *it, flat_key, base::StringView(child_key), storage, inserter);
197       if (inserted)
198         inserter->IncrementArrayEntryIndex(array_key_id);
199       inserted_any |= inserted;
200     }
201     return inserted_any;
202   }
203 
204   // Leaf value.
205   auto flat_key_id = storage->InternString(flat_key);
206   auto key_id = storage->InternString(key);
207 
208   switch (value.type()) {
209     case Json::ValueType::nullValue:
210       break;
211     case Json::ValueType::intValue:
212       inserter->AddArg(flat_key_id, key_id, Variadic::Integer(value.asInt64()));
213       return true;
214     case Json::ValueType::uintValue:
215       inserter->AddArg(flat_key_id, key_id,
216                        Variadic::UnsignedInteger(value.asUInt64()));
217       return true;
218     case Json::ValueType::realValue:
219       inserter->AddArg(flat_key_id, key_id, Variadic::Real(value.asDouble()));
220       return true;
221     case Json::ValueType::stringValue:
222       inserter->AddArg(flat_key_id, key_id,
223                        Variadic::String(storage->InternString(
224                            base::StringView(value.asString()))));
225       return true;
226     case Json::ValueType::booleanValue:
227       inserter->AddArg(flat_key_id, key_id, Variadic::Boolean(value.asBool()));
228       return true;
229     case Json::ValueType::objectValue:
230     case Json::ValueType::arrayValue:
231       PERFETTO_FATAL("Non-leaf types handled above");
232       break;
233   }
234   return false;
235 #else
236   perfetto::base::ignore_result(value);
237   perfetto::base::ignore_result(flat_key);
238   perfetto::base::ignore_result(key);
239   perfetto::base::ignore_result(storage);
240   perfetto::base::ignore_result(inserter);
241   return false;
242 #endif
243 }
244 
245 }  // namespace json
246 }  // namespace trace_processor
247 }  // namespace perfetto
248