Android P init进程reboot流程和调试方法

Android中的init进程是安卓系统用户空间启动的第一个进程。

相关源码:
system\core\reboot\reboot.c
system\core\init\init.cpp
system\core\init\reboot.cpp

inti进程源码路径为:
system/core/init/

reboot启动路程
reboot是一个二进制可执行文件,其源码路径为:
system\core\reboot

该目录只有两个文件,一个编译文件,一个c文件:
Android.bp
reboot.c

在system\core\reboot目录下编译,生成reboot可执行文件,生成目录在system/bin中

当我们在执行reboot命令时,就是执行的system/bin/reboot

int main(int argc, char* argv[]) {
    int ret;
    size_t prop_len;
    char property_val[PROPERTY_VALUE_MAX];
    static const char reboot[] = "reboot";
    const char* cmd = reboot;
    char* optarg = "";

    opterr = 0;
    do {
        int c;



        c = getopt(argc, argv, "p");

        if (c == -1) {
            break;
        }

        switch (c) {
        case 'p':
            cmd = "shutdown";
            break;
        case '?':
            fprintf(stderr, "usage: %s [-p] [rebootcommand]\n", argv[0]);
            exit(EXIT_FAILURE);
        }
    } while (1);

    if(argc > optind + 1) {
        fprintf(stderr, "%s: too many arguments\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    if (argc > optind)
        optarg = argv[optind];
    if (!optarg || !optarg[0]) optarg = "shell";

    prop_len = snprintf(property_val, sizeof(property_val), "%s,%s", cmd, optarg);
    if (prop_len >= sizeof(property_val)) {
        fprintf(stderr, "%s command too long: %s\n", cmd, optarg);
        exit(EXIT_FAILURE);
    }

    ret = property_set(ANDROID_RB_PROPERTY, property_val);
    if (ret < 0) {
        perror(cmd);
        exit(EXIT_FAILURE);
    }

    // Don't return early. Give the reboot command time to take effect
    // to avoid messing up scripts which do "adb shell reboot && adb wait-for-device"
    if (cmd == reboot) {
        while (1) {
            pause();
        }
    }

    fprintf(stderr, "Done\n");
    return 0;
}

这里我们主要看ret = property_set(ANDROID_RB_PROPERTY, property_val);

#define ANDROID_RB_PROPERTY “sys.powerctl”

即设置了属性值sys.powerctl为“reboot,adb”或者“reboot,shell”或者“shutdown,shell”或者“reboot,-p”

“reboot,adb”,表示在adb中输入adb reboot进行重启
“reboot,shell”,表示在shell中输入reboot进行重启
“shutdown,shell”,表示在shell中输入reboot -p进行关机
“reboot,-p”,表示在adb中输入adb reboot -p进行关机

system/core/init/init.cpp

void property_changed(const std::string& name, const std::string& value) {
    // If the property is sys.powerctl, we bypass the event queue and immediately handle it.
    // This is to ensure that init will always and immediately shutdown/reboot, regardless of
    // if there are other pending events to process or if init is waiting on an exec service or
    // waiting on a property.
    // In non-thermal-shutdown case, 'shutdown' trigger will be fired to let device specific
    // commands to be executed.
    if (name == "sys.powerctl") {
		
		//property_set("vendor.reboot", "reboot");
		
        // Despite the above comment, we can't call HandlePowerctlMessage() in this function,
        // because it modifies the contents of the action queue, which can cause the action queue
        // to get into a bad state if this function is called from a command being executed by the
        // action queue.  Instead we set this flag and ensure that shutdown happens before the next
        // command is run in the main init loop.
        // TODO: once property service is removed from init, this will never happen from a builtin,
        // but rather from a callback from the property service socket, in which case this hack can
        // go away.
        shutdown_command = value;
        do_shutdown = true;
        
        
    }

    if (property_triggers_enabled) ActionManager::GetInstance().QueuePropertyChange(name, value);

    if (waiting_for_prop) {
        if (wait_prop_name == name && wait_prop_value == value) {
            LOG(INFO) << "Wait for property took " << *waiting_for_prop;
            ResetWaitForProp();
        }
    }
}

property_changed中监听了系统属性的变化,并且在sys.powerctl属性变化时,将do_shutdown = true;

我们再来看main函数中的执行:

int main(int argc, char** argv) {
    while (true) {
        // By default, sleep until something happens.
        int epoll_timeout_ms = -1;

        if (do_shutdown && !shutting_down) {
            do_shutdown = false;
            //modify by sunxiaolin 20191030
            LOG(INFO) << "sunxiaolin,init,sys.powerctl reboot or shutdown sleep(5000)!";
            property_set("vendor.reboot", "reboot");
            if (!(waiting_for_prop || Service::is_exec_service_running())) {
				//LOG(INFO) << "sunxiaolin,init,ExecuteOneCommand!";
            	am.ExecuteOneCommand();
        	}
        
            sleep(3);
        
            if (HandlePowerctlMessage(shutdown_command)) {
                shutting_down = true;
            }
        }

		//modify by sunxiaolin 20191105
        if (!(waiting_for_prop || Service::is_exec_service_running())) {
            am.ExecuteOneCommand();
        }
	}
}

如果收到sys.powerctl属性的变化,条件do_shutdown && !shutting_down得到满足,将执行:
HandlePowerctlMessage

system\core\init\reboot.cpp

bool HandlePowerctlMessage(const std::string& command) {
    unsigned int cmd = 0;
    std::vector<std::string> cmd_params = Split(command, ",");
    std::string reboot_target = "";
    bool run_fsck = false;
    bool command_invalid = false;

    if (cmd_params.size() > 3) {
        command_invalid = true;
    } else if (cmd_params[0] == "shutdown") {
        cmd = ANDROID_RB_POWEROFF;
        if (cmd_params.size() == 2) {
            if (cmd_params[1] == "userrequested") {
                // The shutdown reason is PowerManager.SHUTDOWN_USER_REQUESTED.
                // Run fsck once the file system is remounted in read-only mode.
                run_fsck = true;
            } else if (cmd_params[1] == "thermal") {
                // Turn off sources of heat immediately.
                TurnOffBacklight();
                // run_fsck is false to avoid delay
                cmd = ANDROID_RB_THERMOFF;
            }
        }
    } else if (cmd_params[0] == "reboot") {
        cmd = ANDROID_RB_RESTART2;
        if (cmd_params.size() >= 2) {
            reboot_target = cmd_params[1];
            // When rebooting to the bootloader notify the bootloader writing
            // also the BCB.
            if (reboot_target == "bootloader") {
                std::string err;
                if (!write_reboot_bootloader(&err)) {
                    LOG(ERROR) << "reboot-bootloader: Error writing "
                                  "bootloader_message: "
                               << err;
                }
            } else if (reboot_target == "recovery") {
                std::string err;
                if (!write_reboot_recovery(&err)) {
                    LOG(ERROR) << "reboot-recovery: Error writing "
                                  "recovery_message: "
                               << err;
                }
            }
            // If there is an additional parameter, pass it along
            if ((cmd_params.size() == 3) && cmd_params[2].size()) {
                reboot_target += "," + cmd_params[2];
            }
        }
    } else {
        command_invalid = true;
    }
    if (command_invalid) {
        LOG(ERROR) << "powerctl: unrecognized command '" << command << "'";
        return false;
    }

    LOG(INFO) << "Clear action queue and start shutdown trigger";
    ActionManager::GetInstance().ClearQueue();
    // Queue shutdown trigger first
    ActionManager::GetInstance().QueueEventTrigger("shutdown");
    // Queue built-in shutdown_done
    auto shutdown_handler = [cmd, command, reboot_target, run_fsck](const BuiltinArguments&) {
        DoReboot(cmd, command, reboot_target, run_fsck);
        return Success();
    };
    ActionManager::GetInstance().QueueBuiltinAction(shutdown_handler, "shutdown_done");

    // Skip wait for prop if it is in progress
    ResetWaitForProp();

    // Clear EXEC flag if there is one pending
    for (const auto& s : ServiceList::GetInstance()) {
        s->UnSetExec();
    }

    return true;
}

编译
在system/core/init下面mm,生成symbols/init

调试
直接push到根目录生效
adb push Z:\imx8_p9.0.0_2.1.0_auto_ga\android9.0.0\out\target\product\mek_8q\symbols\init /

<think>我们正在讨论如何关闭开机时init进程设置的SELinux权限。根据提供的参考资料,我们可以采取临时关闭或永久关闭的方式。但是用户特别询问了关于init进程设置selinux权限的关闭方法,因此我们需要关注系统启动过程中如何控制SELinux的状态。 参考引用: - 引用[1]中提到临时关闭SELinux的方法:`setenforce 0`(临时关闭直到下次重启)永久关闭需要修改系统属性(如设置`ro.boot.selinux=permissive`或修改内核参数)。 - 引用[3]提到在初始化过程中通过`security_getenforce()``selinux_is_enforcing()`来判断是否开启SELinux,并根据结果设置。 因此,关闭init进程设置的SELinux权限的方法主要分为两种: ### 一、临时关闭(无需重启生效,但重启后恢复) 1. **通过adb命令**(需要root权限): ```bash adb shell su -c "setenforce 0" ``` 此命令将SELinux模式设置为Permissive(宽容模式),即不强制执行安全策略,仅记录违规行为。但重启后恢复为原设置。 ### 二、永久关闭(需修改系统配置,重启生效) 1. **修改系统属性**(适用于部分设备): - 在bootloader命令行添加内核参数: ```bash androidboot.selinux=permissive ``` 或者修改`/boot`分区下的cmdline(需要解锁bootloaderroot权限)。 - 修改系统属性文件(如`/system/build.prop`或`/vendor/default.prop`),添加: ```properties ro.boot.selinux=permissive ``` 但注意Android 8.0以后禁止在`default.prop`中设置,需通过bootloader传递参数。 2. **修改init进程代码逻辑**(需重新编译系统): 根据引用[3],在系统源码中修改`system/core/init/selinux.cpp`的初始化逻辑。例如,强制设置enforce状态为0: ```cpp // 在selinux_initialize()函数中找到设置enforce的地方,修改为: if (selinux_is_enforcing() > 0) { selinux_set_enforce(0); // 强制设为Permissive } ``` 或修改启动参数解析逻辑,使系统始终以Permissive模式启动。 ### 三、绕过SELinux权限检查(针对服务启动) 引用[2]提到,在service定义中添加`seclabel`可以指定服务的SELinux上下文。如果不想为某个服务编写完整的SELinux策略,可以尝试将其上下文设置为宽容模式下的类型(但这不是关闭整个系统的SELinux)。 ### 验证方法 - 检查当前SELinux状态: ```bash adb shell getenforce ``` 若返回`Permissive`则关闭成功。 ### 注意事项 - **安全风险**:关闭SELinux会降低系统安全性,仅用于调试- **系统稳定性**:部分系统功能依赖SELinux,关闭可能导致异常。 - **恢复**:修改系统属性或内核参数后,若无法启动,需进入恢复模式还原。 ### 相关问题 1. 如何在Android设备上临时禁用SELinux? 2. 如何通过修改内核启动参数永久关闭SELinux? 3. 在AOSP源码中,哪个文件控制了SELinux的初始化? 4. 如何为Android系统服务定制SELinux策略? 5. 如何调试因SELinux策略导致的服务启动失败? [^1]: android13 关闭selinux 临时关闭或者永久关闭 [^2]: Android添加开机启动服务程序关于Selinux权限问题说明 [^3]: 开机自动关闭SELinux权限 </think>在Android系统的启动过程中,init进程负责初始化SELinux策略。以下是关闭init进程中SELinux权限设置的完整方法,分为临时关闭永久关闭两种方案: --- ### 一、临时关闭方法(重启后恢复) 1. **通过ADB命令关闭** ```bash adb shell su -c "setenforce 0" # 立即切换为Permissive模式 ``` - **验证状态**: ```bash adb shell getenforce # 返回"Permissive"表示成功 ``` - **持续时间**:持续到下次重启[^1] 2. **在init.rc中动态注入** 在设备启动后执行: ```bash adb shell "echo 'setenforce 0' >> /init.rc" && adb reboot ``` - ⚠️ 需解锁system分区 - 效果:本次启动期间生效 --- ### 二、永久关闭方法(需源码修改) #### 方案1:修改SELinux初始化逻辑 1. 修改文件:`system/core/init/selinux.cpp` 2. 定位函数:`selinux_initialize()` 3. 添加代码: ```cpp // 在函数开头添加强制关闭 security_setenforce(0); // 强制设置为Permissive模式 return; // 跳过后续初始化 ``` 参考修改点位置[^3]: ``` |-- selinux_initialize() |-- if (selinux_is_enforcing() != 1) |-- 添加强制关闭代码 ``` #### 方案2:修改启动参数 1. 修改文件:`device/<厂商>/<设备>/BoardConfig.mk` 2. 添加配置: ```makefile # 强制Permissive模式 BOARD_KERNEL_CMDLINE += androidboot.selinux=permissive ``` 或修改内核参数: ```bash BOOT_IMAGE=/kernel ... androidboot.selinux=permissive ``` #### 方案3:禁用策略编译(AOSP级) 在设备配置中: ```makefile # 在device.mk中添加 BOARD_SEPOLICY_IGNORE := true # 完全忽略策略 BOARD_NEVER_ALLOW_PERMISSIVE := 0 # 允许Permissive模式 ``` --- ### 三、调试验证方法 1. **检查内核日志**: ```bash adb shell dmesg | grep -i selinux # 期望输出: "SELinux: Disabled at boot" ``` 2. **检查服务状态**: ```bash adb shell getprop | grep selinux # 期望输出: [ro.boot.selinux]: [permissive] ``` 3. **使用audit2allow工具**[^4]: ```bash adb logcat -b events | audit2allow -p policy.29.0 # 若无拒绝日志,说明已关闭 ``` --- ### 四、风险与注意事项 1. **安全风险**: - 📛 禁用后设备易受提权攻击 - 允许任意进程访问系统资源[^1] 2. **兼容性问题**: - 部分系统服务(如Gatekeeper)依赖SELinux - CTS认证要求强制开启 3. **恢复方案**: ```bash # 紧急恢复命令 adb shell su -c "setenforce 1 && reboot" ``` --- ### 相关问题 1. 如何为特定服务定制SELinux策略而不完全关闭? 2. 在SELinux强制模式下,如何调试服务启动失败问题? 3. Android启动过程中SELinux初始化的具体流程是怎样的? 4. 如何通过内核参数控制SELinux的启动模式? 5. 使用`audit2allow`工具时如何解析自定义策略文件? 6. 在AOSP中修改SELinux初始化代码后如何验证修改有效性? [^1]: android13 关闭selinux 临时关闭或者永久关闭 [^3]: 开机自动关闭SELinux权限 [^4]: 使用 audit2allow 工具添加SELinux权限的方法
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sunxiaolin2016

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值