827 lines
18 KiB
C
827 lines
18 KiB
C
/******************************************************************************
|
|
*
|
|
* Copyright (C) 2021-2021 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.
|
|
*
|
|
******************************************************************************/
|
|
|
|
#define LOG_TAG "amlbt_fw"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <dirent.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/time.h>
|
|
#include <sys/poll.h>
|
|
#include <sys/syscall.h>
|
|
#include <sys/prctl.h>
|
|
#include <asm/ioctl.h>
|
|
|
|
#include <termios.h>
|
|
#include <time.h>
|
|
#include <zlib.h>
|
|
#include <pthread.h>
|
|
|
|
#include "amlbt_fwlog.h"
|
|
|
|
typedef struct {
|
|
uint32_t fsize; // Based on 1M multiples
|
|
uint32_t data_cnt;
|
|
uint32_t cur_data_cnt;
|
|
uint32_t files_max_cnt; // default gzip compress file number
|
|
uint32_t cur_files_cnt;
|
|
char fdir[FWLOG_DIR_MAX_SIZE];
|
|
char fpath[FWLOG_PATH_MAX_SIZE];
|
|
char fname_prefix[FWLOG_PREFIX_MAX_SIZE];
|
|
bool pcap_flag;
|
|
} fwlog_info;
|
|
|
|
// Structure to hold file-related information
|
|
typedef struct {
|
|
DIR* dir; // Directory pointer
|
|
char **files; // Array of file paths
|
|
int files_cnt; // Number of files
|
|
} files_info;
|
|
|
|
static fwlog_info fwlog_bt ={
|
|
.fsize = 100,
|
|
.data_cnt = 0,
|
|
.cur_data_cnt = 0,
|
|
.files_max_cnt = 10,
|
|
.cur_files_cnt = 1,
|
|
.fdir = DEFAULT_LOG_DIR,
|
|
.fpath = DEFAULT_FWLOG_PATH,
|
|
.fname_prefix = DEFAULT_LOG_FILE "_",
|
|
.pcap_flag = false,
|
|
};
|
|
|
|
static const int INVALID_FD = -1;
|
|
static int fwlog_fd = INVALID_FD;
|
|
|
|
static int32_t flag_gzip_start = 0;
|
|
// Add mutex definition
|
|
static pthread_mutex_t gzip_start_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
// Add Condition Variable Definition
|
|
static pthread_cond_t gzip_start_cond = PTHREAD_COND_INITIALIZER;
|
|
|
|
pthread_t gzip_thread;
|
|
|
|
static void get_time_stamp(char *buffer, size_t size)
|
|
{
|
|
time_t rawTime;
|
|
struct tm timeInfo;
|
|
|
|
// Get the current time
|
|
time(&rawTime);
|
|
|
|
// Convert to local time in a thread-safe way
|
|
if (localtime_r(&rawTime, &timeInfo) == NULL) {
|
|
// Clear the buffer if conversion fails
|
|
if (size > 0) {
|
|
buffer[0] = '\0';
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Format the time as "YYYYMMDDHHMMSS"
|
|
strftime(buffer, size, "%Y%m%d%H%M%S", &timeInfo);
|
|
}
|
|
|
|
static int mkdir_p(const char *path)
|
|
{
|
|
char tmp[256];
|
|
char *p = NULL;
|
|
size_t len;
|
|
|
|
snprintf(tmp, sizeof(tmp), "%s", path);
|
|
len = strlen(tmp);
|
|
|
|
if (tmp[len - 1] == '/')
|
|
tmp[len - 1] = 0;
|
|
|
|
for (p = tmp + 1; *p; p++) {
|
|
if (*p == '/') {
|
|
*p = 0;
|
|
if (mkdir(tmp, 0755) != 0) {
|
|
if (errno != EEXIST) {
|
|
ALOGE("mkdir:%s fail1 %s\n", tmp, strerror(errno));
|
|
return -1;
|
|
}
|
|
}
|
|
*p = '/';
|
|
}
|
|
}
|
|
|
|
if (mkdir(tmp, 0755) != 0) {
|
|
if (errno != EEXIST) {
|
|
ALOGE("mkdir:%s fail2 %s\n", tmp, strerror(errno));
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int fwlog_get_file_path(const char *file_path, char *fdir, size_t fdir_len,
|
|
char *fname, size_t fname_len)
|
|
{
|
|
if (!file_path || (!*file_path)) {
|
|
ALOGE("Invalid fwlog path");
|
|
return -1;
|
|
}
|
|
|
|
int ret = snprintf(fdir, fdir_len, "%s", file_path);
|
|
if (ret < 0 || (size_t)ret >= fdir_len) {
|
|
ALOGE("Out buffer too small");
|
|
return -1;
|
|
}
|
|
|
|
char *last_slash = strrchr(fdir, '/');
|
|
if (!last_slash) {
|
|
ALOGE("Invalid path, no slash");
|
|
fdir[0] = '\0';
|
|
return -1;
|
|
}
|
|
|
|
if (*(last_slash + 1) != '\0') {
|
|
snprintf(fname, fname_len, "%s", last_slash + 1);
|
|
} else {
|
|
snprintf(fname, fname_len, "%s", DEFAULT_LOG_FILE);
|
|
}
|
|
|
|
*(last_slash + 1) = '\0';
|
|
|
|
return 0;
|
|
}
|
|
|
|
int fwlog_set_path(const char *new_path)
|
|
{
|
|
int ret;
|
|
char tmp_dir[FWLOG_DIR_MAX_SIZE];
|
|
char tmp_file[FWLOG_NAME_MAX_SIZE];
|
|
|
|
if (!new_path) {
|
|
ALOGE("Invalid parameter");
|
|
return -1;
|
|
}
|
|
|
|
ret = fwlog_get_file_path(new_path, tmp_dir, sizeof(tmp_dir), tmp_file, sizeof(tmp_file));
|
|
if (ret) {
|
|
ALOGE("Invalid path");
|
|
return -1;
|
|
}
|
|
|
|
strcpy(fwlog_bt.fdir,tmp_dir);
|
|
|
|
ret = snprintf(fwlog_bt.fpath, sizeof(fwlog_bt.fpath), "%s%s", fwlog_bt.fdir, tmp_file);
|
|
if (ret < 0 || (size_t)ret >= sizeof(fwlog_bt.fpath)) {
|
|
ALOGE("fpath too long");
|
|
return -1;
|
|
}
|
|
|
|
ret = snprintf(fwlog_bt.fname_prefix, sizeof(fwlog_bt.fname_prefix), "%s_", tmp_file);
|
|
if (ret < 0 || (size_t)ret >= sizeof(fwlog_bt.fname_prefix)) {
|
|
ALOGE("fname_prefix too long");
|
|
return -1;
|
|
}
|
|
|
|
ALOGI("fdir:%s fpath:%s fname_prefix:%s",fwlog_bt.fdir, fwlog_bt.fpath, \
|
|
fwlog_bt.fname_prefix);
|
|
|
|
fwlog_pcap_flag_set(true);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void fwlog_write_hex_data(int fd, const uint8_t *data,
|
|
size_t data_len, size_t start_idx)
|
|
{
|
|
if (fd < 0 || data == NULL || start_idx >= data_len)
|
|
return;
|
|
|
|
struct timeval tv;
|
|
struct tm tm;
|
|
char header[64];
|
|
char line[512];
|
|
size_t pos = 0;
|
|
|
|
gettimeofday(&tv, NULL);
|
|
localtime_r(&tv.tv_sec, &tm);
|
|
|
|
strftime(header, sizeof(header), "%Y-%m-%d %H:%M:%S", &tm);
|
|
|
|
pos += snprintf(line + pos, sizeof(line) - pos, "%s.%06ld ",
|
|
header, (long)tv.tv_usec);
|
|
|
|
for (size_t i = start_idx; i < data_len && pos + 3 < sizeof(line); i++)
|
|
pos += snprintf(line + pos, sizeof(line) - pos, "%02x ", data[i]);
|
|
|
|
dprintf(fd, "%s", line);
|
|
}
|
|
|
|
static int fwlog_compare_file_num(const char* file1, const char* file2)
|
|
{
|
|
char number1[FWLOG_NAME_MAX_SIZE] = {0};
|
|
char number2[FWLOG_NAME_MAX_SIZE] = {0};
|
|
|
|
sscanf(file1 + strlen(fwlog_bt.fname_prefix), "%s", number1);
|
|
sscanf(file2 + strlen(fwlog_bt.fname_prefix), "%s", number2);
|
|
|
|
long long num1 = atoll(number1);
|
|
long long num2 = atoll(number2);
|
|
|
|
return (num1 < num2) ? -1 : (num1 > num2) ? 1 : 0;
|
|
}
|
|
|
|
static int fwlog_qsort_compare(const void *a, const void *b) {
|
|
return fwlog_compare_file_num(*(const char **)a, *(const char **)b);
|
|
}
|
|
|
|
static void fwlog_relog_file(void)
|
|
{
|
|
DIR* dir = NULL;
|
|
struct dirent *entry;
|
|
int maxNum = -1;
|
|
char rename_fpath[FWLOG_PATH_MAX_SIZE];
|
|
|
|
dir = opendir(fwlog_bt.fdir);
|
|
if (!dir) {
|
|
ALOGE("opendir:%s fail %s\n", fwlog_bt.fdir, strerror(errno));
|
|
return;
|
|
}
|
|
|
|
while ((entry = readdir(dir)) != NULL) {
|
|
const char *filename = entry->d_name;
|
|
|
|
if (strncmp(filename, fwlog_bt.fname_prefix, strlen(fwlog_bt.fname_prefix)) != 0) {
|
|
continue;
|
|
}
|
|
|
|
const char *numPart = filename + strlen(fwlog_bt.fname_prefix);
|
|
size_t len = strlen(numPart);
|
|
const size_t gz_len = strlen(".gz");
|
|
|
|
if (len <= gz_len) {
|
|
continue;
|
|
}
|
|
|
|
if (strcmp(numPart + len - gz_len, ".gz") != 0) {
|
|
continue;
|
|
}
|
|
|
|
if (len - gz_len >= FWLOG_NAME_MAX_SIZE) {
|
|
ALOGE("Filename too long: %s", filename);
|
|
continue;
|
|
}
|
|
|
|
char numStr[FWLOG_NAME_MAX_SIZE];
|
|
strncpy(numStr, numPart, len - gz_len);
|
|
numStr[len - gz_len] = '\0';
|
|
|
|
int num = 0;
|
|
if (sscanf(numStr, "%d", &num) == 1) {
|
|
if (num > maxNum) {
|
|
ALOGD("maxNum: %d", maxNum);
|
|
maxNum = num;
|
|
}
|
|
}
|
|
}
|
|
|
|
closedir(dir);
|
|
|
|
if (maxNum > 0) {
|
|
fwlog_bt.cur_files_cnt = maxNum + 1;
|
|
} else {
|
|
fwlog_bt.cur_files_cnt = 1;
|
|
}
|
|
|
|
if (fwlog_fd != INVALID_FD) {
|
|
close(fwlog_fd);
|
|
fwlog_fd = INVALID_FD;
|
|
}
|
|
|
|
snprintf(rename_fpath, sizeof(rename_fpath), "%s_%u", fwlog_bt.fpath, fwlog_bt.cur_files_cnt);
|
|
ALOGI("cur_files_cnt:%u rename_fpath: %s", fwlog_bt.cur_files_cnt, rename_fpath);
|
|
|
|
if (rename(fwlog_bt.fpath, rename_fpath) != 0) {
|
|
if (errno != ENOENT) {
|
|
ALOGE("rename to %s fail, errno: %s", rename_fpath, strerror(errno));
|
|
}
|
|
}
|
|
|
|
mode_t prev_mask = umask(0);
|
|
fwlog_fd = open(fwlog_bt.fpath, O_WRONLY | O_CREAT | O_TRUNC,
|
|
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
|
|
umask(prev_mask);
|
|
|
|
if (fwlog_fd == INVALID_FD) {
|
|
ALOGE("open :%s fail", fwlog_bt.fpath);
|
|
}
|
|
}
|
|
|
|
static void fwlog_update_file(void)
|
|
{
|
|
files_info res = {NULL, NULL, 0};
|
|
|
|
fwlog_relog_file();
|
|
|
|
res.dir = opendir(fwlog_bt.fdir);
|
|
if (!res.dir) {
|
|
ALOGE("opendir:%s fail %s\n", fwlog_bt.fdir, strerror(errno));
|
|
return;
|
|
}
|
|
|
|
struct dirent* entry;
|
|
while ((entry = readdir(res.dir)) != NULL) {
|
|
if (strncmp(entry->d_name, fwlog_bt.fname_prefix,
|
|
strlen(fwlog_bt.fname_prefix)) == 0) {
|
|
char **tmp = realloc(res.files, (res.files_cnt + 1) * sizeof(char *));
|
|
if (!tmp) {
|
|
ALOGE("realloc failed");
|
|
// Free already allocated memory
|
|
for (int i = 0; i < res.files_cnt; i++) {
|
|
free(res.files[i]);
|
|
}
|
|
free(res.files);
|
|
res.files = NULL;
|
|
break;
|
|
}
|
|
res.files = tmp;
|
|
|
|
res.files[res.files_cnt] = strdup(entry->d_name);
|
|
if (!res.files[res.files_cnt]) {
|
|
ALOGE("strdup failed");
|
|
// Free already allocated memory
|
|
for (int i = 0; i < res.files_cnt; i++) {
|
|
free(res.files[i]);
|
|
}
|
|
free(res.files);
|
|
res.files = NULL;
|
|
res.files_cnt = 0;
|
|
break;
|
|
}
|
|
res.files_cnt++;
|
|
}
|
|
}
|
|
|
|
closedir(res.dir);
|
|
res.dir = NULL;
|
|
|
|
ALOGI("files_max_cnt:%u files_cnt:%d", fwlog_bt.files_max_cnt, res.files_cnt);
|
|
|
|
if (res.files_cnt > fwlog_bt.files_max_cnt) {
|
|
int deleteCnt = res.files_cnt - fwlog_bt.files_max_cnt;
|
|
qsort(res.files, res.files_cnt, sizeof(char *), fwlog_qsort_compare);
|
|
|
|
for (int i = 0; i < deleteCnt; i++) {
|
|
char oldestFile[FWLOG_PATH_MAX_SIZE];
|
|
snprintf(oldestFile, sizeof(oldestFile), "%s/%s", fwlog_bt.fdir, res.files[i]);
|
|
remove(oldestFile);
|
|
ALOGI("Removing %s", oldestFile);
|
|
free(res.files[i]); // Released
|
|
}
|
|
|
|
// Use memmove to move the back forward
|
|
memmove(res.files, res.files + deleteCnt, (res.files_cnt - deleteCnt) * sizeof(char *));
|
|
res.files_cnt -= deleteCnt;
|
|
}
|
|
|
|
for (int i = 0; i < res.files_cnt; i++) {
|
|
free(res.files[i]); // The remaining release
|
|
}
|
|
free(res.files);
|
|
|
|
pthread_mutex_lock(&gzip_start_mutex);
|
|
flag_gzip_start = 1;
|
|
pthread_cond_signal(&gzip_start_cond);
|
|
pthread_mutex_unlock(&gzip_start_mutex);
|
|
}
|
|
|
|
static int fwlog_gzip_rename(void)
|
|
{
|
|
files_info res = {NULL, NULL, 0};
|
|
int ret = -1;
|
|
char tmp_path[FWLOG_PATH_MAX_SIZE];
|
|
|
|
res.dir = opendir(fwlog_bt.fdir);
|
|
if (!res.dir) {
|
|
ALOGE("opendir:%s fail %s\n", fwlog_bt.fdir, strerror(errno));
|
|
return ret;
|
|
}
|
|
|
|
struct dirent *entry;
|
|
while ((entry = readdir(res.dir)) != NULL) {
|
|
if (strncmp(entry->d_name, fwlog_bt.fname_prefix, strlen(fwlog_bt.fname_prefix)) == 0) {
|
|
char **tmp = realloc(res.files, (res.files_cnt + 1) * sizeof(char *));
|
|
if (!tmp) {
|
|
ALOGE("realloc failed");
|
|
goto cleanup;
|
|
}
|
|
res.files = tmp;
|
|
|
|
res.files[res.files_cnt] = strdup(entry->d_name);
|
|
if (!res.files[res.files_cnt]) {
|
|
ALOGE("strdup failed");
|
|
goto cleanup;
|
|
}
|
|
res.files_cnt++;
|
|
}
|
|
}
|
|
|
|
closedir(res.dir);
|
|
res.dir = NULL;
|
|
|
|
ALOGI("files_cnt: %d", res.files_cnt);
|
|
|
|
if (res.files_cnt == 0) {
|
|
ret = 0;
|
|
goto cleanup;
|
|
}
|
|
|
|
qsort(res.files, res.files_cnt, sizeof(char *), fwlog_qsort_compare);
|
|
|
|
// Step 1: rename old files to tmp
|
|
for (int i = 0; i < res.files_cnt; i++) {
|
|
char old_path[FWLOG_PATH_MAX_SIZE];
|
|
snprintf(old_path, sizeof(old_path), "%s%s", fwlog_bt.fdir, res.files[i]);
|
|
snprintf(tmp_path, sizeof(tmp_path), "%s%s.tmp", fwlog_bt.fdir, res.files[i]);
|
|
|
|
if (rename(old_path, tmp_path) != 0) {
|
|
ALOGE("Rename %s to %s fail, errno: %s", old_path, tmp_path, strerror(errno));
|
|
goto cleanup;
|
|
}
|
|
|
|
char *new_name = strdup(tmp_path);
|
|
if (!new_name) {
|
|
ALOGE("strdup failed for tmp_path");
|
|
goto cleanup;
|
|
}
|
|
|
|
free(res.files[i]);
|
|
res.files[i] = new_name;
|
|
}
|
|
|
|
// Step 2: rename tmp to new name with index
|
|
for (int i = 0; i < res.files_cnt; i++) {
|
|
snprintf(tmp_path, sizeof(tmp_path), "%s%s%d.gz",
|
|
fwlog_bt.fdir, fwlog_bt.fname_prefix, i + 1);
|
|
|
|
if (rename(res.files[i], tmp_path) != 0) {
|
|
ALOGE("Rename %s to %s fail, errno: %s", res.files[i], tmp_path, strerror(errno));
|
|
goto cleanup;
|
|
}
|
|
ALOGI("Renamed to %s", tmp_path);
|
|
}
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
if (res.dir)
|
|
closedir(res.dir);
|
|
|
|
if (res.files) {
|
|
for (int i = 0; i < res.files_cnt; i++) {
|
|
free(res.files[i]);
|
|
}
|
|
free(res.files);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int fwlog_gzip_compress(const char* input_path, const char* output_path)
|
|
{
|
|
FILE* source = NULL;
|
|
gzFile dest = NULL;
|
|
unsigned char buffer[4096] = {0};
|
|
int num_read = 0, num_write = 0;
|
|
mode_t prev_mask;
|
|
int ret = 0;
|
|
|
|
prev_mask = umask(002);
|
|
ALOGI("start compress: %s -> %s", input_path, output_path);
|
|
|
|
source = fopen(input_path, "rb");
|
|
if (!source) {
|
|
ALOGE("fopen: %s fail: %s", input_path, strerror(errno));
|
|
umask(prev_mask);
|
|
return -1;
|
|
}
|
|
|
|
dest = gzopen(output_path, "wb");
|
|
if (!dest) {
|
|
ALOGE("gzopen: %s fail: %s", output_path, strerror(errno));
|
|
fclose(source);
|
|
umask(prev_mask);
|
|
return -1;
|
|
}
|
|
|
|
umask(prev_mask);
|
|
|
|
while ((num_read = fread(buffer, 1, sizeof(buffer), source)) > 0) {
|
|
num_write = gzwrite(dest, buffer, num_read);
|
|
if (num_write == 0) {
|
|
int errnum = 0;
|
|
const char* msg = gzerror(dest, &errnum);
|
|
ALOGE("gzwrite failed: %s", msg);
|
|
ret = -1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ferror(source)) {
|
|
ALOGE("fread error: %s", strerror(errno));
|
|
ret = -1;
|
|
}
|
|
|
|
fclose(source);
|
|
gzclose(dest);
|
|
|
|
ALOGI("finish compress: %s", ret == 0 ? "OK" : "FAIL");
|
|
return ret;
|
|
}
|
|
|
|
// Thread cleanup function, used to release resources when the thread is canceled
|
|
static void fwlog_thread_cleanup(void *arg)
|
|
{
|
|
files_info *res = (files_info *)arg;
|
|
|
|
// Close directory
|
|
if (res->dir) {
|
|
closedir(res->dir);
|
|
res->dir = NULL;
|
|
}
|
|
|
|
// Free log files
|
|
if (res->files) {
|
|
for (int i = 0; i < res->files_cnt; i++) {
|
|
free(res->files[i]);
|
|
}
|
|
free(res->files);
|
|
res->files = NULL;
|
|
res->files_cnt = 0;
|
|
}
|
|
|
|
// Release mutex to prevent deadlock
|
|
if (pthread_mutex_trylock(&gzip_start_mutex) == 0) {
|
|
pthread_mutex_unlock(&gzip_start_mutex);
|
|
}
|
|
|
|
ALOGI("thread cleanup done");
|
|
}
|
|
|
|
|
|
static void *fwlog_gzip_compress_thread(void *arg)
|
|
{
|
|
(void)arg;
|
|
|
|
struct dirent *entry;
|
|
files_info res = {NULL, NULL, 0};
|
|
|
|
// Set thread cleanup function
|
|
pthread_cleanup_push(fwlog_thread_cleanup, (void*)&res);
|
|
|
|
ALOGI("start");
|
|
|
|
while (1) {
|
|
pthread_mutex_lock(&gzip_start_mutex);
|
|
while (!flag_gzip_start) {
|
|
pthread_cond_wait(&gzip_start_cond, &gzip_start_mutex);
|
|
}
|
|
pthread_mutex_unlock(&gzip_start_mutex);
|
|
|
|
ALOGI("gzip compress files start");
|
|
|
|
// Free previous log files
|
|
if (res.files) {
|
|
for (int i = 0; i < res.files_cnt; i++) {
|
|
free(res.files[i]);
|
|
}
|
|
free(res.files);
|
|
res.files = NULL;
|
|
res.files_cnt = 0;
|
|
}
|
|
|
|
res.dir = opendir(fwlog_bt.fdir);
|
|
if (!res.dir) {
|
|
ALOGE("opendir failed");
|
|
goto compress_exit;
|
|
}
|
|
|
|
while ((entry = readdir(res.dir)) != NULL) {
|
|
size_t len = strlen(entry->d_name);
|
|
if (strncmp(entry->d_name, fwlog_bt.fname_prefix,
|
|
strlen(fwlog_bt.fname_prefix)) == 0 &&
|
|
!(len >= 3 && strcmp(entry->d_name + len - 3, ".gz") == 0)) {
|
|
|
|
char **tmp = realloc(res.files, (res.files_cnt + 1) * sizeof(char *));
|
|
if (!tmp) {
|
|
ALOGE("realloc failed");
|
|
goto compress_exit;
|
|
}
|
|
res.files = tmp;
|
|
|
|
res.files[res.files_cnt] = strdup(entry->d_name);
|
|
if (!res.files[res.files_cnt]) {
|
|
ALOGE("strdup failed");
|
|
goto compress_exit;
|
|
}
|
|
res.files_cnt++;
|
|
}
|
|
}
|
|
closedir(res.dir);
|
|
res.dir = NULL;
|
|
|
|
for (int i = 0; i < res.files_cnt; ) {
|
|
char Filename[FWLOG_PATH_MAX_SIZE];
|
|
char gFilename[FWLOG_PATH_MAX_SIZE];
|
|
|
|
snprintf(Filename, sizeof(Filename), "%s%s%s", fwlog_bt.fdir,
|
|
(fwlog_bt.fdir[strlen(fwlog_bt.fdir) - 1] == '/') ? "" : "/", res.files[i]);
|
|
|
|
snprintf(gFilename, sizeof(gFilename), "%s.gz", Filename);
|
|
|
|
ALOGI("Compress in: %s, out: %s", Filename, gFilename);
|
|
|
|
if (!fwlog_gzip_compress(Filename, gFilename)) {
|
|
if (remove(Filename) == 0) {
|
|
free(res.files[i]);
|
|
memmove(res.files + i, res.files + i + 1, (res.files_cnt - i - 1) * sizeof(char *));
|
|
res.files_cnt--;
|
|
} else {
|
|
ALOGE("Remove fail: %s", Filename);
|
|
i++;
|
|
}
|
|
} else {
|
|
ALOGE("Compress fail: %s", Filename);
|
|
remove(gFilename);
|
|
i++;
|
|
}
|
|
}
|
|
|
|
fwlog_gzip_rename();
|
|
|
|
compress_exit:
|
|
if (res.dir) {
|
|
closedir(res.dir);
|
|
res.dir = NULL;
|
|
}
|
|
|
|
if (res.files) {
|
|
for (int i = 0; i < res.files_cnt; i++) {
|
|
free(res.files[i]);
|
|
}
|
|
free(res.files);
|
|
res.files = NULL;
|
|
res.files_cnt = 0;
|
|
}
|
|
|
|
pthread_mutex_lock(&gzip_start_mutex);
|
|
flag_gzip_start = 0;
|
|
pthread_mutex_unlock(&gzip_start_mutex);
|
|
|
|
sleep(1);
|
|
}
|
|
|
|
ALOGI("finish");
|
|
|
|
// Pop-up cleanup function
|
|
pthread_cleanup_pop(1);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void fwlog_set_size(uint16_t val)
|
|
{
|
|
fwlog_bt.fsize = val;
|
|
}
|
|
|
|
void fwlog_set_cnt(uint16_t val)
|
|
{
|
|
fwlog_bt.files_max_cnt = val;
|
|
}
|
|
|
|
void fwlog_pcap_flag_set(bool val)
|
|
{
|
|
fwlog_bt.pcap_flag = val;
|
|
}
|
|
|
|
bool fwlog_pcap_flag_get(void)
|
|
{
|
|
return fwlog_bt.pcap_flag;
|
|
}
|
|
|
|
void fwlog_init(void)
|
|
{
|
|
bool pcap_flag = fwlog_pcap_flag_get();
|
|
if (!pcap_flag) {
|
|
ALOGI("flag=%d, exit", pcap_flag);
|
|
return;
|
|
}
|
|
|
|
if (mkdir_p(fwlog_bt.fdir)) {
|
|
ALOGE("mkdir_p fail");
|
|
return;
|
|
}
|
|
|
|
ALOGI("fsize:%u data_cnt:%u files_max_cnt:%u cur_data_cnt:%u", fwlog_bt.fsize, \
|
|
fwlog_bt.data_cnt, fwlog_bt.files_max_cnt, fwlog_bt.cur_data_cnt);
|
|
|
|
if (pthread_create(&gzip_thread, NULL, fwlog_gzip_compress_thread, NULL) != 0) {
|
|
ALOGE("gzip_thread pthread_create fail");
|
|
} else {
|
|
//pthread_setname_np(gzip_thread, "bt_fwlog_gzip");
|
|
prctl(PR_SET_NAME, "bt_fwlog_gzip", 0,0,0);
|
|
}
|
|
|
|
fwlog_update_file();
|
|
}
|
|
|
|
void fwlog_close (void)
|
|
{
|
|
bool pcap_flag = fwlog_pcap_flag_get();
|
|
if (!pcap_flag) {
|
|
ALOGI("flag=%d, exit", pcap_flag);
|
|
return;
|
|
} else {
|
|
ALOGI();
|
|
}
|
|
|
|
if (fwlog_fd != INVALID_FD) {
|
|
close(fwlog_fd);
|
|
fwlog_fd = INVALID_FD;
|
|
}
|
|
|
|
// Cancel gzip thread
|
|
if (pthread_cancel(gzip_thread) != 0) {
|
|
ALOGE("pthread_cancel failed");
|
|
} else {
|
|
// Wait for thread to finish
|
|
if (pthread_join(gzip_thread, NULL) != 0) {
|
|
ALOGE("pthread_join failed");
|
|
} else {
|
|
ALOGI("gzip_thread exit successful");
|
|
}
|
|
}
|
|
|
|
// Destroy mutex and condition variable
|
|
pthread_mutex_destroy(&gzip_start_mutex);
|
|
pthread_cond_destroy(&gzip_start_cond);
|
|
}
|
|
|
|
void fwlog_handle_signal(int sig)
|
|
{
|
|
ALOGD();
|
|
fwlog_close();
|
|
|
|
exit(0);
|
|
}
|
|
|
|
void fwlog_record(const uint8_t* data, uint32_t data_len)
|
|
{
|
|
if (!fwlog_pcap_flag_get()) {
|
|
return;
|
|
}
|
|
|
|
if (fwlog_fd == INVALID_FD) {
|
|
ALOGE("invalid fwlog_fd");
|
|
return;
|
|
}
|
|
|
|
uint32_t one_pkg_size = 0;
|
|
|
|
// Need to remove three bytes, event code + command code + data len
|
|
fwlog_write_hex_data(fwlog_fd, data, (data_len - 2), 2);
|
|
fwlog_bt.cur_data_cnt++;
|
|
|
|
ALOGD("fsize:%u", fwlog_bt.fsize);
|
|
|
|
one_pkg_size = (data_len - 2) * 3 + 27; // 27:time tag len
|
|
fwlog_bt.data_cnt = (fwlog_bt.fsize * 1024 * 1024) / one_pkg_size;
|
|
|
|
ALOGD("one_pkg_size:%u data_cnt:%u cur_data_cnt:%u", one_pkg_size, \
|
|
fwlog_bt.data_cnt, fwlog_bt.cur_data_cnt);
|
|
|
|
if (fwlog_bt.cur_data_cnt >= fwlog_bt.data_cnt) {
|
|
fwlog_update_file();
|
|
fwlog_bt.cur_data_cnt = 0;
|
|
}
|
|
}
|