/* * Copyright (C) 2024 Amlogic Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #ifdef DISPLAY_LOGLIB #include #endif #include "DispAdptLog.h" #include "MesonTypes.h" typedef struct log_info { int active_level; // debug log level FILE *print_out; // log output file FILE *trace_file; // trace output file bool alog; // output log to logcat int trace_to_log; // trace output to logcat int di_number; // di number int di_log; // enable di log } log_info_t; log_info_t g_log = { .active_level = DEFAULT_LOG_LEVEL, .print_out = NULL, .trace_file = NULL, .alog = true, .trace_to_log = 0, .di_number = -1, .di_log = -1, }; log_info_t *getLogInfo() { return &g_log; } FILE *getDebugFile() { log_info_t *log = getLogInfo(); if (!log->print_out) return stderr; return log->print_out; } long long DispAdptGetCurrentTime(void) { long long utcCurrentTimeMillis; timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); utcCurrentTimeMillis = ts.tv_sec * 1000LL + ts.tv_nsec / 1000000LL; return utcCurrentTimeMillis; } long long DispAdptGetCurrentTimeUs(void) { long long utcCurrentTimeUs; timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); utcCurrentTimeUs = ts.tv_sec * 1000000LL + ts.tv_nsec / 1000LL; return utcCurrentTimeUs; } static void FilePrint(FILE *f, const char* fmt, va_list args) { if (f == NULL) return; fprintf(f, "%lld: pid: %d ", DispAdptGetCurrentTime(), getpid()); vfprintf(f, fmt, args); fflush(f); } #ifdef DISPLAY_LOGLIB void LogPrint(FILE *f, bool alog, const char* fmt, va_list args) { if (alog) { DispAdptLogPrint(ANDROID_LOG_INFO, DISPLAY_TAG, fmt, args); } else { FilePrint(f, fmt, args); } } #else void LogPrint(FILE *f, bool alog, const char* fmt, va_list args) { (void)alog; FilePrint(f, fmt, args); } #endif void DispAdptLog(int level, const char *fmt, ...) { log_info_t *log = getLogInfo(); if (log && level <= log->active_level) { va_list argptr; va_start(argptr, fmt); LogPrint(getDebugFile(), log->alog, fmt, argptr); va_end(argptr); } } void TracePrint(const char *fmt, ...) { log_info_t *log = getLogInfo(); if (log == NULL) return; va_list argptr; va_start(argptr, fmt); LogPrint(log->trace_file, log->trace_to_log, fmt, argptr); va_end(argptr); } void reset() { log_info_t *log = getLogInfo(); log->active_level = DEFAULT_LOG_LEVEL; log->di_number = -1; log->di_log = -1; log->alog = true; if (log->print_out) fclose(log->print_out); log->print_out = NULL; } void DispAdptLogInit() { char buf[MESON_MAX_STR_LEN] = { 0 }; char path[MESON_MAX_STR_LEN] = { 0 }; log_info_t *log = getLogInfo(); snprintf(path, sizeof(path), "%s/%s", ADPT_LISTENER_DIR, DEBUG_LOG); if (DispAdptReadFile(path, buf, true, MESON_MAX_STR_LEN) == 0) { reset(); DispAdptDebugSetting(buf); } const char *env = getenv("DISPLAY_DEBUG_FILE"); if (env && log->print_out == NULL) { if (!strcmp(env, "stdout")) log->print_out = stdout; else log->print_out = fopen(env, "w"); } if (log->active_level < 0) log->active_level = DEFAULT_LOG_LEVEL; env = getenv("DISPLAY_DEBUG"); if (env) { log->active_level = atoi(env); } } int DispAdptReadFile(const char *path, char *val, bool original, int valSize) { char buf[MESON_MAX_STR_LEN] = { 0 }; int fd, len; if ((fd = open(path, O_RDONLY)) < 0) { DISPLAY_LOGE("open %s fail. Error info [%s]", path, strerror(errno)); return -errno; } len = read(fd, buf, MESON_MAX_STR_LEN - 1); close(fd); if (len < 0) { DISPLAY_LOGE("read error: %s, %s\n", path, strerror(errno)); return -errno; } if (!original) { int i, j; for (i = 0, j = 0; i <= len - 1; i++) { /* * change '\0' to 0x20(spacing), otherwise the string buffer will be cut off * if the last char is '\0' should not replace it */ if (0x0 == buf[i] && i < len - 1) { buf[i] = 0x20; DISPLAY_LOGD("read buffer index:%d is a 0x0, replace to spacing \n", i); } /* delete all the character of '\n' and '\r'*/ if (0x0a != buf[i] && 0x0d != buf[i]) { buf[j++] = buf[i]; } } buf[j] = 0x0; } DISPLAY_LOGD("read %s, result length:%d, val:%s\n", path, len, buf); strncpy(val, buf, valSize); return 0; } int DispAdptWriteFile(const char *path, const char *val) { int fd; if ((fd = open(path, O_RDWR)) < 0) { DISPLAY_LOGE("open %s fail. Error info [%s]", path, strerror(errno)); return -errno; } DISPLAY_LOGD("%s: write (%s) to file (%s)", __func__, val, path); if (write(fd, val, strlen(val)) != (int)strlen(val)) DISPLAY_LOGE("write %s failed!\n", path); close(fd); return 0; } int DispAdptGetDiNumber() { log_info_t *log = getLogInfo(); return log->di_number; } int DispAdptGetDiLog() { log_info_t *log = getLogInfo(); return log->di_log; } std::unordered_map parseKeyValue(const std::string& input) { std::unordered_map result; std::stringstream ss(input); std::string key, value; std::string kvPair; while (ss >> kvPair) { size_t eqPos = kvPair.find('='); if (eqPos != std::string::npos) { key = kvPair.substr(0, eqPos); value = kvPair.substr(eqPos + 1); result[key] = value; } } return result; } int DispAdptDebugSetting(char *content) { auto parsed = parseKeyValue(content); log_info_t *log = getLogInfo(); for (const auto& pair : parsed) { if (pair.first == "DISPLAY_DEBUG") log->active_level = atoi(pair.second.c_str()); if (pair.first == "DISPLAY_DEBUG_FILE") { if (log->print_out == NULL) log->print_out = fopen(pair.second.c_str(), "a"); } if (pair.first == "DI_NUMBER") log->di_number = atoi(pair.second.c_str()); if (pair.first == "DI_LOG") log->di_log = atoi(pair.second.c_str()); if (pair.first == "ALOG") log->alog = atoi(pair.second.c_str()) > 0 ? true : false; if (pair.first == "TRACE") log->trace_to_log = atoi(pair.second.c_str()) > 1 ? true : false; if (pair.first == "TRACE_FILE") log->trace_file = fopen(pair.second.c_str(), "w"); } return 0; } void DispAdptLogDestroy() { log_info_t *log = getLogInfo(); if (log != NULL) { if (log->print_out) fclose(log->print_out); log->print_out = NULL; if (log->trace_file) fclose(log->trace_file); log->trace_file = NULL; } } #ifdef DISPLAY_LOGLIB void DispAdptLogPrint(int prio, const char* tag, const char* fmt, va_list args) { char buf[1024]; int len; len = snprintf(buf, sizeof(buf), "[%lld] ", DispAdptGetCurrentTime()); len = vsnprintf(buf + len, sizeof(buf) - len, fmt, args); if (len >= 0 && len < (int)sizeof(buf)) __android_log_print(prio, tag, "%s", buf); else __android_log_print(prio, tag, "[TRUNCATED]%s", buf); } #endif