1 // Copyright 2020 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "host-common/opengl/logger.h"
16 
17 #include "aemu/base/files/PathUtils.h"
18 #include "aemu/base/synchronization/Lock.h"
19 
20 #include <algorithm>
21 #include <fstream>
22 #include <inttypes.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <string>
26 
27 #include "aemu/base/msvc.h"
28 
29 #ifndef _MSC_VER
30 #include <sys/time.h>
31 #endif
32 #include <vector>
33 
34 using android::base::AutoLock;
35 using android::base::Lock;
36 using android::base::PathUtils;
37 
38 // The purpose of the OpenGL logger is to log
39 // information about such things as EGL initialization
40 // and possibly miscellanous OpenGL commands,
41 // in order to get a better idea of what is going on
42 // in crash reports.
43 
44 // The OpenGLLogger implementation's initialization method
45 // by default uses the crash reporter's data directory.
46 
47 static const int kBufferLen = 2048;
48 
49 typedef std::pair<uint64_t, std::string> TimestampedLogEntry;
50 
51 class OpenGLLogger {
52 public:
53     OpenGLLogger();
54     OpenGLLogger(const char* filename);
55     void stop();
56 
57     // Coarse log: Call this infrequently.
58     void writeCoarse(const char* str);
59 
60     // Fine log: When we want to log very frequent events.
61     // Fine logs can be toggled on/off.
62     void writeFineTimestamped(const char* str);
63 
64     void setLoggerFlags(AndroidOpenglLoggerFlags flags);
65     bool isFineLogging() const;
66 
67     static OpenGLLogger* get();
68 
69 private:
70 
71     void writeFineLocked(uint64_t time, const char* str);
72     void stopFineLogLocked();
73 
74     Lock mLock;
75     AndroidOpenglLoggerFlags mLoggerFlags = OPENGL_LOGGER_NONE;
76     uint64_t mPrevTimeUs = 0;
77     std::string mFileName;
78     std::ofstream mFileHandle;
79     std::string mFineLogFileName;
80     std::ofstream mFineLogFileHandle;
81     std::vector<TimestampedLogEntry> mFineLog;
82     DISALLOW_COPY_ASSIGN_AND_MOVE(OpenGLLogger);
83 };
84 
sOpenGLLogger()85 static OpenGLLogger* sOpenGLLogger() {
86     static OpenGLLogger* g = new OpenGLLogger;
87     return g;
88 }
89 
get()90 OpenGLLogger* OpenGLLogger::get() {
91     return sOpenGLLogger();
92 }
93 
OpenGLLogger()94 OpenGLLogger::OpenGLLogger() {
95 // #ifdef AEMU_MIN
96     return;
97 // #else
98 //     const std::string& data_dir =
99 //         CrashReporter::get()->getDataExchangeDir();
100 //     mFileName = PathUtils::join(data_dir,
101 //                                 "opengl_log.txt");
102 //     mFileHandle.open(mFileName, std::ios::app);
103 //     mFineLogFileName = PathUtils::join(data_dir,
104 //                                        "opengl_cxt_log.txt");
105 //     mFineLogFileHandle.open(mFineLogFileName, std::ios::app);
106 // #endif
107 }
108 
OpenGLLogger(const char * filename)109 OpenGLLogger::OpenGLLogger(const char* filename) :
110     mFileName(filename) {
111     mFileHandle.open(mFileName, std::ios::app);
112 }
113 
writeCoarse(const char * str)114 void OpenGLLogger::writeCoarse(const char* str) {
115     AutoLock lock(mLock);
116     if (mLoggerFlags & OPENGL_LOGGER_PRINT_TO_STDOUT) {
117         printf("%s\n", str);
118     }
119     if (mFileHandle) {
120         mFileHandle << str << std::endl;
121     }
122 }
123 
stop()124 void OpenGLLogger::stop() {
125     AutoLock lock(mLock);
126     stopFineLogLocked();
127     mFileHandle.close();
128 }
129 
writeFineLocked(uint64_t time,const char * str)130 void OpenGLLogger::writeFineLocked(uint64_t time, const char* str) {
131     if (mLoggerFlags & OPENGL_LOGGER_PRINT_TO_STDOUT) {
132         printf("%s", str);
133     } else {
134         mFineLog.emplace_back(time, str);
135     }
136 }
137 
writeFineTimestamped(const char * str)138 void OpenGLLogger::writeFineTimestamped(const char* str) {
139     if (mLoggerFlags & OPENGL_LOGGER_DO_FINE_LOGGING) {
140         char buf[kBufferLen] = {};
141         struct timeval tv;
142         gettimeofday(&tv, NULL);
143 
144         uint64_t curr_micros = (tv.tv_usec) % 1000;
145         uint64_t curr_millis = (tv.tv_usec / 1000) % 1000;
146         uint64_t curr_secs = tv.tv_sec;
147         uint64_t curr_us = tv.tv_sec * 1000000ULL + tv.tv_usec;
148         snprintf(buf, sizeof(buf) - 1,
149                 "time_us="
150                 "%" PRIu64 " s "
151                 "%" PRIu64 " ms "
152                 "%" PRIu64 " us deltaUs "
153                 "%" PRIu64 " | %s",
154                 curr_secs,
155                 curr_millis,
156                 curr_micros,
157                 curr_us - mPrevTimeUs,
158                 str);
159         AutoLock lock(mLock);
160         writeFineLocked(curr_micros + 1000ULL * curr_millis +
161                   1000ULL * 1000ULL * curr_secs, buf);
162         mPrevTimeUs = curr_us;
163     }
164 }
165 
setLoggerFlags(AndroidOpenglLoggerFlags flags)166 void OpenGLLogger::setLoggerFlags(AndroidOpenglLoggerFlags flags) {
167     AutoLock lock(mLock);
168     bool needStopFineLog =
169         (mLoggerFlags & OPENGL_LOGGER_DO_FINE_LOGGING) &&
170         (!(flags & OPENGL_LOGGER_DO_FINE_LOGGING));
171 
172     if (needStopFineLog) {
173         stopFineLogLocked();
174     }
175 
176     mLoggerFlags = flags;
177 }
178 
isFineLogging() const179 bool OpenGLLogger::isFineLogging() const {
180     // For speed, we'll just let this read of mLoggerFlags race.
181     return (mLoggerFlags & OPENGL_LOGGER_DO_FINE_LOGGING);
182 }
183 
stopFineLogLocked()184 void OpenGLLogger::stopFineLogLocked() {
185     // Only print message when fine-grained
186     // logging is turned on.
187     if (!mFineLog.empty()) {
188         fprintf(stderr,
189                 "Writing fine-grained GL log to %s...",
190                 mFineLogFileName.c_str());
191     }
192 
193     // Sort log entries according to their timestamps.
194     // This is because the log entries might arrive
195     // out of order.
196     std::sort(mFineLog.begin(), mFineLog.end(),
197               [](const TimestampedLogEntry& x,
198                  const TimestampedLogEntry& y) {
199                   return x.first < y.first;
200               });
201 
202     if (mFineLogFileHandle) {
203         for (const auto& entry : mFineLog) {
204             // The fine log does not print newlines
205             // as it is used with the opengl debug
206             // printout in emugl, which adds
207             // newlines of its own.
208             mFineLogFileHandle << entry.second;
209         }
210         mFineLogFileHandle.close();
211         if (!mFineLog.empty()) {
212             fprintf(stderr, "done\n");
213         }
214     }
215     mFineLog.clear();
216 }
217 
218 // C interface
219 
android_init_opengl_logger()220 void android_init_opengl_logger() {
221     OpenGLLogger::get();
222 }
223 
android_opengl_logger_set_flags(AndroidOpenglLoggerFlags flags)224 void android_opengl_logger_set_flags(AndroidOpenglLoggerFlags flags) {
225     OpenGLLogger::get()->setLoggerFlags(flags);
226 }
227 
android_opengl_logger_write(const char * fmt,...)228 void android_opengl_logger_write(const char* fmt, ...) {
229     char buf[kBufferLen] = {};
230     va_list ap;
231     va_start(ap, fmt);
232     vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
233     va_end(ap);
234     OpenGLLogger::get()->writeCoarse(buf);
235 }
236 
android_opengl_cxt_logger_write(const char * fmt,...)237 void android_opengl_cxt_logger_write(const char* fmt, ...) {
238     auto gl_log = OpenGLLogger::get();
239 
240     if (!gl_log->isFineLogging()) return;
241 
242     char buf[kBufferLen] = {};
243     va_list ap;
244     va_start(ap, fmt);
245     vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
246     va_end(ap);
247 
248     gl_log->writeFineTimestamped(buf);
249 }
250 
android_stop_opengl_logger()251 void android_stop_opengl_logger() {
252     OpenGLLogger* gl_log = OpenGLLogger::get();
253     gl_log->stop();
254 }
255