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