/******************************* 程序功能:把抖音极速版的数据库文件,挂载到tmpfs内存中。避免频繁写入内部存储,提高EMMC使用寿命。 ********************************/ #define LOG_TAG "FileInotify" #include #include #include #include #include #include #include #include #include #include #include #include #include #define CMD_BASE 0xCBAABC10 #define FK_IS_GET_POWER2 (CMD_BASE + 12) #define EVENT_SIZE (sizeof(struct inotify_event)) #define EVENT_BUF_LEN (1024 * (EVENT_SIZE + 16)) #define MAX_BUF_SIZE 256 #define NOTIFY_DIR_NUM 2 //监控文件名 #define NOTIFY_FILE "apm_monitor_t1.db" #define NOTIFY_FILE_2 "apm_monitor_t1.db-journal" //监听目录 #define NOTIFY_PATH "/data/data/com.ss.android.ugc.aweme.lite/databases/" #define NOTIFY_PATH_2 "/data/data/com.ss.android.ugc.live/databases/" //挂载目录 #define TMPFS_PATH "/data_mirror/com.ss.android.ugc.aweme.lite/databases/" #define TMPFS_PATH_2 "/data_mirror/com.ss.android.ugc.live/databases/" typedef enum INDEX { DIR1, DIR2, }INDEX_T; typedef struct { int dir_exists[NOTIFY_DIR_NUM]; int wd[NOTIFY_DIR_NUM]; int fd; }inotify_info; void *inotify_func(void *argc) { inotify_info *info = (inotify_info *)argc; char buf[MAX_BUF_SIZE]; while(1) { if(access(NOTIFY_PATH, F_OK) == 0 && info->dir_exists[DIR1] == 0) { //监听目录 info->dir_exists[DIR1] = 1; info->wd[DIR1] = inotify_add_watch(info->fd, NOTIFY_PATH, IN_CREATE | IN_DELETE); //pthread_exit(NULL); //ALOGD("add dir %s,wd=%d\n", NOTIFY_PATH, info->wd[DIR1]); } if(access(NOTIFY_PATH_2, F_OK) == 0 && info->dir_exists[DIR2] == 0) { //监听目录 info->dir_exists[DIR2] = 1; info->wd[DIR2] = inotify_add_watch(info->fd, NOTIFY_PATH_2, IN_CREATE | IN_DELETE); //pthread_exit(NULL); //ALOGD("add dir %s,wd=%d\n", NOTIFY_PATH_2, info->wd[DIR2]); } //应用卸载目录删除,重新设置标志 if(access(NOTIFY_PATH, F_OK) != 0) { info->dir_exists[DIR1] = 0; } if(access(NOTIFY_PATH_2, F_OK) != 0) { info->dir_exists[DIR2] = 0; } sleep(5); } } int do_mount(char *name, int wd, inotify_info *info) { char buf[MAX_BUF_SIZE]; //1. 创建tmpfs目录 if(access(TMPFS_PATH, F_OK) != 0) //如果目录不存在 { sprintf(buf, "mkdir -p %s", TMPFS_PATH); system(buf); memset(buf, 0, sizeof(buf)); } if(access(TMPFS_PATH_2, F_OK) != 0) //如果目录不存在 { sprintf(buf, "mkdir -p %s", TMPFS_PATH_2); system(buf); memset(buf, 0, sizeof(buf)); } //2. 创建tmpfs文件 sprintf(buf, "%s/%s", TMPFS_PATH, name); if(access(buf, F_OK) != 0) //如果文件不存在 { sprintf(buf, "touch %s/%s", TMPFS_PATH, name); system(buf); memset(buf, 0, sizeof(buf)); } sprintf(buf, "%s/%s", TMPFS_PATH_2, name); if(access(buf, F_OK) != 0) //如果文件不存在 { sprintf(buf, "touch %s/%s", TMPFS_PATH_2, name); system(buf); memset(buf, 0, sizeof(buf)); } //3. 挂载 if(info->wd[DIR1] == wd) { sprintf(buf, "%s/%s", NOTIFY_PATH, name); if(access(buf, F_OK) == 0) //如果文件存在 { //mount -o vcloud --bind /data_mirror/com.ss.android.ugc.aweme.lite/apm_monitor_t1.db /data/data/com.ss.android.ugc.aweme.lite/databases/apm_monitor_t1.db sprintf(buf, "mount -o vcloud --bind %s/%s %s/%s", TMPFS_PATH, name, NOTIFY_PATH, name); system(buf); memset(buf, 0, sizeof(buf)); } } if(info->wd[DIR2] == wd) { sprintf(buf, "%s/%s", NOTIFY_PATH_2, name); if(access(buf, F_OK) == 0) //如果文件存在 { sprintf(buf, "mount -o vcloud --bind %s/%s %s/%s", TMPFS_PATH_2, name, NOTIFY_PATH_2, name); system(buf); memset(buf, 0, sizeof(buf)); } } return 0; } int do_umount(char *name, int wd, inotify_info *info) { char buf[MAX_BUF_SIZE]; if(info->wd[DIR1] == wd) { //1. 卸载 sprintf(buf, "%s/%s", NOTIFY_PATH, name); if(access(buf, F_OK) == 0) //如果文件存在 { sprintf(buf, "umount %s/%s", NOTIFY_PATH, name); system(buf); memset(buf, 0, sizeof(buf)); } //2. 删除文件 memset(buf, 0, sizeof(buf)); sprintf(buf, "rm %s/%s", TMPFS_PATH, name); system(buf); } if(info->wd[DIR2] == wd) { //1. 卸载 sprintf(buf, "%s/%s", NOTIFY_PATH_2, name); if(access(buf, F_OK) == 0) //如果文件存在 { sprintf(buf, "umount %s/%s", NOTIFY_PATH_2, name); system(buf); memset(buf, 0, sizeof(buf)); } //2. 删除文件 memset(buf, 0, sizeof(buf)); sprintf(buf, "rm %s/%s", TMPFS_PATH_2, name); system(buf); } return 0; } void do_rmfile(char *name) { char buf[MAX_BUF_SIZE]; memset(buf, 0, sizeof(buf)); sprintf(buf, "rm %s/%s", NOTIFY_PATH, name); system(buf); memset(buf, 0, sizeof(buf)); sprintf(buf, "rm %s/%s", NOTIFY_PATH_2, name); system(buf); } int main(void) { inotify_info info; pthread_t tid; int length, i = 0; char buf[EVENT_BUF_LEN]; //selinux prctl(FK_IS_GET_POWER2, 0, 0, 0); //inotify初始化 info.fd = inotify_init(); if (info.fd < 0) { perror("inotify_init"); return -1; } //监听目录 pthread_create(&tid, NULL, inotify_func, &info); while(1) { i = 0; length = read(info.fd, buf, EVENT_BUF_LEN); if (length < 0) { perror("read"); continue; } while (i < length) { struct inotify_event *event = (struct inotify_event *) &buf[i]; if (event->len) { if (event->mask & IN_CREATE) { if (!(event->mask & IN_ISDIR)) { if(strcmp(NOTIFY_FILE, event->name) == 0 || strcmp(NOTIFY_FILE_2, event->name) == 0) { //ALOGD("file %s created wd=%d\n", event->name, event->wd); #if 0 do_mount(event->name, event->wd, &info); #else //直接删除文件 do_rmfile(event->name); #endif } } } else if (event->mask & IN_DELETE) { if (!(event->mask & IN_ISDIR)) { if(strcmp(NOTIFY_FILE, event->name) == 0 || strcmp(NOTIFY_FILE_2, event->name) == 0) { //ALOGD("file %s deleted wd=%d\n", event->name, event->wd); #if 0 do_umount(event->name, event->wd, &info); #endif } } } } i += EVENT_SIZE + event->len; } } inotify_rm_watch(info.fd, info.wd[DIR1]); inotify_rm_watch(info.fd, info.wd[DIR2]); close(info.fd); return 0; }