• 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 namespace {
32 
33 #if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
TimeUnitToNs(TimeUnit unit)34 int64_t TimeUnitToNs(TimeUnit unit) {
35   return static_cast<int64_t>(unit);
36 }
37 #endif
38 
39 }  // namespace
40 
IsJsonSupported()41 bool IsJsonSupported() {
42 #if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
43   return true;
44 #else
45   return false;
46 #endif
47 }
48 
CoerceToTs(TimeUnit unit,const Json::Value & value)49 base::Optional<int64_t> CoerceToTs(TimeUnit unit, const Json::Value& value) {
50   PERFETTO_DCHECK(IsJsonSupported());
51 
52 #if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
53   switch (static_cast<size_t>(value.type())) {
54     case Json::realValue:
55       return static_cast<int64_t>(value.asDouble() *
56                                   static_cast<double>(TimeUnitToNs(unit)));
57     case Json::uintValue:
58     case Json::intValue:
59       return value.asInt64() * TimeUnitToNs(unit);
60     case Json::stringValue: {
61       std::string s = value.asString();
62       size_t lhs_end = std::min<size_t>(s.find('.'), s.size());
63       size_t rhs_start = std::min<size_t>(lhs_end + 1, s.size());
64       base::Optional<int64_t> lhs = base::StringToInt64(s.substr(0, lhs_end));
65       base::Optional<double> rhs =
66           base::StringToDouble("0." + s.substr(rhs_start, std::string::npos));
67       if ((!lhs.has_value() && lhs_end > 0) ||
68           (!rhs.has_value() && rhs_start < s.size())) {
69         return base::nullopt;
70       }
71       int64_t factor = TimeUnitToNs(unit);
72       return lhs.value_or(0) * factor +
73              static_cast<int64_t>(rhs.value_or(0) *
74                                   static_cast<double>(factor));
75     }
76     default:
77       return base::nullopt;
78   }
79 #else
80   perfetto::base::ignore_result(unit);
81   perfetto::base::ignore_result(value);
82   return base::nullopt;
83 #endif
84 }
85 
CoerceToInt64(const Json::Value & value)86 base::Optional<int64_t> CoerceToInt64(const Json::Value& value) {
87   PERFETTO_DCHECK(IsJsonSupported());
88 
89 #if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
90   switch (static_cast<size_t>(value.type())) {
91     case Json::realValue:
92     case Json::uintValue:
93       return static_cast<int64_t>(value.asUInt64());
94     case Json::intValue:
95       return value.asInt64();
96     case Json::stringValue: {
97       std::string s = value.asString();
98       char* end;
99       int64_t n = strtoll(s.c_str(), &end, 10);
100       if (end != s.data() + s.size())
101         return base::nullopt;
102       return n;
103     }
104     default:
105       return base::nullopt;
106   }
107 #else
108   perfetto::base::ignore_result(value);
109   return base::nullopt;
110 #endif
111 }
112 
CoerceToUint32(const Json::Value & value)113 base::Optional<uint32_t> CoerceToUint32(const Json::Value& value) {
114   PERFETTO_DCHECK(IsJsonSupported());
115 
116 #if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
117   base::Optional<int64_t> result = CoerceToInt64(value);
118   if (!result.has_value())
119     return base::nullopt;
120   int64_t n = result.value();
121   if (n < 0 || n > std::numeric_limits<uint32_t>::max())
122     return base::nullopt;
123   return static_cast<uint32_t>(n);
124 #else
125   perfetto::base::ignore_result(value);
126   return base::nullopt;
127 #endif
128 }
129 
ParseJsonString(base::StringView raw_string)130 base::Optional<Json::Value> ParseJsonString(base::StringView raw_string) {
131   PERFETTO_DCHECK(IsJsonSupported());
132 
133 #if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
134   Json::CharReaderBuilder b;
135   auto reader = std::unique_ptr<Json::CharReader>(b.newCharReader());
136 
137   Json::Value value;
138   const char* begin = raw_string.data();
139   return reader->parse(begin, begin + raw_string.size(), &value, nullptr)
140              ? base::make_optional(std::move(value))
141              : base::nullopt;
142 #else
143   perfetto::base::ignore_result(raw_string);
144   return base::nullopt;
145 #endif
146 }
147 
AddJsonValueToArgs(const Json::Value & value,base::StringView flat_key,base::StringView key,TraceStorage * storage,ArgsTracker::BoundInserter * inserter)148 bool AddJsonValueToArgs(const Json::Value& value,
149                         base::StringView flat_key,
150                         base::StringView key,
151                         TraceStorage* storage,
152                         ArgsTracker::BoundInserter* inserter) {
153   PERFETTO_DCHECK(IsJsonSupported());
154 
155 #if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
156   if (value.isObject()) {
157     auto it = value.begin();
158     bool inserted = false;
159     for (; it != value.end(); ++it) {
160       std::string child_name = it.name();
161       std::string child_flat_key = flat_key.ToStdString() + "." + child_name;
162       std::string child_key = key.ToStdString() + "." + child_name;
163       inserted |=
164           AddJsonValueToArgs(*it, base::StringView(child_flat_key),
165                              base::StringView(child_key), storage, inserter);
166     }
167     return inserted;
168   }
169 
170   if (value.isArray()) {
171     auto it = value.begin();
172     bool inserted_any = false;
173     std::string array_key = key.ToStdString();
174     StringId array_key_id = storage->InternString(key);
175     for (; it != value.end(); ++it) {
176       size_t array_index = inserter->GetNextArrayEntryIndex(array_key_id);
177       std::string child_key =
178           array_key + "[" + std::to_string(array_index) + "]";
179       bool inserted = AddJsonValueToArgs(
180           *it, flat_key, base::StringView(child_key), storage, inserter);
181       if (inserted)
182         inserter->IncrementArrayEntryIndex(array_key_id);
183       inserted_any |= inserted;
184     }
185     return inserted_any;
186   }
187 
188   // Leaf value.
189   auto flat_key_id = storage->InternString(flat_key);
190   auto key_id = storage->InternString(key);
191 
192   switch (value.type()) {
193     case Json::ValueType::nullValue:
194       break;
195     case Json::ValueType::intValue:
196       inserter->AddArg(flat_key_id, key_id, Variadic::Integer(value.asInt64()));
197       return true;
198     case Json::ValueType::uintValue:
199       inserter->AddArg(flat_key_id, key_id,
200                        Variadic::UnsignedInteger(value.asUInt64()));
201       return true;
202     case Json::ValueType::realValue:
203       inserter->AddArg(flat_key_id, key_id, Variadic::Real(value.asDouble()));
204       return true;
205     case Json::ValueType::stringValue:
206       inserter->AddArg(flat_key_id, key_id,
207                        Variadic::String(storage->InternString(
208                            base::StringView(value.asString()))));
209       return true;
210     case Json::ValueType::booleanValue:
211       inserter->AddArg(flat_key_id, key_id, Variadic::Boolean(value.asBool()));
212       return true;
213     case Json::ValueType::objectValue:
214     case Json::ValueType::arrayValue:
215       PERFETTO_FATAL("Non-leaf types handled above");
216       break;
217   }
218   return false;
219 #else
220   perfetto::base::ignore_result(value);
221   perfetto::base::ignore_result(flat_key);
222   perfetto::base::ignore_result(key);
223   perfetto::base::ignore_result(storage);
224   perfetto::base::ignore_result(inserter);
225   return false;
226 #endif
227 }
228 
229 }  // namespace json
230 }  // namespace trace_processor
231 }  // namespace perfetto
232