From d584360de2b5a40b6ab14f4b11d90529abe8face Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Thu, 14 Feb 2019 00:52:59 -0500 Subject: [PATCH] More optimized APK traversal --- native/jni/magiskhide/proc_monitor.cpp | 86 +++++++++++++++----------- native/jni/utils/file.cpp | 8 +-- native/jni/utils/include/utils.h | 2 +- 3 files changed, 54 insertions(+), 42 deletions(-) diff --git a/native/jni/magiskhide/proc_monitor.cpp b/native/jni/magiskhide/proc_monitor.cpp index 1ddaad493..7ca4f523e 100644 --- a/native/jni/magiskhide/proc_monitor.cpp +++ b/native/jni/magiskhide/proc_monitor.cpp @@ -188,51 +188,64 @@ static bool process_pid(int pid) { return true; } -static void listdir_apk(const char *name) { - DIR *dir; - struct dirent *entry; - const char *ext; - char path[4096]; +static int xinotify_add_watch(int fd, const char* path, uint32_t mask) { + int ret = inotify_add_watch(fd, path, mask); + if (ret >= 0) { + LOGI("proc_monitor: Monitoring %s\n", path); + } else { + PLOGE("proc_monitor: Monitor %s", path); + } + return ret; +} - if (!(dir = opendir(name))) +static char *append_path(char *eof, const char *name) { + *(eof++) = '/'; + char c; + while ((c = *(name++))) + *(eof++) = c; + *eof = '\0'; + return eof; +} + +#define DATA_APP "/data/app" + +static void find_apks(char *path, char *eof) { + DIR *dir = opendir(path); + if (dir == nullptr) return; - while ((entry = readdir(dir)) != NULL) { - snprintf(path, sizeof(path), "%s/%s", name, - entry->d_name); + // assert(*eof == '\0'); + struct dirent *entry; + while ((entry = xreaddir(dir))) { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) + continue; if (entry->d_type == DT_DIR) { - if (strcmp(entry->d_name, ".") == 0 - || strcmp(entry->d_name, "..") == 0) - continue; - listdir_apk(path); - } else { - ext = &path[strlen(path) - 4]; - if (!strncmp(".apk", ext, 4)) { - pthread_mutex_lock(&list_lock); - for (auto &s : hide_list) { - // Compare with (path + 10) to trim "/data/app/" - if (strncmp(path + 10, s.c_str(), s.length()) == 0) { - if (inotify_add_watch(inotify_fd, path, IN_OPEN | IN_DELETE) > 0) { - LOGI("proc_monitor: Monitoring %s\n", path); - } else { - LOGE("proc_monitor: Failed to monitor %s: %s\n", path, strerror(errno)); - } - break; - } + find_apks(path, append_path(eof, entry->d_name)); + *eof = '\0'; + } else if (strend(entry->d_name, ".apk") == 0) { + // Path will be in this format: /data/app/[pkg]-[hash or 1 or 2] + char *dash = strchr(path, '-'); + *dash = '\0'; + for (auto &s : hide_list) { + if (s == path + sizeof(DATA_APP)) { + *dash = '-'; + append_path(eof, entry->d_name); + xinotify_add_watch(inotify_fd, path, IN_OPEN | IN_DELETE); + *eof = '\0'; + break; } - pthread_mutex_unlock(&list_lock); } + *dash = '-'; + break; } } - closedir(dir); } // Iterate through /data/app and search all .apk files void update_inotify_mask() { - // Setup inotify - const char data_app[] = "/data/app"; + char buf[4096]; if (inotify_fd >= 0) close(inotify_fd); @@ -244,14 +257,13 @@ void update_inotify_mask() { } LOGI("proc_monitor: Updating APK list\n"); - listdir_apk(data_app); + strcpy(buf, DATA_APP); + pthread_mutex_lock(&list_lock); + find_apks(buf, buf + sizeof(DATA_APP) - 1); + pthread_mutex_unlock(&list_lock); // Add /data/app itself to the watch list to detect app (un)installations/updates - if (inotify_add_watch(inotify_fd, data_app, IN_CLOSE_WRITE | IN_MOVED_TO | IN_DELETE) > 0) { - LOGI("proc_monitor: Monitoring %s\n", data_app, inotify_fd); - } else { - LOGE("proc_monitor: Failed to monitor %s: %s\n", strerror(errno)); - } + xinotify_add_watch(inotify_fd, DATA_APP, IN_CLOSE_WRITE | IN_MOVED_TO | IN_DELETE); } void proc_monitor() { diff --git a/native/jni/utils/file.cpp b/native/jni/utils/file.cpp index f5b8994a7..0f470d875 100644 --- a/native/jni/utils/file.cpp +++ b/native/jni/utils/file.cpp @@ -60,7 +60,7 @@ int mkdirs(const char *pathname, mode_t mode) { return 0; } -void in_order_walk(int dirfd, void (*callback)(int, struct dirent*)) { +void post_order_walk(int dirfd, void (*fn)(int, struct dirent *)) { struct dirent *entry; int newfd; DIR *dir = fdopendir(dirfd); @@ -73,10 +73,10 @@ void in_order_walk(int dirfd, void (*callback)(int, struct dirent*)) { continue; if (entry->d_type == DT_DIR) { newfd = xopenat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC); - in_order_walk(newfd, callback); + post_order_walk(newfd, fn); close(newfd); } - callback(dirfd, entry); + fn(dirfd, entry); } } @@ -93,7 +93,7 @@ void rm_rf(const char *path) { } void frm_rf(int dirfd) { - in_order_walk(dirfd, [](auto dirfd, auto entry) -> void { + post_order_walk(dirfd, [](auto dirfd, auto entry) -> void { unlinkat(dirfd, entry->d_name, entry->d_type == DT_DIR ? AT_REMOVEDIR : 0); }); } diff --git a/native/jni/utils/include/utils.h b/native/jni/utils/include/utils.h index fa384e1b7..32d773e6e 100644 --- a/native/jni/utils/include/utils.h +++ b/native/jni/utils/include/utils.h @@ -108,7 +108,7 @@ struct file_attr { int fd_getpath(int fd, char *path, size_t size); int fd_getpathat(int dirfd, const char *name, char *path, size_t size); int mkdirs(const char *pathname, mode_t mode); -void in_order_walk(int dirfd, void (*callback)(int, struct dirent*)); +void post_order_walk(int dirfd, void (*fn)(int, struct dirent *)); void rm_rf(const char *path); void frm_rf(int dirfd); void mv_f(const char *source, const char *destination);