blob: 10ba0f0157309a78aa022c81a976d8497f6e7e58 [file] [log] [blame]
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <pthread.h>
#include <sys/sysinfo.h>
#include <sys/prctl.h>
#include <cutils/properties.h>
#include "hawk_lib.h"
#include "hawk_api.h"
#include "hawk_sender.h"
#include "hawk_statistics.h"
#include "hawk_rild.h"
#define HAWK_TIMESTAMP_DELTA 120 /* time in seconds between time from boot update */
#define HAWK_FIFO_TIMEOUT (60*60*12) /* time in seconds (12 hours) */
#define HAWK_STARTUP TEL_DIR "hawk_startup.sh"
#define HAWK_CHECK_DATA TEL_DIR "hawk_check_data.sh"
#define HAWK_CHECK_DATA_DELTA (60*60) /* time in seconds (1 hour) */
extern struct hawk_object g_hawk;
extern struct ml_fifo fifo;
static __attribute__ ((noreturn))
void *hawk_worker( __attribute__ ((unused))
void *ptr)
{
struct hawk_msg *msg = NULL;
prctl(PR_SET_NAME, "hawk_worker");
while (1) {
/* pthread_cond_wait will first unlock and then lock the mutex */
pthread_mutex_lock(&g_hawk.cond_mutex);
while (list_empty(&g_hawk.msgq_head)) {
pthread_cond_wait(&g_hawk.cond, &g_hawk.cond_mutex);
}
msg = list_entry(g_hawk.msgq_head.next, struct hawk_msg, list);
list_del_init(g_hawk.msgq_head.next);
g_hawk.q_item_count--;
pthread_mutex_unlock(&g_hawk.cond_mutex);
if (msg == NULL)
continue;
sprintf(msg->msg_info.event_dir, "%s/hawk_default_dir", hawk_dir);
/*check and update missed messages */
hawk_mark_messages_as_offline();
/* process message and release the buffer */
switch (msg->msg_info.status) {
case HAWK_STATUS_LOGS_READY:
{
///
/// ADD LOGS + HAWK_SPY
///
unsigned long long free_space;
if (msg->msg_info.event_id[0] == 0) {
struct ml_uniqid uid;
sprintf(msg->msg_info.event_id, "%s", ml_get_uniqid(&uid));
}
sprintf(msg->msg_info.event_dir, "%s/%s", hawk_dir, msg->msg_info.event_id);
if (!ml_dir_update(hawk_dir))
break;
if (!ml_dir_update(msg->msg_info.event_dir))
break;
if (msg->msg_info.event_type == HAWK_EVENT_ASSERT ||
msg->msg_info.event_type == HAWK_EVENT_SILENT_RESET) {
hawk_update_assert_description(msg);
}
// 1. check if we have limit on housing space
// 1.1 check free space in the housing space
free_space = get_logs_free_space();
// 1.2 if free space bigger then 100K
if (free_space > HAWK_FILE_SIZE) {
hawk_spy_file(msg);
free_space -= HAWK_FILE_SIZE;
}
// 1.3 if free space bigger then 500K
if (msg->msg_info.include_dmesg_log == 1 && (free_space > HAWK_FILE_SIZE)) {
hawk_save_dmesg_file(msg);
free_space -= HAWK_FILE_SIZE;
}
#if 0
/*number of sdl is defined as 2 in diag_fs.cfg each file 1MB
* check we have space for the files*/
if (free_space >= MAX_SDL_SIZE) {
hawk_save_sdl_log(msg);
free_space -= MAX_SDL_SIZE;
}
if (free_space >= msg->msg_info.binary_log_size) {
hawk_save_valuable_event_bin_log(msg);
free_space -= msg->msg_info.binary_log_size;
}
#endif
// 1.4 create full_logs.tgz and tiny_logs.tgz
hawk_zip_create(msg);
//no break is intended to allow sending of event report
}
case HAWK_STATUS_IN_PROGRESS:
// if mgs is notification only, send to hawk sender
if (msg->msg_info.event_type != HAWK_EVENT_ASSERT_DETECTED)
hawk_send_event_report(&msg->msg_info);
break;
case HAWK_STATUS_HOST_COMMAND:
hawk_execute_host_command(&msg->msg_info);
break;
default:
ml_log_error("unknown event status %d ignoring event\n", msg->msg_info.status);
}
free(msg);
msg = NULL;
} /* while (1) */
}
/************************************************************************/
/* */
/************************************************************************/
struct hawk_cached_string {
struct list_head list;
char *str;
};
static void hawk_str_to_cache(char *str, struct list_head *list)
{
struct hawk_cached_string *cs;
cs = calloc(1, sizeof(*cs));
if (!cs) {
ml_log_error("OOM '%s'\n", strerror(errno));
ml_system_retry(1, 30, "eeh -T panic hawk_OOM");
exit(1);
}
cs->str = strdup(str);
if (!cs->str) {
ml_log_error("OOM '%s'\n", strerror(errno));
ml_system_retry(1, 30, "eeh -T panic hawk_OOM");
exit(1);
}
INIT_LIST_HEAD(&cs->list);
list_add_tail(&cs->list, list);
ml_log_debug("Adding to cache '%s'\n", str);
}
static __attribute__ ((noreturn))
void *hawk_fifo_listen( __attribute__ ((unused))
void *ptr)
{
char x[HAWK_FIFO_STRING_LEN], *res;
struct timeval timeout;
struct list_head cached_strings;
struct hawk_msg *msg;
prctl(PR_SET_NAME, "hawk_fifo_listener");
INIT_LIST_HEAD(&cached_strings);
fifo.fname = HAWK_FIFO_NAME;
if (ml_create_fifo(&fifo) != 0) {
ml_system_retry(1, 30, "eeh -T panic hawk_fifo_creation_failed");
exit(1);
}
while (1) {
if (!g_hawk.rild_init_done) {
timeout.tv_sec = 1;
timeout.tv_usec = 1l;
} else {
// Push all cached command strings into worker queue
while (!list_empty(&cached_strings)) {
struct hawk_cached_string *cs;
cs = list_entry(cached_strings.next, struct hawk_cached_string, list);
list_del_init(cached_strings.next);
ml_log_info("Remove from cache '%s'\n", cs->str);
if ((msg = hawk_str_to_msg(cs->str)) != NULL)
hawk_add_msg(msg);
free(cs->str);
free(cs);
}
timeout.tv_sec = HAWK_FIFO_TIMEOUT;
timeout.tv_usec = 1l;
}
res = ml_chomp(ml_read_fifo(&fifo, x, HAWK_FIFO_STRING_LEN, &timeout));
if (res == NULL || res[0] == 0)
continue;
// While rild init not done or cached queue have pending commands
// drop new commands into cache
// General purpose of CACHE queue is to cache commands before all HAWK init
// done.
if (!g_hawk.rild_init_done || !list_empty(&cached_strings)) {
hawk_str_to_cache(res, &cached_strings);
continue;
}
if ((msg = hawk_str_to_msg(res)) != NULL)
hawk_add_msg(msg);
}
}
static __attribute__ ((noreturn))
void *hawk_data_check( __attribute__ ((unused))
void *ptr)
{
prctl(PR_SET_NAME, "hawk_data_check");
while (1) {
sleep(HAWK_CHECK_DATA_DELTA);
system(HAWK_CHECK_DATA);
}
}
static void __attribute__ ((__noreturn__)) usage(const char *s)
{
fprintf(stderr, "Usage: %s \n", s);
fprintf(stderr, "-h - print this help message\n");
fprintf(stderr, "-f - disable standalone fota thread\n");
fprintf(stderr, "-d - enable debug logs\n");
fprintf(stderr, "-p - enable data check\n");
exit(1);
}
int main(int argc, char *argv[])
{
pthread_t thid1, thid2;
pthread_attr_t tattr1, tattr2;
long tmp = 0, file_updated = 0, delta = 0;
long next_keep_alive_time = hawk_uptime() + HAWK_KEEP_ALIVE_INTERVAL;
int res, data_check = 0;
struct ml_vers curVer;
struct ml_bld_vers bldVer;
int c;
int run_sa_fota_thread = 1;
do {
c = getopt(argc, argv, "hfdp");
if (c == EOF)
break;
switch (c) {
case '?':
case 'h':
usage(argv[0]);
case 'f':
run_sa_fota_thread = 0;
break;
case 'd':
ml_set_log_level(ML_LOG_DEBUG);
break;
case 'p':
data_check = 1;
break;
}
} while (1);
set_service_log_tag(HKName);
ml_system_retry(1, ML_SYSTEM_MAX_TIMEOUT, HAWK_STARTUP);
hawk_lib_init(HAWK_HOST_CONNECTION_TYPE_STANDALONE);
pthread_mutex_init(&g_hawk.cond_mutex, NULL);
pthread_mutex_init(&g_hawk.general_mutex, NULL);
pthread_mutex_init(&g_hawk.statistics_mutex, NULL);
pthread_cond_init(&g_hawk.cond, NULL);
INIT_LIST_HEAD(&g_hawk.msgq_head);
g_hawk.q_item_count = 0;
//In case of FW update/change we clear statistics
if (ml_get_vers(&curVer) != NULL) {
struct ml_vers prevVer;
property_get(HAWK_PROP_VERS, prevVer.s, "0");
ml_log_debug("previous version was %s", prevVer.s);
ml_log_debug("current version is %s", curVer.s);
if (strcmp(curVer.s,prevVer.s) != 0) { /* new version */
char command_buf[128];
//clear statistics
clear_statistics();
//clear ML properties
property_del(ML_MSEQ_PROP);
property_del(ML_BOOTSEQ_PROP);
property_del(ML_CP_VER_PROP);
//remove old RAMDUMPS and modem_dump directory
snprintf(command_buf, sizeof(command_buf) - 1, "rm -rf %sRAMDUMP* %s %s", hawk_mount, LOG_DIR_SD_MODEM, hawk_dir);
ml_system_retry(1, ML_SYSTEM_MAX_TIMEOUT, command_buf);
//update version property
property_set(HAWK_PROP_VERS, curVer.s);
//update build version property
if(ml_get_bld_vers(&bldVer) != NULL)
property_set(HAWK_PROP_BLD_VERS, bldVer.s);
}
}
pthread_attr_init(&tattr2);
pthread_attr_setdetachstate(&tattr2, PTHREAD_CREATE_DETACHED);
if (pthread_create(&thid2, &tattr2, hawk_worker, NULL)) {
ml_log_error("hawk worker pthread_create failed '%s'\n", strerror(errno));
return -1;
}
pthread_attr_init(&tattr1);
pthread_attr_setdetachstate(&tattr1, PTHREAD_CREATE_DETACHED);
if (pthread_create(&thid1, &tattr1, hawk_fifo_listen, NULL)) {
ml_log_error("fifo listen pthread_create failed '%s'\n", strerror(errno));
return -1;
}
if(ml_get_long_property("ro.hawk.fota.is_enabled") != 1)
run_sa_fota_thread = 0;
res = hawk_sender_create_worker(run_sa_fota_thread);
if (res != 0) {
ml_log_error("Failed to init hawk....\n");
return -1;
}
if (data_check) {
pthread_t thid3;
pthread_attr_t tattr3;
pthread_attr_init(&tattr3);
pthread_attr_setdetachstate(&tattr3, PTHREAD_CREATE_DETACHED);
if (pthread_create(&thid3, &tattr3, hawk_data_check, NULL)) {
ml_log_error("data check pthread_create failed '%s'\n", strerror(errno));
return -1;
}
}
while (1) {
if (!g_hawk.rild_init_done) {
sleep(2);
continue;
}
tmp = hawk_uptime();
delta = tmp - file_updated;
ml_log_debug("tmp=%ld, delta=%ld, next_keep_alive_time=%ld", tmp, delta, next_keep_alive_time);
if (delta >= HAWK_TIMESTAMP_DELTA) {
file_updated = tmp;
hawk_set_timestamp();
}
if (next_keep_alive_time < tmp) { /*current time ls larger then next keep alive event time */
hawk_send_keep_alive_event();
next_keep_alive_time = tmp + HAWK_KEEP_ALIVE_INTERVAL;
}
//save_statistics();
hawk_rild_get_rat();
sleep(delta >= HAWK_TIMESTAMP_DELTA ? HAWK_TIMESTAMP_DELTA : HAWK_TIMESTAMP_DELTA - delta + 1);
}
}