Android Framework实战视频--init进程的bootanimation启动源码分析(补充Android 10部分的BootAnimation的启动源码分析)

在线学习课程,课程咨询答疑和新课信息:QQ交流群:422901085进行课程讨论
转自于:https://blog.csdn.net/learnframework/article/details/116719986

课程答疑和新课信息:QQ交流群:422901085进行课程讨论
FrameWork入门课视频链接:https://edu.csdn.net/course/detail/30298
FrameWork实战课1视频链接:https://edu.csdn.net/course/detail/30275
FrameWork跨进程通信视频链接:https://edu.csdn.net/course/detail/35911
专题博客系列:
Android 8.1 zygote 启动过程源码
Android Framework实战视频--Zygote的fork进程篇
Android Framework实战视频--SystemServer启动篇
Android Framework实战视频--SystemServer启动FallbackHome篇
Android Framework实战视频--FallbackHome进程启动及Activity启动篇
Android Framework实战视频--FallbackHome结束启动Launcher篇
Android Framework实战视频--BootAnimation的启动源码分析(Android8.1)

Android Framework实战视频--init进程的bootanimation启动源码分析(补充Android 10部分的BootAnimation的启动源码分析)

Android Framework实战视频--BootAnimation的启动源码分析(补充Android 10部分的差异)

提示:针对有的同学可能代码较新这里基于Android 10源码对init部分进行分析
针对Android init进程启动property service的启动部分流程如下:
init进程的入口main函数已经不在init.cpp而是在main.cpp
路径如下:
system/core/init/main.cpp

int main(int argc, char** argv) {
#if __has_feature(address_sanitizer)
    __asan_set_error_report_callback(AsanReportCallback);
#endif

    if (!strcmp(basename(argv[0]), "ueventd")) {
        return ueventd_main(argc, argv);
    }

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

            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);//这里是关键,二阶段启动
        }
    }

    return FirstStageMain(argc, argv);
}

这里主要看的是二阶段启动方法SecondStageMain,该方法又是回到init.cpp

int SecondStageMain(int argc, char** argv) {
    //省略
    StartPropertyService(&property_fd);
    if (auto result = epoll.RegisterHandler(property_fd, HandlePropertyFd); !result) { //监听fd的事件
        LOG(FATAL) << "Could not register epoll handler for property fd: " << result.error();
    }
//省略
    return 0;
}

这里又看一个熟悉的方法StartPropertyService,而且传递进去了一个property_fd地址,然后对property_fd进行监听,该方法如下:

void StartPropertyService(int* epoll_socket) {
    property_set("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";
    }
    //特别注意这里双工通信,可以实现0端写入1端读取,1端写入0端读取
    *epoll_socket = sockets[0];//把fd传递给了指针
    init_socket = sockets[1];

    property_set_fd = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,false, 0666, 0, 0, nullptr);//创建PROP_SERVICE_NAME 的socket进行通信
    if (property_set_fd == -1) {
        PLOG(FATAL) << "start_property_service socket creation failed";
    }

    listen(property_set_fd, 8);

    std::thread{PropertyServiceThread}.detach();//启动线程监听数据

    property_set = [](const std::string& key, const std::string& value) -> uint32_t {
        android::base::SetProperty(key, value);
        return 0;
    };
}

这里其实和8.1差不多,主要创建socket,监听socket绑定和接收数据(特别注意这里双工通信,可以实现0端写入1端读取,1端写入0端读取),而且接收数据和对数据处理是在PropertyServiceThread方法中实现:

static void PropertyServiceThread() {
    Epoll epoll;
    if (auto result = epoll.Open(); !result) {
        LOG(FATAL) << result.error();
    }

    if (auto result = epoll.RegisterHandler(property_set_fd, handle_property_set_fd); !result) {
        LOG(FATAL) << result.error();
    }

    if (auto result = epoll.RegisterHandler(init_socket, HandleInitSocket); !result) {
        LOG(FATAL) << result.error();
    }

    while (true) {
        if (auto result = epoll.Wait(std::nullopt); !result) {
            LOG(ERROR) << result.error();
        }
    }
}

这里主要使用了epoll来监听各个fd的变化,这里我们主要关心是epoll.RegisterHandler(property_set_fd, handle_property_set_fd); !result),这个property_set_fd才是我们关心的fd,有数据变化这里会触发handle_property_set_fd方法:

static void handle_property_set_fd() {
  //省略
    switch (cmd) {
    case PROP_MSG_SETPROP: {
        //省略
        uint32_t result =HandlePropertySet(prop_name, prop_value, source_context, cr, nullptr, &error);     
        //省略
        break;
      }

    case PROP_MSG_SETPROP2: {
      //省略
        uint32_t result = HandlePropertySet(name, value, source_context, cr, &socket, &error);
        //省略
    default:
      //省略
        break;
    }
}

这里最后其实最后调用到了HandlePropertySet:

// This returns one of the enum of PROP_SUCCESS or PROP_ERROR*.
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 (StartsWith(name, "ctl.")) {//开机动画就是符合这个
        return SendControlMessage(name.c_str() + 4, value, cr.pid, socket, error);
    }
//省略

    return PropertySet(name, value, error);
}

代码可以看出开机动画就是符合这个“ctrl.”情况接下来执行SendControlMessage:

static uint32_t SendControlMessage(const std::string& msg, const std::string& name, pid_t pid,SocketConnection* socket, std::string* error) {
   //省略
    if (auto result = SendMessage(init_socket, property_msg); !result) {
        // We've already released the fd above, so if we fail to send the message to init, we need
        // to manually free it here.
        if (fd != -1) {
            close(fd);
        }
        *error = "Failed to send control message: " + result.error_string();
        return PROP_ERROR_HANDLE_CONTROL_MESSAGE;
    }

    return PROP_SUCCESS;
}

这里其实就是调用SendMessage来发一个消息,但是这里大家注意发给了init_socket这个fd(就是前面说过的0端写入1端读取),那接下来在就会在init.cpp的HandlePropertyFd收到消息,故来分析方法:

static void HandlePropertyFd() {
    auto message = ReadMessage(property_fd);
   //省略
    switch (property_message.msg_case()) {
        case PropertyMessage::kControlMessage: {
            auto& control_message = property_message.control_message();
            //这里是关键,又会调用HandleControlMessage启动及判断是否成功
            bool success = HandleControlMessage(control_message.msg(), control_message.name(),
                                                control_message.pid());

            uint32_t response = success ? PROP_SUCCESS : PROP_ERROR_HANDLE_CONTROL_MESSAGE;
            if (control_message.has_fd()) {
                int fd = control_message.fd();
                TEMP_FAILURE_RETRY(send(fd, &response, sizeof(response), 0));
                close(fd);
            }
            break;
        }
        case PropertyMessage::kChangedMessage: {
            auto& changed_message = property_message.changed_message();
            property_changed(changed_message.name(), changed_message.value());
            break;
        }
        default:
            LOG(ERROR) << "Unknown message type from property service: "
                       << property_message.msg_case();
    }
}

这里最后又调用到HandleControlMessage:

bool HandleControlMessage(const std::string& msg, const std::string& name, pid_t pid) {
//获取一个control msg的map
    const auto& map = get_control_message_map();
    const auto it = map.find(msg);
   //省略
    const ControlMessageFunction& function = it->second;//得到对应function

    Service* svc = nullptr;

    switch (function.target) {
        case ControlTarget::SERVICE:
            svc = ServiceList::GetInstance().FindService(name);//寻找出对于service
            break;
        case ControlTarget::INTERFACE:
            svc = ServiceList::GetInstance().FindInterface(name);
            break;
        default:
            LOG(ERROR) << "Invalid function target from static map key '" << msg << "': "
                       << static_cast<std::underlying_type<ControlTarget>::type>(function.target);
            return false;
    }

    if (svc == nullptr) {
        LOG(ERROR) << "Could not find '" << name << "' for ctl." << msg;
        return false;
    }

    if (auto result = function.action(svc); !result) {//获取service后,会调用function进行执行
        LOG(ERROR) << "Could not ctl." << msg << " for '" << name << "': " << result.error();
        return false;
    }
    return true;
}

其实就是根据control msg获取对应的function,然后执行方法,那具体执行什么方法呢?
这里的get_control_message_map如下:

static const std::map<std::string, ControlMessageFunction>& get_control_message_map() {
    // clang-format off
    static const std::map<std::string, ControlMessageFunction> control_message_functions = {
        {"sigstop_on",        {ControlTarget::SERVICE,
                               [](auto* service) { service->set_sigstop(true); return Success(); }}},
        {"sigstop_off",       {ControlTarget::SERVICE,
                               [](auto* service) { service->set_sigstop(false); return Success(); }}},
        {"start",             {ControlTarget::SERVICE,   DoControlStart}},
        {"stop",              {ControlTarget::SERVICE,   DoControlStop}},
        {"restart",           {ControlTarget::SERVICE,   DoControlRestart}},
        {"interface_start",   {ControlTarget::INTERFACE, DoControlStart}},
        {"interface_stop",    {ControlTarget::INTERFACE, DoControlStop}},
        {"interface_restart", {ControlTarget::INTERFACE, DoControlRestart}},
    };
    // clang-format on

    return control_message_functions;
}

所以这里我们bootanimation("ctrl.start")明显属于start,所以匹配的方法为DoControlStart:

static Result<Success> DoControlStart(Service* service) {
    return service->Start();
}

看到service->Start();后就知道和以前8.1一模一样了,都是service启动,不再进行分析,看对于视频或者blog既可以

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,245评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,749评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,960评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,575评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,668评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,670评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,664评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,422评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,864评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,178评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,340评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,015评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,646评论 3 323
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,265评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,494评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,261评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,206评论 2 352

推荐阅读更多精彩内容