mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-04-24 20:51:28 +00:00
Stop using polymorphism in magiskinit
This commit is contained in:
parent
c8e9ce7627
commit
3c6889505b
@ -11,8 +11,6 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
vector<string> mount_list;
|
||||
|
||||
template<char... cs> using chars = integer_sequence<char, cs...>;
|
||||
|
||||
// If quoted, parsing ends when we find char in [breaks]
|
||||
@ -180,22 +178,7 @@ if (access(file_name, R_OK) == 0) { \
|
||||
} \
|
||||
}
|
||||
|
||||
BootConfig::BootConfig() {
|
||||
// Get kernel data using procfs and sysfs
|
||||
if (access("/proc/cmdline", F_OK) != 0) {
|
||||
xmkdir("/proc", 0755);
|
||||
xmount("proc", "/proc", "proc", 0, nullptr);
|
||||
mount_list.emplace_back("/proc");
|
||||
}
|
||||
if (access("/sys/block", F_OK) != 0) {
|
||||
xmkdir("/sys", 0755);
|
||||
xmount("sysfs", "/sys", "sysfs", 0, nullptr);
|
||||
mount_list.emplace_back("/sys");
|
||||
}
|
||||
|
||||
// Log to kernel
|
||||
rust::setup_klog();
|
||||
|
||||
void BootConfig::init() {
|
||||
set(parse_cmdline(full_read("/proc/cmdline")));
|
||||
set(parse_bootconfig(full_read("/proc/bootconfig")));
|
||||
|
||||
@ -234,7 +217,7 @@ bool check_two_stage() {
|
||||
return init.contains("selinux_setup");
|
||||
}
|
||||
|
||||
void unxz_init(const char *init_xz, const char *init) {
|
||||
static void unxz_init(const char *init_xz, const char *init) {
|
||||
LOGD("unxz %s -> %s\n", init_xz, init);
|
||||
int fd = xopen(init, O_WRONLY | O_CREAT, 0777);
|
||||
fd_stream ch(fd);
|
||||
|
@ -60,16 +60,67 @@ void restore_ramdisk_init() {
|
||||
}
|
||||
}
|
||||
|
||||
class RecoveryInit : public BaseInit {
|
||||
public:
|
||||
using BaseInit::BaseInit;
|
||||
void start() override {
|
||||
LOGD("Ramdisk is recovery, abort\n");
|
||||
restore_ramdisk_init();
|
||||
rm_rf("/.backup");
|
||||
exec_init();
|
||||
MagiskInit::MagiskInit(char **argv) : argv(argv), config{} {
|
||||
// Get kernel data using procfs and sysfs
|
||||
if (access("/proc/cmdline", F_OK) != 0) {
|
||||
xmkdir("/proc", 0755);
|
||||
xmount("proc", "/proc", "proc", 0, nullptr);
|
||||
mount_list.emplace_back("/proc");
|
||||
}
|
||||
};
|
||||
if (access("/sys/block", F_OK) != 0) {
|
||||
xmkdir("/sys", 0755);
|
||||
xmount("sysfs", "/sys", "sysfs", 0, nullptr);
|
||||
mount_list.emplace_back("/sys");
|
||||
}
|
||||
|
||||
// Log to kernel
|
||||
rust::setup_klog();
|
||||
|
||||
// Load kernel configs
|
||||
config.init();
|
||||
}
|
||||
|
||||
static void recovery() {
|
||||
LOGI("Ramdisk is recovery, abort\n");
|
||||
restore_ramdisk_init();
|
||||
rm_rf("/.backup");
|
||||
}
|
||||
|
||||
void MagiskInit::legacy_system_as_root() {
|
||||
LOGI("Legacy SAR Init\n");
|
||||
prepare_data();
|
||||
bool is_two_stage = mount_system_root();
|
||||
if (is_two_stage)
|
||||
redirect_second_stage();
|
||||
else
|
||||
patch_ro_root();
|
||||
}
|
||||
|
||||
void MagiskInit::rootfs() {
|
||||
LOGI("RootFS Init\n");
|
||||
prepare_data();
|
||||
LOGD("Restoring /init\n");
|
||||
rename(backup_init(), "/init");
|
||||
patch_rw_root();
|
||||
}
|
||||
|
||||
void MagiskInit::start() {
|
||||
if (argv[1] != nullptr && argv[1] == "selinux_setup"sv)
|
||||
second_stage();
|
||||
else if (config.skip_initramfs)
|
||||
legacy_system_as_root();
|
||||
else if (config.force_normal_boot)
|
||||
first_stage();
|
||||
else if (access("/sbin/recovery", F_OK) == 0 || access("/system/bin/recovery", F_OK) == 0)
|
||||
recovery();
|
||||
else if (check_two_stage())
|
||||
first_stage();
|
||||
else
|
||||
rootfs();
|
||||
|
||||
// Finally execute the original init
|
||||
exec_init();
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
umask(0);
|
||||
@ -81,23 +132,6 @@ int main(int argc, char *argv[]) {
|
||||
if (getpid() != 1)
|
||||
return 1;
|
||||
|
||||
BaseInit *init;
|
||||
BootConfig config;
|
||||
|
||||
if (argc > 1 && argv[1] == "selinux_setup"sv)
|
||||
init = new SecondStageInit(argv, &config);
|
||||
else if (config.skip_initramfs)
|
||||
init = new LegacySARInit(argv, &config);
|
||||
else if (config.force_normal_boot)
|
||||
init = new FirstStageInit(argv, &config);
|
||||
else if (access("/sbin/recovery", F_OK) == 0 || access("/system/bin/recovery", F_OK) == 0)
|
||||
init = new RecoveryInit(argv, &config);
|
||||
else if (check_two_stage())
|
||||
init = new FirstStageInit(argv, &config);
|
||||
else
|
||||
init = new RootFSInit(argv, &config);
|
||||
|
||||
// Run the main routine
|
||||
init->start();
|
||||
exit(1);
|
||||
MagiskInit init(argv);
|
||||
init.start();
|
||||
}
|
||||
|
@ -6,18 +6,18 @@
|
||||
using kv_pairs = std::vector<std::pair<std::string, std::string>>;
|
||||
|
||||
struct BootConfig {
|
||||
bool skip_initramfs = false;
|
||||
bool force_normal_boot = false;
|
||||
bool rootwait = false;
|
||||
bool emulator = false;
|
||||
char slot[3]{};
|
||||
char dt_dir[64]{};
|
||||
char fstab_suffix[32]{};
|
||||
char hardware[32]{};
|
||||
char hardware_plat[32]{};
|
||||
bool skip_initramfs;
|
||||
bool force_normal_boot;
|
||||
bool rootwait;
|
||||
bool emulator;
|
||||
char slot[3];
|
||||
char dt_dir[64];
|
||||
char fstab_suffix[32];
|
||||
char hardware[32];
|
||||
char hardware_plat[32];
|
||||
kv_pairs partition_map;
|
||||
|
||||
BootConfig();
|
||||
void init();
|
||||
private:
|
||||
void set(const kv_pairs &);
|
||||
void print();
|
||||
@ -27,121 +27,45 @@ private:
|
||||
#define INIT_PATH "/system/bin/init"
|
||||
#define REDIR_PATH "/data/magiskinit"
|
||||
|
||||
extern std::vector<std::string> mount_list;
|
||||
|
||||
int magisk_proxy_main(int argc, char *argv[]);
|
||||
bool unxz(out_stream &strm, rust::Slice<const uint8_t> bytes);
|
||||
bool check_two_stage();
|
||||
const char *backup_init();
|
||||
void restore_ramdisk_init();
|
||||
|
||||
/***************
|
||||
* Base classes
|
||||
***************/
|
||||
|
||||
class BaseInit {
|
||||
protected:
|
||||
BootConfig *config;
|
||||
char **argv;
|
||||
|
||||
[[noreturn]] void exec_init();
|
||||
void prepare_data();
|
||||
dev_t find_block(const char *partname);
|
||||
void collect_devices();
|
||||
public:
|
||||
BaseInit(char *argv[], BootConfig *config) : config(config), argv(argv) {}
|
||||
virtual ~BaseInit() = default;
|
||||
virtual void start() = 0;
|
||||
};
|
||||
|
||||
class MagiskInit : public BaseInit {
|
||||
class MagiskInit {
|
||||
private:
|
||||
std::string preinit_dev;
|
||||
std::vector<std::string> mount_list;
|
||||
char **argv;
|
||||
BootConfig config;
|
||||
|
||||
void parse_config_file();
|
||||
void patch_sepolicy(const char *in, const char *out);
|
||||
bool hijack_sepolicy();
|
||||
// Setup mounts and environment
|
||||
void setup_tmp(const char *path);
|
||||
void collect_devices();
|
||||
void mount_preinit_dir();
|
||||
protected:
|
||||
void prepare_data();
|
||||
dev_t find_block(const char *partname);
|
||||
bool mount_system_root();
|
||||
|
||||
// Setup and patch root directory
|
||||
void parse_config_file();
|
||||
void patch_rw_root();
|
||||
void patch_ro_root();
|
||||
|
||||
// Two stage init
|
||||
void redirect_second_stage();
|
||||
void first_stage();
|
||||
void second_stage();
|
||||
|
||||
// SELinux
|
||||
void patch_sepolicy(const char *in, const char *out);
|
||||
bool hijack_sepolicy();
|
||||
|
||||
[[noreturn]] void exec_init();
|
||||
void legacy_system_as_root();
|
||||
void rootfs();
|
||||
public:
|
||||
using BaseInit::BaseInit;
|
||||
};
|
||||
|
||||
/***************
|
||||
* 2 Stage Init
|
||||
***************/
|
||||
|
||||
class FirstStageInit : public BaseInit {
|
||||
private:
|
||||
void prepare();
|
||||
public:
|
||||
FirstStageInit(char *argv[], BootConfig *config) : BaseInit(argv, config) {
|
||||
LOGD("%s\n", __FUNCTION__);
|
||||
};
|
||||
void start() override {
|
||||
prepare();
|
||||
exec_init();
|
||||
}
|
||||
};
|
||||
|
||||
class SecondStageInit : public MagiskInit {
|
||||
private:
|
||||
bool prepare();
|
||||
public:
|
||||
SecondStageInit(char *argv[], BootConfig *config) : MagiskInit(argv, config) {
|
||||
LOGD("%s\n", __FUNCTION__);
|
||||
};
|
||||
|
||||
void start() override {
|
||||
bool is_rootfs = prepare();
|
||||
if (is_rootfs)
|
||||
patch_rw_root();
|
||||
else
|
||||
patch_ro_root();
|
||||
exec_init();
|
||||
}
|
||||
};
|
||||
|
||||
/*************
|
||||
* Legacy SAR
|
||||
*************/
|
||||
|
||||
class LegacySARInit : public MagiskInit {
|
||||
private:
|
||||
bool mount_system_root();
|
||||
void first_stage_prep();
|
||||
public:
|
||||
LegacySARInit(char *argv[], BootConfig *config) : MagiskInit(argv, config) {
|
||||
LOGD("%s\n", __FUNCTION__);
|
||||
};
|
||||
void start() override {
|
||||
prepare_data();
|
||||
bool is_two_stage = mount_system_root();
|
||||
if (is_two_stage)
|
||||
first_stage_prep();
|
||||
else
|
||||
patch_ro_root();
|
||||
exec_init();
|
||||
}
|
||||
};
|
||||
|
||||
/************
|
||||
* Initramfs
|
||||
************/
|
||||
|
||||
class RootFSInit : public MagiskInit {
|
||||
private:
|
||||
void prepare();
|
||||
public:
|
||||
RootFSInit(char *argv[], BootConfig *config) : MagiskInit(argv, config) {
|
||||
LOGD("%s\n", __FUNCTION__);
|
||||
}
|
||||
void start() override {
|
||||
prepare();
|
||||
patch_rw_root();
|
||||
exec_init();
|
||||
}
|
||||
explicit MagiskInit(char *argv[]);
|
||||
void start();
|
||||
};
|
||||
|
@ -45,7 +45,7 @@ static void parse_device(devinfo *dev, const char *uevent) {
|
||||
});
|
||||
}
|
||||
|
||||
void BaseInit::collect_devices() {
|
||||
void MagiskInit::collect_devices() {
|
||||
char path[PATH_MAX];
|
||||
devinfo dev{};
|
||||
if (auto dir = xopen_dir("/sys/dev/block"); dir) {
|
||||
@ -59,9 +59,9 @@ void BaseInit::collect_devices() {
|
||||
auto name = rtrim(full_read(path));
|
||||
strscpy(dev.dmname, name.data(), sizeof(dev.dmname));
|
||||
}
|
||||
if (auto it = std::ranges::find_if(config->partition_map, [&](const auto &i) {
|
||||
if (auto it = std::ranges::find_if(config.partition_map, [&](const auto &i) {
|
||||
return i.first == dev.devname;
|
||||
}); dev.partname[0] == '\0' && it != config->partition_map.end()) {
|
||||
}); dev.partname[0] == '\0' && it != config.partition_map.end()) {
|
||||
// use androidboot.partition_map as partname fallback.
|
||||
strscpy(dev.partname, it->second.data(), sizeof(dev.partname));
|
||||
}
|
||||
@ -72,7 +72,7 @@ void BaseInit::collect_devices() {
|
||||
}
|
||||
}
|
||||
|
||||
dev_t BaseInit::find_block(const char *partname) {
|
||||
dev_t MagiskInit::find_block(const char *partname) {
|
||||
if (dev_list.empty())
|
||||
collect_devices();
|
||||
|
||||
@ -143,7 +143,7 @@ void MagiskInit::mount_preinit_dir() {
|
||||
}
|
||||
}
|
||||
|
||||
bool LegacySARInit::mount_system_root() {
|
||||
bool MagiskInit::mount_system_root() {
|
||||
LOGD("Mounting system_root\n");
|
||||
|
||||
// there's no /dev in stub cpio
|
||||
@ -163,13 +163,13 @@ bool LegacySARInit::mount_system_root() {
|
||||
|
||||
// Try normal partname
|
||||
char sys_part[32];
|
||||
sprintf(sys_part, "system%s", config->slot);
|
||||
sprintf(sys_part, "system%s", config.slot);
|
||||
dev = find_block(sys_part);
|
||||
if (dev > 0)
|
||||
goto mount_root;
|
||||
|
||||
// Poll forever if rootwait was given in cmdline
|
||||
} while (config->rootwait);
|
||||
} while (config.rootwait);
|
||||
|
||||
// We don't really know what to do at this point...
|
||||
LOGE("Cannot find root partition, abort\n");
|
||||
@ -198,7 +198,7 @@ mount_root:
|
||||
|
||||
// For API 28 AVD, it uses legacy SAR setup that requires
|
||||
// special hacks in magiskinit to work properly.
|
||||
if (!is_two_stage && config->emulator) {
|
||||
if (!is_two_stage && config.emulator) {
|
||||
avd_hack = true;
|
||||
// These values are hardcoded for API 28 AVD
|
||||
auto vendor_dev = find_block("vendor");
|
||||
@ -210,7 +210,7 @@ mount_root:
|
||||
return is_two_stage;
|
||||
}
|
||||
|
||||
void BaseInit::exec_init() {
|
||||
void MagiskInit::exec_init() {
|
||||
// Unmount in reverse order
|
||||
for (auto &p : reversed(mount_list)) {
|
||||
if (xumount2(p.data(), MNT_DETACH) == 0)
|
||||
@ -220,12 +220,12 @@ void BaseInit::exec_init() {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void BaseInit::prepare_data() {
|
||||
void MagiskInit::prepare_data() {
|
||||
LOGD("Setup data tmp\n");
|
||||
xmkdir("/data", 0755);
|
||||
xmount("magisk", "/data", "tmpfs", 0, "mode=755");
|
||||
|
||||
cp_afc("/init", "/data/magiskinit");
|
||||
cp_afc("/init", REDIR_PATH);
|
||||
cp_afc("/.backup", "/data/.backup");
|
||||
cp_afc("/overlay.d", "/data/overlay.d");
|
||||
}
|
||||
|
@ -347,12 +347,6 @@ void MagiskInit::patch_ro_root() {
|
||||
chdir("/");
|
||||
}
|
||||
|
||||
void RootFSInit::prepare() {
|
||||
prepare_data();
|
||||
LOGD("Restoring /init\n");
|
||||
rename(backup_init(), "/init");
|
||||
}
|
||||
|
||||
#define PRE_TMPSRC "/magisk"
|
||||
#define PRE_TMPDIR PRE_TMPSRC "/tmp"
|
||||
|
||||
|
@ -64,7 +64,7 @@ bool MagiskInit::hijack_sepolicy() {
|
||||
// This only happens on Android 8.0 - 9.0
|
||||
|
||||
char buf[4096];
|
||||
ssprintf(buf, sizeof(buf), "%s/fstab/compatible", config->dt_dir);
|
||||
ssprintf(buf, sizeof(buf), "%s/fstab/compatible", config.dt_dir);
|
||||
dt_compat = full_read(buf);
|
||||
if (dt_compat.empty()) {
|
||||
// Device does not do early mount and uses monolithic policy
|
||||
@ -106,7 +106,7 @@ bool MagiskInit::hijack_sepolicy() {
|
||||
int fd = xopen(MOCK_COMPAT, O_WRONLY);
|
||||
|
||||
char buf[4096];
|
||||
ssprintf(buf, sizeof(buf), "%s/fstab/compatible", config->dt_dir);
|
||||
ssprintf(buf, sizeof(buf), "%s/fstab/compatible", config.dt_dir);
|
||||
xumount2(buf, MNT_DETACH);
|
||||
|
||||
hijack();
|
||||
|
@ -8,12 +8,13 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
void FirstStageInit::prepare() {
|
||||
void MagiskInit::first_stage() {
|
||||
LOGI("First Stage Init\n");
|
||||
prepare_data();
|
||||
|
||||
if (struct stat st{}; fstatat(-1, "/sdcard", &st, AT_SYMLINK_NOFOLLOW) != 0 &&
|
||||
fstatat(-1, "/first_stage_ramdisk/sdcard", &st, AT_SYMLINK_NOFOLLOW) != 0) {
|
||||
if (config->force_normal_boot) {
|
||||
if (config.force_normal_boot) {
|
||||
xmkdirs("/first_stage_ramdisk/storage/self", 0755);
|
||||
xsymlink("/system/system/bin/init", "/first_stage_ramdisk/storage/self/primary");
|
||||
LOGD("Symlink /first_stage_ramdisk/storage/self/primary -> /system/system/bin/init\n");
|
||||
@ -29,8 +30,8 @@ void FirstStageInit::prepare() {
|
||||
LOGD("Bind mount /sdcard -> /sdcard\n");
|
||||
} else {
|
||||
// rootfs before 3.12
|
||||
xmount("/data/magiskinit", "/sdcard", nullptr, MS_BIND, nullptr);
|
||||
LOGD("Bind mount /sdcard -> /data/magiskinit\n");
|
||||
xmount(REDIR_PATH, "/sdcard", nullptr, MS_BIND, nullptr);
|
||||
LOGD("Bind mount " REDIR_PATH " -> /sdcard\n");
|
||||
}
|
||||
restore_ramdisk_init();
|
||||
} else {
|
||||
@ -44,7 +45,7 @@ void FirstStageInit::prepare() {
|
||||
}
|
||||
}
|
||||
|
||||
void LegacySARInit::first_stage_prep() {
|
||||
void MagiskInit::redirect_second_stage() {
|
||||
// Patch init binary
|
||||
int src = xopen("/init", O_RDONLY);
|
||||
int dest = xopen("/data/init", O_CREAT | O_WRONLY, 0);
|
||||
@ -61,7 +62,8 @@ void LegacySARInit::first_stage_prep() {
|
||||
xmount("/data/init", "/init", nullptr, MS_BIND, nullptr);
|
||||
}
|
||||
|
||||
bool SecondStageInit::prepare() {
|
||||
void MagiskInit::second_stage() {
|
||||
LOGI("Second Stage Init\n");
|
||||
umount2("/init", MNT_DETACH);
|
||||
umount2(INIT_PATH, MNT_DETACH); // just in case
|
||||
unlink("/data/init");
|
||||
@ -76,7 +78,8 @@ bool SecondStageInit::prepare() {
|
||||
// We are still on rootfs, so make sure we will execute the init of the 2nd stage
|
||||
unlink("/init");
|
||||
xsymlink(INIT_PATH, "/init");
|
||||
return true;
|
||||
patch_rw_root();
|
||||
} else {
|
||||
patch_ro_root();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user