• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 #ifndef SRC_TRACE_PROCESSOR_IMPORTERS_JSON_JSON_TRACE_TOKENIZER_H_
18 #define SRC_TRACE_PROCESSOR_IMPORTERS_JSON_JSON_TRACE_TOKENIZER_H_
19 
20 #include <stdint.h>
21 
22 #include "src/trace_processor/importers/common/chunked_trace_reader.h"
23 #include "src/trace_processor/importers/json/json_utils.h"
24 #include "src/trace_processor/importers/systrace/systrace_line_tokenizer.h"
25 #include "src/trace_processor/storage/trace_storage.h"
26 
27 namespace Json {
28 class Value;
29 }
30 
31 namespace perfetto {
32 namespace trace_processor {
33 
34 class TraceProcessorContext;
35 
36 // Visible for testing.
37 enum class ReadDictRes {
38   kFoundDict,
39   kNeedsMoreData,
40   kEndOfTrace,
41   kEndOfArray,
42 };
43 
44 // Parses at most one JSON dictionary and returns a pointer to the end of it,
45 // or nullptr if no dict could be detected.
46 // This is to avoid decoding the full trace in memory and reduce heap traffic.
47 // E.g.  input:  { a:1 b:{ c:2, d:{ e:3 } } } , { a:4, ... },
48 //       output: [   only this is parsed    ] ^return value points here.
49 // Visible for testing.
50 ReadDictRes ReadOneJsonDict(const char* start,
51                             const char* end,
52                             base::StringView* value,
53                             const char** next);
54 
55 enum class ReadKeyRes {
56   kFoundKey,
57   kNeedsMoreData,
58   kEndOfDictionary,
59   kFatalError,
60 };
61 
62 // Parses at most one JSON key and returns a pointer to the start of the value
63 // associated with that key.
64 // This is to avoid decoding the full trace in memory and reduce heap traffic.
65 // E.g. input:  a:1 b:{ c:2}}
66 //     output:    ^ return value points here, key is set to "a".
67 // Note: even if the whole key may be available, this method will return
68 // kNeedsMoreData until the first character of the value is available.
69 // Visible for testing.
70 ReadKeyRes ReadOneJsonKey(const char* start,
71                           const char* end,
72                           std::string* key,
73                           const char** next);
74 
75 // Takes as input a JSON dictionary and returns the value associated with
76 // the provided key (if it exists).
77 // Implementation note: this method does not currently support dictionaries
78 // which have arrays as JSON values because current users of this method
79 // do not require this.
80 // Visible for testing.
81 util::Status ExtractValueForJsonKey(base::StringView dict,
82                                     const std::string& key,
83                                     base::Optional<std::string>* value);
84 
85 enum class ReadSystemLineRes {
86   kFoundLine,
87   kNeedsMoreData,
88   kEndOfSystemTrace,
89   kFatalError,
90 };
91 
92 ReadSystemLineRes ReadOneSystemTraceLine(const char* start,
93                                          const char* end,
94                                          std::string* line,
95                                          const char** next);
96 
97 // Reads a JSON trace in chunks and extracts top level json objects.
98 class JsonTraceTokenizer : public ChunkedTraceReader {
99  public:
100   explicit JsonTraceTokenizer(TraceProcessorContext*);
101   ~JsonTraceTokenizer() override;
102 
103   // ChunkedTraceReader implementation.
104   util::Status Parse(TraceBlobView) override;
105   void NotifyEndOfFile() override;
106 
107  private:
108   // Enum which tracks which type of JSON trace we are dealing with.
109   enum class TraceFormat {
110     // Enum value when ther outer-most layer is a dictionary with multiple
111     // key value pairs
112     kOuterDictionary,
113 
114     // Enum value when we only have trace events (i.e. the outermost
115     // layer is just a array of trace events).
116     kOnlyTraceEvents,
117   };
118 
119   // Enum which tracks our current position within the trace.
120   enum class TracePosition {
121     // This indicates that we are inside the outermost dictionary of the
122     // trace and need to read the next key of the dictionary.
123     // This position is only valid when the |format_| == |kOuterDictionary|.
124     kDictionaryKey,
125 
126     // This indicates we are inside the systemTraceEvents string.
127     // This position is only valid when the |format_| == |kOuterDictionary|.
128     kSystemTraceEventsString,
129 
130     // This indicates we are waiting for the entire metadata dictionary to be
131     // available.
132     kWaitingForMetadataDictionary,
133 
134     // This indicates where are inside the traceEvents array.
135     kTraceEventsArray,
136 
137     // This indicates we cannot parse any more data in the trace.
138     kEof,
139   };
140 
141   util::Status ParseInternal(const char* start,
142                              const char* end,
143                              const char** next);
144 
145   TraceProcessorContext* const context_;
146 
147   TraceFormat format_ = TraceFormat::kOuterDictionary;
148   TracePosition position_ = TracePosition::kDictionaryKey;
149 
150   SystraceLineTokenizer systrace_line_tokenizer_;
151 
152   uint64_t offset_ = 0;
153   // Used to glue together JSON objects that span across two (or more)
154   // Parse boundaries.
155   std::vector<char> buffer_;
156 };
157 
158 }  // namespace trace_processor
159 }  // namespace perfetto
160 
161 #endif  // SRC_TRACE_PROCESSOR_IMPORTERS_JSON_JSON_TRACE_TOKENIZER_H_
162