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 #if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON) 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 #endif 97 98 // Reads a JSON trace in chunks and extracts top level json objects. 99 class JsonTraceTokenizer : public ChunkedTraceReader { 100 public: 101 explicit JsonTraceTokenizer(TraceProcessorContext*); 102 ~JsonTraceTokenizer() override; 103 104 // ChunkedTraceReader implementation. 105 util::Status Parse(std::unique_ptr<uint8_t[]>, size_t) override; 106 void NotifyEndOfFile() override; 107 108 private: 109 // Enum which tracks which type of JSON trace we are dealing with. 110 enum class TraceFormat { 111 // Enum value when ther outer-most layer is a dictionary with multiple 112 // key value pairs 113 kOuterDictionary, 114 115 // Enum value when we only have trace events (i.e. the outermost 116 // layer is just a array of trace events). 117 kOnlyTraceEvents, 118 }; 119 120 // Enum which tracks our current position within the trace. 121 enum class TracePosition { 122 // This indicates that we are inside the outermost dictionary of the 123 // trace and need to read the next key of the dictionary. 124 // This position is only valid when the |format_| == |kOuterDictionary|. 125 kDictionaryKey, 126 127 // This indicates we are inside the systemTraceEvents string. 128 // This position is only valid when the |format_| == |kOuterDictionary|. 129 kSystemTraceEventsString, 130 131 // This indicates we are waiting for the entire metadata dictionary to be 132 // available. 133 kWaitingForMetadataDictionary, 134 135 // This indicates where are inside the traceEvents array. 136 kTraceEventsArray, 137 138 // This indicates we cannot parse any more data in the trace. 139 kEof, 140 }; 141 142 #if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON) 143 util::Status ParseInternal(const char* start, 144 const char* end, 145 const char** next); 146 #endif 147 148 TraceProcessorContext* const context_; 149 150 TraceFormat format_ = TraceFormat::kOuterDictionary; 151 TracePosition position_ = TracePosition::kDictionaryKey; 152 153 SystraceLineTokenizer systrace_line_tokenizer_; 154 155 uint64_t offset_ = 0; 156 // Used to glue together JSON objects that span across two (or more) 157 // Parse boundaries. 158 std::vector<char> buffer_; 159 }; 160 161 } // namespace trace_processor 162 } // namespace perfetto 163 164 #endif // SRC_TRACE_PROCESSOR_IMPORTERS_JSON_JSON_TRACE_TOKENIZER_H_ 165