安卓15开机动画BootAnimation启动源码简单分析

前言

安卓 启动链路里,SurfaceFlinger 一定先于 BootAnimation 工作起来,否则开机动画根本没有显示目标。因此,SurfaceFlinger 是 bootanimation 的前置依赖。

相关源码路径

bash 复制代码
bootanimation   frameworks/base/cmds/bootanimation/
surfaceflinger  frameworks/native/services/surfaceflinger/
init            system/core/init/

surfaceflinger启动

安卓内核起来后会启动第一个init进程。init进程会根据init.rc(system/core/rootdir/init.rc)配置启动surfaceflinger进程。

rc 复制代码
# surfaceflinger.rc

service surfaceflinger /system/bin/surfaceflinger
    class core animation
    user system
    group graphics drmrpc readproc
    capabilities SYS_NICE
    onrestart restart --only-if-running zygote
    task_profiles HighPerformance
    socket pdx/system/vr/display/client     stream 0666 system graphics u:object_r:pdx_display_client_endpoint_socket:s0
    socket pdx/system/vr/display/manager    stream 0666 system graphics u:object_r:pdx_display_manager_endpoint_socket:s0
    socket pdx/system/vr/display/vsync      stream 0666 system graphics u:object_r:pdx_display_vsync_endpoint_socket:s0

surfaceflinger有一个单独的rc文件,定义了class core animation

rc 复制代码
# system/core/rootdir/init.rc

on boot
	......
    chown system system /sys/kernel/ipv4/tcp_rmem_max
    chown root radio /proc/cmdline
    chown root system /proc/bootconfig

    # Define default initial receive window size in segments.
    setprop net.tcp_def_init_rwnd 60

    # Start standard binderized HAL daemons
    class_start hal

	# 这里,启动所有core类
    class_start core

init.rc 的执行流程中,Android 不再倾向于逐个手动 start 服务,而是通过 class_start 命令来批量启动同一类别的服务。

  • 当系统启动进入特定阶段(如 on boot)时,init.rc 会执行 class_start core
  • 因为 SurfaceFlinger 被标记为 core 类,init 进程会自动扫描所有加载的 .rc 文件,并启动所有属于该类的服务。

surfaceflinger进程便启动了,跟着就会跑进程的main()函数,即frameworks/native/services/surfaceflinger/main_surfaceflinger.cpp。这个main_surfaceflinger.cpp就是第一个执行的文件,因为它包含了程序的入口点 main() 函数。

cpp 复制代码
/* main_surfaceflinger.cpp */

int main(int, char**) {
    sp<SurfaceFlinger> flinger = surfaceflinger::createSurfaceFlinger(); // 创建surfaceflinger服务
    
    flinger->init(); // 初始化SurfaceFlinger
    
    // 将SurfaceFlinger注册为系统服务
    sp<IServiceManager> sm(defaultServiceManager());
    sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false,
                   IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);
    
    // run surface flinger in this thread
    flinger->run();

    return 0;
}

cpp 复制代码
/* SurfaceFlinger.cpp */
void SurfaceFlinger::init() FTL_FAKE_GUARD(kMainThreadContext) {
	...
    // 异步设置系统属性
    // Avoid blocking the main thread on `init` to set properties.
    mInitBootPropsFuture.callOnce([this] {
        return std::async(std::launch::async, &SurfaceFlinger::initBootProperties, this);
    });
    ...
}

void SurfaceFlinger::initBootProperties() {
    property_set("service.sf.present_timestamp", mHasReliablePresentFences ? "1" : "0");

    if (base::GetBoolProperty("debug.sf.boot_animation"s, true)) {
        // Reset and (if needed) start BootAnimation.
        property_set("service.bootanim.exit", "0"); // 这个属性bootanimation进程里会周期检查,=1时就退出动画,这里=0表示要播放动画
        property_set("service.bootanim.progress", "0");
        property_set("ctl.start", "bootanim");	// 启动 开机动画
    }
}

这样bootanim进程就会启动?凭什么设置了一个属性就启动了?


那么下面我们来看,/system/core/init/main.cpp ,在看init进程的main.cpp的main函数中:

cpp 复制代码
/* system/core/init/main.cpp */

int main(int argc, char** argv) {
...

    if (argc > 1) {
        if (!strcmp(argv[1], "subcontext")) {
            android::base::InitLogging(argv, &android::base::KernelLogger);
            const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();

            return SubcontextMain(argc, argv, &function_map);
        }

        if (!strcmp(argv[1], "selinux_setup")) {
            return SetupSelinux(argv);
        }

        if (!strcmp(argv[1], "second_stage")) {
            return SecondStageMain(argc, argv); // 第二阶段则进一步加载系统配置并启动系统服务,SecondStageMain是在init.cpp中
        }
    }

    return FirstStageMain(argc, argv);
}
cpp 复制代码
/* system/core/init/init.cpp */

int SecondStageMain(int argc, char** argv) {
	...
    StartPropertyService(&property_fd); // 在property_service.cpp中定义,这里先执行
    ...

	while (true) {
        ...
        auto epoll_result = epoll.Wait(epoll_timeout); // 等待事件(被 WakeMainInitThread() 唤醒),这里等到后面才会用到
        if (!epoll_result.ok()) {
            LOG(ERROR) << epoll_result.error();
        }
        if (!IsShuttingDown()) {
            HandleControlMessages();
            SetUsbController();
        }
    }

    return 0;        
}
cpp 复制代码
/* system/core/init/property_service.cpp */

void StartPropertyService(int* epoll_socket) {
    InitPropertySet("ro.property_service.version", "2");

    int sockets[2];
    if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sockets) != 0) {
        PLOG(FATAL) << "Failed to socketpair() between property_service and init";
    }
    *epoll_socket = from_init_socket = sockets[0];
    init_socket = sockets[1];
    StartSendingMessages();

    // 启动属性服务线程
    StartThread(PROP_SERVICE_FOR_SYSTEM_NAME, 0660, AID_SYSTEM, property_service_for_system_thread,
                true);
    StartThread(PROP_SERVICE_NAME, 0666, 0, property_service_thread, false);

    auto async_persist_writes =
            android::base::GetBoolProperty("ro.property_service.async_persist_writes", false);

    if (async_persist_writes) {
        persist_write_thread = std::make_unique<PersistWriteThread>();
    }
}




void StartThread(const char* name, int mode, int gid, std::thread& t, bool listen_init) {
    int fd = -1;
    if (auto result = CreateSocket(name, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
                                   /*passcred=*/false, /*should_listen=*/false, mode, /*uid=*/0,
                                   /*gid=*/gid, /*socketcon=*/{});
        result.ok()) {
        fd = *result;
    } else {
        LOG(FATAL) << "start_property_service socket creation failed: " << result.error();
    }

    listen(fd, 8);

    // 创建新线程,运行 PropertyServiceThread 函数
    auto new_thread = std::thread(PropertyServiceThread, fd, listen_init);
    t.swap(new_thread);
}




static void PropertyServiceThread(int fd, bool listen_init) {
    Epoll epoll; // 创建一个 epoll 实例,监听多个文件描述符(FD)的事件
    if (auto result = epoll.Open(); !result.ok()) {
        LOG(FATAL) << result.error();
    }

    // 将属性服务的 socket(fd)注册到 epoll,当有数据可读时,调用 handle_property_set_fd 处理。
    if (auto result = epoll.RegisterHandler(fd, std::bind(handle_property_set_fd, fd));
        !result.ok()) {
        LOG(FATAL) << result.error();
    }

    ...
}





static void handle_property_set_fd(int fd) {
switch (cmd) {
    case PROP_MSG_SETPROP: {
        ...
        const auto& cr = socket.cred();
        std::string error;
        // 这里的HandlePropertySetNoSocket,最后也会调用HandlePropertySet
        auto result = HandlePropertySetNoSocket(prop_name, prop_value, source_context, cr, &error);
        if (result != PROP_SUCCESS) {
            LOG(ERROR) << "Unable to set property '" << prop_name << "' from uid:" << cr.uid
                       << " gid:" << cr.gid << " pid:" << cr.pid << ": " << error;
        }

        break;
      }

    case PROP_MSG_SETPROP2: {
        ...
        // 这里的HandlePropertySet
        auto result = HandlePropertySet(name, value, source_context, cr, &socket, &error);
        if (!result) {
            // Result will be sent after completion.
            return;
        }
        if (*result != PROP_SUCCESS) {
            LOG(ERROR) << "Unable to set property '" << name << "' from uid:" << cr.uid
                       << " gid:" << cr.gid << " pid:" << cr.pid << ": " << error;
        }
        socket.SendUint32(*result);
        break;
      }

    default:
        LOG(ERROR) << "sys_prop: invalid command " << cmd;
        socket.SendUint32(PROP_ERROR_INVALID_CMD);
        break;
    }
}

在之前的SurfaceFlinger::initBootProperties中,传入的参数name=ctl.start,value=bootanim

cpp 复制代码
/* system/core/init/property_service.cpp */

std::optional<uint32_t> HandlePropertySet(const std::string& name, const std::string& value,
                                          const std::string& source_context, const ucred& cr,
                                          SocketConnection* socket, std::string* error) {
    if (auto ret = CheckPermissions(name, value, source_context, cr, error); ret != PROP_SUCCESS) {
        return {ret};
    }

    if (StartsWith(name, "ctl.")) {
        // 这里,最终经过裁剪后,传入的是start和bootanim
        return {SendControlMessage(name.c_str() + 4, value, cr.pid, socket, error)};
    }

    ...
}

static uint32_t SendControlMessage(const std::string& msg, const std::string& name, pid_t pid,
                                   SocketConnection* socket, std::string* error) {
    ...

    bool queue_success = QueueControlMessage(msg, name, pid, fd); // 将消息加入队列
    if (!queue_success && fd != -1) {
        uint32_t response = PROP_ERROR_HANDLE_CONTROL_MESSAGE;
        TEMP_FAILURE_RETRY(send(fd, &response, sizeof(response), 0));
        close(fd);
    }

    return PROP_SUCCESS;
}
cpp 复制代码
/* system/core/init/init.cpp */

bool QueueControlMessage(const std::string& message, const std::string& name, pid_t pid, int fd) {
    auto lock = std::lock_guard{pending_control_messages_lock};
    if (pending_control_messages.size() > 100) {
        LOG(ERROR) << "Too many pending control messages, dropped '" << message << "' for '" << name
                   << "' from pid: " << pid;
        return false;
    }
    pending_control_messages.push({message, name, pid, fd});
    WakeMainInitThread(); // 唤醒主线程!通知 init 主循环处理
    return true;
}

在回到system/core/init/init.cpp的SecondStageMain主循环处理:

cpp 复制代码
/* system/core/init/init.cpp */

int SecondStageMain(int argc, char** argv) {

	while (true) {
        ...
        auto epoll_result = epoll.Wait(epoll_timeout); // 等待事件(被 WakeMainInitThread() 唤醒)
        if (!epoll_result.ok()) {
            LOG(ERROR) << epoll_result.error();
        }
        if (!IsShuttingDown()) {
            HandleControlMessages(); //这里,HandleControlMessages会调用HandleControlMessage
            SetUsbController();
        }
    }

    return 0;        
}



static bool HandleControlMessage(std::string_view message, const std::string& name,
                                 pid_t from_pid) {    
	const auto& map = GetControlMessageMap(); //这里,查表获取处理函数,GetControlMessageMap定义在下面
    const auto it = map.find(action); // // action = "start"
    if (it == map.end()) {
        LOG(ERROR) << "Unknown control msg '" << message << "'";
        return false;
    }
    const auto& function = it->second; // 对应启动服务的函数指针

    // // 调用实际的 Start 函数
    if (auto result = function(service); !result.ok()) {
        LOG(ERROR) << "Control message: Could not ctl." << message << " for '" << name
                   << "' from pid: " << from_pid << " (" << process_cmdline
                   << "): " << result.error();
        return false;
    }
}    

// 查表对应的处理函数
static const std::map<std::string, ControlMessageFunction, std::less<>>& GetControlMessageMap() {
    // clang-format off
    static const std::map<std::string, ControlMessageFunction, std::less<>> control_message_functions = {
		...
        {"start",             DoControlStart}, // 我们是这个 start
        {"stop",              DoControlStop},
        {"restart",           DoControlRestart},
    };
    // clang-format on
    return control_message_functions;
}
static Result<void> DoControlStart(Service* service) {
    return service->Start(); //至此,就启动了bootanimation
}

其它

"挂载分区"含义

给物理存储分区分配一个 "可访问的目录路径";

安卓场景的具体例子

比如系统启动时 init.rc 里的这句配置:

bash 复制代码
mount ext4 /dev/block/system /system ro wait

拆解就是:

  • ext4:分区的文件系统格式;
  • /dev/block/system:物理存储分区的设备节点;
  • /system:挂载点;
  • ro:挂载为只读。

挂载前:/system 只是一个空目录,/dev/block/system 是一块无法访问的存储;

挂载后:访问 /system/bin/bootanimation 就等于直接读写 /dev/block/system 分区里的 bootanimation 文件。

相关推荐
Hi~晴天大圣2 小时前
MySQL中JSON 格式字段里某个值修改
android·mysql·json
BoomHe2 小时前
Kotlin shareIn 和 stateIn 使用场景
android·kotlin·android jetpack
张雨zy2 小时前
Vue 的 v-if 与 v-show,Android 的 GONE 与 INVISIBLE
android·前端·vue.js
飘逸飘逸3 小时前
Autojs进阶-插件更新记录
android·javascript
Be for thing3 小时前
Android 传感器硬件原理 + 功耗测试与异常定位实战(手表 / IoT / 手机通用)
android·学习·智能手机
阿拉斯攀登3 小时前
第 8 篇 RK 平台安卓驱动实战 1:GPIO 输入输出驱动,从内核到 App 全流程打通
android·驱动开发·rk3568·瑞芯微·rk安卓驱动
常利兵3 小时前
告别SharedPreferences!DataStore+Android Keystore构建安全存储新防线
android·安全
2501_915918413 小时前
网站抓包解析,掌握浏览器请求和 HTTPS 数据分析的流程
android·ios·小程序·https·uni-app·iphone·webview
黄林晴3 小时前
Android 17 要下狠手了:无障碍服务 API 将被严格限制
android