openpilot is an open source driver assistance system. openpilot performs the functions of Automated Lane Centering and Adaptive Cruise Control for over 200 supported car makes and models.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

347 lines
8.9 KiB

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <assert.h>
#include <time.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <pthread.h>
#include <bzlib.h>
#include <iostream>
#include <fstream>
#include <streambuf>
#ifdef QCOM
#include <cutils/properties.h>
#endif
#include "common/swaglog.h"
#include "common/params.h"
#include "common/util.h"
#include "common/version.h"
#include "messaging.hpp"
#include "logger.h"
// ***** logging helpers *****
void append_property(const char* key, const char* value, void *cookie) {
std::vector<std::pair<std::string, std::string> > *properties =
(std::vector<std::pair<std::string, std::string> > *)cookie;
properties->push_back(std::make_pair(std::string(key), std::string(value)));
}
int logger_mkpath(char* file_path) {
assert(file_path && *file_path);
char* p;
for (p=strchr(file_path+1, '/'); p; p=strchr(p+1, '/')) {
*p = '\0';
if (mkdir(file_path, 0777)==-1) {
if (errno != EEXIST) {
*p = '/';
return -1;
}
}
*p = '/';
}
return 0;
}
// ***** log metadata *****
void logger_build_boot(MessageBuilder &msg) {
auto boot = msg.initEvent().initBoot();
boot.setWallTimeNanos(nanos_since_epoch());
std::string lastKmsg = util::read_file("/sys/fs/pstore/console-ramoops");
boot.setLastKmsg(capnp::Data::Reader((const kj::byte*)lastKmsg.data(), lastKmsg.size()));
std::string lastPmsg = util::read_file("/sys/fs/pstore/pmsg-ramoops-0");
boot.setLastPmsg(capnp::Data::Reader((const kj::byte*)lastPmsg.data(), lastPmsg.size()));
std::string launchLog = util::read_file("/tmp/launch_log");
boot.setLaunchLog(capnp::Text::Reader(launchLog.data(), launchLog.size()));
}
void logger_build_init_data(MessageBuilder &msg) {
auto init = msg.initEvent().initInitData();
if (util::file_exists("/EON")) {
init.setDeviceType(cereal::InitData::DeviceType::NEO);
} else if (util::file_exists("/TICI")) {
init.setDeviceType(cereal::InitData::DeviceType::TICI);
} else {
init.setDeviceType(cereal::InitData::DeviceType::PC);
}
init.setVersion(capnp::Text::Reader(COMMA_VERSION));
std::ifstream cmdline_stream("/proc/cmdline");
std::vector<std::string> kernel_args;
std::string buf;
while (cmdline_stream >> buf) {
kernel_args.push_back(buf);
}
auto lkernel_args = init.initKernelArgs(kernel_args.size());
for (int i=0; i<kernel_args.size(); i++) {
lkernel_args.set(i, kernel_args[i]);
}
init.setKernelVersion(util::read_file("/proc/version"));
#ifdef QCOM
{
std::vector<std::pair<std::string, std::string> > properties;
property_list(append_property, (void*)&properties);
auto lentries = init.initAndroidProperties().initEntries(properties.size());
for (int i=0; i<properties.size(); i++) {
auto lentry = lentries[i];
lentry.setKey(properties[i].first);
lentry.setValue(properties[i].second);
}
}
#endif
const char* dongle_id = getenv("DONGLE_ID");
if (dongle_id) {
init.setDongleId(std::string(dongle_id));
}
init.setDirty(!getenv("CLEAN"));
// log params
Params params = Params();
init.setGitCommit(params.get("GitCommit"));
init.setGitBranch(params.get("GitBranch"));
init.setGitRemote(params.get("GitRemote"));
init.setPassive(params.read_db_bool("Passive"));
{
std::map<std::string, std::string> params_map;
params.read_db_all(&params_map);
auto lparams = init.initParams().initEntries(params_map.size());
int i = 0;
for (auto& kv : params_map) {
auto lentry = lparams[i];
lentry.setKey(kv.first);
lentry.setValue(kv.second);
i++;
}
}
}
void log_init_data(LoggerState *s) {
MessageBuilder msg;
logger_build_init_data(msg);
auto bytes = msg.toBytes();
logger_log(s, bytes.begin(), bytes.size(), s->has_qlog);
}
static void log_sentinel(LoggerState *s, cereal::Sentinel::SentinelType type) {
MessageBuilder msg;
auto sen = msg.initEvent().initSentinel();
sen.setType(type);
auto bytes = msg.toBytes();
logger_log(s, bytes.begin(), bytes.size(), true);
}
// ***** logging functions *****
void logger_init(LoggerState *s, const char* log_name, bool has_qlog) {
memset(s, 0, sizeof(*s));
umask(0);
pthread_mutex_init(&s->lock, NULL);
s->part = -1;
s->has_qlog = has_qlog;
time_t rawtime = time(NULL);
struct tm timeinfo;
localtime_r(&rawtime, &timeinfo);
strftime(s->route_name, sizeof(s->route_name),
"%Y-%m-%d--%H-%M-%S", &timeinfo);
snprintf(s->log_name, sizeof(s->log_name), "%s", log_name);
}
static LoggerHandle* logger_open(LoggerState *s, const char* root_path) {
int err;
LoggerHandle *h = NULL;
for (int i=0; i<LOGGER_MAX_HANDLES; i++) {
if (s->handles[i].refcnt == 0) {
h = &s->handles[i];
break;
}
}
assert(h);
snprintf(h->segment_path, sizeof(h->segment_path),
"%s/%s--%d", root_path, s->route_name, s->part);
snprintf(h->log_path, sizeof(h->log_path), "%s/%s.bz2", h->segment_path, s->log_name);
snprintf(h->qlog_path, sizeof(h->qlog_path), "%s/qlog.bz2", h->segment_path);
snprintf(h->lock_path, sizeof(h->lock_path), "%s.lock", h->log_path);
err = logger_mkpath(h->log_path);
if (err) return NULL;
FILE* lock_file = fopen(h->lock_path, "wb");
if (lock_file == NULL) return NULL;
fclose(lock_file);
h->log_file = fopen(h->log_path, "wb");
if (h->log_file == NULL) goto fail;
if (s->has_qlog) {
h->qlog_file = fopen(h->qlog_path, "wb");
if (h->qlog_file == NULL) goto fail;
}
int bzerror;
h->bz_file = BZ2_bzWriteOpen(&bzerror, h->log_file, 9, 0, 30);
if (bzerror != BZ_OK) goto fail;
if (s->has_qlog) {
h->bz_qlog = BZ2_bzWriteOpen(&bzerror, h->qlog_file, 9, 0, 30);
if (bzerror != BZ_OK) goto fail;
}
pthread_mutex_init(&h->lock, NULL);
h->refcnt++;
return h;
fail:
LOGE("logger failed to open files");
if (h->bz_file) {
BZ2_bzWriteClose(&bzerror, h->bz_file, 0, NULL, NULL);
h->bz_file = NULL;
}
if (h->bz_qlog) {
BZ2_bzWriteClose(&bzerror, h->bz_qlog, 0, NULL, NULL);
h->bz_qlog = NULL;
}
if (h->qlog_file) {
fclose(h->qlog_file);
h->qlog_file = NULL;
}
if (h->log_file) {
fclose(h->log_file);
h->log_file = NULL;
}
return NULL;
}
int logger_next(LoggerState *s, const char* root_path,
char* out_segment_path, size_t out_segment_path_len,
int* out_part) {
bool is_start_of_route = !s->cur_handle;
if (!is_start_of_route) log_sentinel(s, cereal::Sentinel::SentinelType::END_OF_SEGMENT);
pthread_mutex_lock(&s->lock);
s->part++;
LoggerHandle* next_h = logger_open(s, root_path);
if (!next_h) {
pthread_mutex_unlock(&s->lock);
return -1;
}
if (s->cur_handle) {
lh_close(s->cur_handle);
}
s->cur_handle = next_h;
if (out_segment_path) {
snprintf(out_segment_path, out_segment_path_len, "%s", next_h->segment_path);
}
if (out_part) {
*out_part = s->part;
}
pthread_mutex_unlock(&s->lock);
// write beggining of log metadata
log_init_data(s);
log_sentinel(s, is_start_of_route ? cereal::Sentinel::SentinelType::START_OF_ROUTE : cereal::Sentinel::SentinelType::START_OF_SEGMENT);
return 0;
}
LoggerHandle* logger_get_handle(LoggerState *s) {
pthread_mutex_lock(&s->lock);
LoggerHandle* h = s->cur_handle;
if (h) {
pthread_mutex_lock(&h->lock);
h->refcnt++;
pthread_mutex_unlock(&h->lock);
}
pthread_mutex_unlock(&s->lock);
return h;
}
void logger_log(LoggerState *s, uint8_t* data, size_t data_size, bool in_qlog) {
pthread_mutex_lock(&s->lock);
if (s->cur_handle) {
lh_log(s->cur_handle, data, data_size, in_qlog);
}
pthread_mutex_unlock(&s->lock);
}
void logger_close(LoggerState *s) {
log_sentinel(s, cereal::Sentinel::SentinelType::END_OF_ROUTE);
pthread_mutex_lock(&s->lock);
if (s->cur_handle) {
lh_close(s->cur_handle);
}
pthread_mutex_unlock(&s->lock);
}
void lh_log(LoggerHandle* h, uint8_t* data, size_t data_size, bool in_qlog) {
pthread_mutex_lock(&h->lock);
assert(h->refcnt > 0);
int bzerror;
BZ2_bzWrite(&bzerror, h->bz_file, data, data_size);
if (in_qlog && h->bz_qlog != NULL) {
BZ2_bzWrite(&bzerror, h->bz_qlog, data, data_size);
}
pthread_mutex_unlock(&h->lock);
}
void lh_close(LoggerHandle* h) {
pthread_mutex_lock(&h->lock);
assert(h->refcnt > 0);
h->refcnt--;
if (h->refcnt == 0) {
if (h->bz_file){
int bzerror;
BZ2_bzWriteClose(&bzerror, h->bz_file, 0, NULL, NULL);
h->bz_file = NULL;
}
if (h->bz_qlog){
int bzerror;
BZ2_bzWriteClose(&bzerror, h->bz_qlog, 0, NULL, NULL);
h->bz_qlog = NULL;
}
if (h->qlog_file) {
fclose(h->qlog_file);
h->qlog_file = NULL;
}
fclose(h->log_file);
h->log_file = NULL;
unlink(h->lock_path);
pthread_mutex_unlock(&h->lock);
pthread_mutex_destroy(&h->lock);
return;
}
pthread_mutex_unlock(&h->lock);
}