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 #include "TraceBuffer.h"
18 
19 #include <chrono>
20 #include <sstream>
21 #include <unistd.h>
22 #include <vector>
23 
24 #include <inttypes.h>
25 
26 #include "android-base/utf8.h"
27 
28 #include "util/Files.h"
29 
30 namespace aapt {
31 namespace tracebuffer {
32 
33 namespace {
34 
35 constexpr char kBegin = 'B';
36 constexpr char kEnd = 'E';
37 
38 struct TracePoint {
39   pid_t tid;
40   int64_t time;
41   std::string tag;
42   char type;
43 };
44 
45 std::vector<TracePoint> traces;
46 
GetTime()47 int64_t GetTime() noexcept {
48   auto now = std::chrono::steady_clock::now();
49   return std::chrono::duration_cast<std::chrono::microseconds>(now.time_since_epoch()).count();
50 }
51 
52 } // namespace anonymous
53 
AddWithTime(const std::string & tag,char type,int64_t time)54 void AddWithTime(const std::string& tag, char type, int64_t time) noexcept {
55   TracePoint t = {getpid(), time, tag, type};
56   traces.emplace_back(t);
57 }
58 
Add(const std::string & tag,char type)59 void Add(const std::string& tag, char type) noexcept {
60   AddWithTime(tag, type, GetTime());
61 }
62 
63 
64 
65 
Flush(const std::string & basePath)66 void Flush(const std::string& basePath) {
67   TRACE_CALL();
68   if (basePath.empty()) {
69     return;
70   }
71 
72   std::stringstream s;
73   s << basePath << aapt::file::sDirSep << "report_aapt2_" << getpid() << ".json";
74   FILE* f = android::base::utf8::fopen(s.str().c_str(), "a");
75   if (f == nullptr) {
76     return;
77   }
78 
79   for(const TracePoint& trace : traces) {
80     fprintf(f, "{\"ts\" : \"%" PRIu64 "\", \"ph\" : \"%c\", \"tid\" : \"%d\" , \"pid\" : \"%d\", "
81             "\"name\" : \"%s\" },\n", trace.time, trace.type, 0, trace.tid, trace.tag.c_str());
82   }
83   fclose(f);
84   traces.clear();
85 }
86 
87 } // namespace tracebuffer
88 
BeginTrace(const std::string & tag)89 void BeginTrace(const std::string& tag) {
90   tracebuffer::Add(tag, tracebuffer::kBegin);
91 }
92 
EndTrace()93 void EndTrace() {
94   tracebuffer::Add("", tracebuffer::kEnd);
95 }
96 
Trace(const std::string & tag)97 Trace::Trace(const std::string& tag) {
98   tracebuffer::Add(tag, tracebuffer::kBegin);
99 }
100 
Trace(const std::string & tag,const std::vector<android::StringPiece> & args)101 Trace::Trace(const std::string& tag, const std::vector<android::StringPiece>& args) {
102   std::stringstream s;
103   s << tag;
104   s << " ";
105   for (auto& arg : args) {
106     s << arg.to_string();
107     s << " ";
108   }
109   tracebuffer::Add(s.str(), tracebuffer::kBegin);
110 }
111 
~Trace()112 Trace::~Trace() {
113   tracebuffer::Add("", tracebuffer::kEnd);
114 }
115 
FlushTrace(const std::string & basepath,const std::string & tag)116 FlushTrace::FlushTrace(const std::string& basepath, const std::string& tag)
117     : basepath_(basepath)  {
118   tracebuffer::Add(tag, tracebuffer::kBegin);
119 }
120 
FlushTrace(const std::string & basepath,const std::string & tag,const std::vector<android::StringPiece> & args)121 FlushTrace::FlushTrace(const std::string& basepath, const std::string& tag,
122     const std::vector<android::StringPiece>& args) : basepath_(basepath) {
123   std::stringstream s;
124   s << tag;
125   s << " ";
126   for (auto& arg : args) {
127     s << arg.to_string();
128     s << " ";
129   }
130   tracebuffer::Add(s.str(), tracebuffer::kBegin);
131 }
132 
FlushTrace(const std::string & basepath,const std::string & tag,const std::vector<std::string> & args)133 FlushTrace::FlushTrace(const std::string& basepath, const std::string& tag,
134     const std::vector<std::string>& args) : basepath_(basepath){
135   std::stringstream s;
136   s << tag;
137   s << " ";
138   for (auto& arg : args) {
139     s << arg;
140     s << " ";
141   }
142   tracebuffer::Add(s.str(), tracebuffer::kBegin);
143 }
144 
~FlushTrace()145 FlushTrace::~FlushTrace() {
146   tracebuffer::Add("", tracebuffer::kEnd);
147   tracebuffer::Flush(basepath_);
148 }
149 
150 } // namespace aapt
151 
152