kernel: throne_tracker: offload to kthread tiann #2632

Run throne_tracker() in kthread instead of blocking the caller.
Prevents full lockup during installation and removing the manager.

By default, first run remains synchronous for compatibility purposes
(FDE, FBEv1, FBEv2)

Features:
- looks and waits for manager UID in /data/system/packages.list
- run track_throne() in a kthread after the first synchronous run
- prevent duplicate thread creation with a single-instance check
- spinlock-on-d_lock based polling adressing possible race conditions.

Race conditions adressed
- single instance kthread lock, smp_mb()
- track_throne_function, packages.list, spinlock-on-d_lock based polling
- is_manager_apk, apk, spinlock-on-d_lock based polling

This is a squash of:
https://github.com/tiann/KernelSU/pull/2632

Original skeleton based on:
`kernelsu: move throne_tracker() to kthread`
`kernelsu: check locking before accessing files and dirs during searching manager`
`kernelsu: look for manager UID in /data/system/packages.list, not /data/system/packages.list.tmp`
0b05e927...8783badd

Co-Authored-By: backslashxx <118538522+backslashxx@users.noreply.github.com>
Co-Authored-By: Yaroslav Zviezda <10716792+acroreiser@users.noreply.github.com>
Signed-off-by: backslashxx <118538522+backslashxx@users.noreply.github.com>
This commit is contained in:
ShirkNeko
2025-09-24 01:50:49 +08:00
parent 23dde3f863
commit 86ccca18eb
4 changed files with 130 additions and 2 deletions

View File

@@ -17,8 +17,13 @@
#include "dynamic_manager.h"
#include "throne_comm.h"
#include <linux/kthread.h>
#include <linux/sched.h>
uid_t ksu_manager_uid = KSU_INVALID_UID;
static struct task_struct *throne_thread;
#define KSU_UID_LIST_PATH "/data/misc/user_uid/uid_list"
#define USER_DATA_PATH "/data/user_de/0"
#define USER_DATA_PATH_LEN 256
@@ -547,7 +552,7 @@ void search_manager(const char *path, int depth, struct list_head *uid_data)
if (!stop) {
file = ksu_filp_open_compat(
pos->dirpath, O_RDONLY | O_NOFOLLOW, 0);
pos->dirpath, O_RDONLY | O_NOFOLLOW | O_DIRECTORY, 0);
if (IS_ERR(file)) {
pr_err("Failed to open directory: %s, err: %ld\n",
pos->dirpath, PTR_ERR(file));
@@ -613,7 +618,7 @@ static bool is_uid_exist(uid_t uid, char *package, void *data)
return exist;
}
void track_throne(void)
static void track_throne_function()
{
struct list_head uid_list;
INIT_LIST_HEAD(&uid_list);
@@ -695,6 +700,37 @@ out:
}
}
static int throne_tracker_thread(void *data)
{
pr_info("%s: pid: %d started\n", __func__, current->pid);
track_throne_function();
throne_thread = NULL;
smp_mb();
pr_info("%s: pid: %d exit!\n", __func__, current->pid);
return 0;
}
void track_throne(void)
{
#ifndef CONFIG_KSU_THRONE_TRACKER_ALWAYS_THREADED
static bool throne_tracker_first_run __read_mostly = true;
if (unlikely(throne_tracker_first_run)) {
track_throne_function();
throne_tracker_first_run = false;
return;
}
#endif
smp_mb();
if (throne_thread != NULL) // single instance lock
return;
throne_thread = kthread_run(throne_tracker_thread, NULL, "throne_tracker");
if (IS_ERR(throne_thread)) {
throne_thread = NULL;
return;
}
}
void ksu_throne_tracker_init(void)
{
// nothing to do