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