| #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); |
| } |
| } |