首先来看一下BootAnimation的.rc文件 bootanim.rc,从class core animation可知,该进程是属于core和animation两大类的进程,但注意到,bootanim.rc和surfaceflinger.rc相比较,bootanim.rc多了一个disabled,我们知道,当init进程去执行init.rc的时候,执行到on boot块中的class_start core 语句的时候,就会启动core类的进程,其实,更准确来讲,是启动所有非disabled 的core类进程,所以即使执行了class_start core,也不会启动BootAnimation进程。

//bootanim.rc

service bootanim /system/bin/bootanimation
    class core animation
    user graphics
    group graphics audio
    disabled
    oneshot
    writepid /dev/stune/top-app/tasks

执行了class_start core后,会触发到system/core/init/buildtins.cpp中的do_class_start方法的执行,

从StartIfNotDisabled可知,该方法会启动所有非disabled 相关的进程,所以也就不会启动BootAnimation进程。

// builtins.cpp

static int do_class_start(const std::vector<std::string>& args) {
        /* Starting a class does not start services
         * which are explicitly disabled.  They must
         * be started individually.
         */
 
    ServiceManager::GetInstance().
        ForEachServiceInClass(args[1], [] (Service* s) { s->StartIfNotDisabled(); });
    return 0;
}

那BootAnimation进程是在哪里启动的呢?

我们知道,android中的所有界面的显示都是需要surfaceflinger进程的绘制和渲染,所以BootAnimation进程肯定是在SurfaceFlinger之后启动的,我们先看一下surfaceflinger进程的代码

//main_sufaceflinger.cpp

int main(int, char**) {
   
    ........省略
   
    flinger->init();

    ........省略

    flinger->run();

    return 0;
}
// SurfaceFlinger.cpp

void SurfaceFlinger::init() {
   
    ......省略

   //这里会创建一个线程
    if (getHwComposer().hasCapability(
            HWC2::Capability::PresentFenceIsNotReliable)) {
        mStartPropertySetThread = new StartPropertySetThread(false);
    } else {
        mStartPropertySetThread = new StartPropertySetThread(true);
    }

    //启动线程
    if (mStartPropertySetThread->Start() != NO_ERROR) {
        ALOGE("Run StartPropertySetThread failed!");
    }

    ALOGV("Done initializing");
}

当调用mStartPropertySetThread->Start() 之后会启动这个线程,启动线程之后,就会触发threadLoop()方法执行,执行了property_set("ctl.start", "bootanim") 这条语句就会去启动BootAnimation了

// StartPropertySetThread.cpp

//threadLoop()相当于java线程类中runable(),当调用StartPropertySetThread的时候就会触发该方法执行

bool StartPropertySetThread::threadLoop() {
    // Set property service.sf.present_timestamp, consumer need check its readiness
    property_set(kTimestampProperty, mTimestampPropertyValue ? "1" : "0");
    // Clear BootAnimation exit flag
    property_set("service.bootanim.exit", "0");
    // Start BootAnimation if not started
    property_set("ctl.start", "bootanim");
    // Exit immediately
    return false;
}

问题1:为什么执行了property_set("ctl.start", "bootanim")语句,设置了属性之后,就会启动BootAnimation了呢?

回答:在init.cpp的main方法中,会调用start_property_service() 来创建一个socket来进行跨进程通信,当我们在surfaceflinger进程中设置了property_set("ctl.start", "bootanim")之后,就会触发init进程中的handle_property_set_fd方法的执行

//property_service.cpp

void start_property_service() {
    property_set("ro.property_service.version", "2");

    property_set_fd = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
                                   false, 0666, 0, 0, nullptr, sehandle);
    if (property_set_fd == -1) {
        PLOG(ERROR) << "start_property_service socket creation failed";
        exit(1);
    }

    listen(property_set_fd, 8);

    register_epoll_handler(property_set_fd, handle_property_set_fd);
}

在 handle_property_set_fd方法中,会执行handle_property_set方法

//property.service.cpp

//最终会执行了handle_property_set方法

static void handle_property_set_fd() {
   
   .......省略

    switch (cmd) {
    case PROP_MSG_SETPROP: {
        .....省略

        handle_property_set(socket, prop_value, prop_value, true);
        break;
      }

    case PROP_MSG_SETPROP2: {
         .....省略

        handle_property_set(socket, name, value, false);
        break;
      }

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

/*
* 通过StartsWith(name, "ctl.")判断是否以ctr.l开头,而启动BootAnimation的时候,设置了属性
*  property_set("ctl.start", "bootanim"),刚好是ctl.开头,所以进入了if判断逻辑,执行
*  handle_control_message方法
*/

static void handle_property_set(SocketConnection& socket,
                                const std::string& name,
                                const std::string& value,
                                bool legacy_protocol) {
  
  ......省略

  if (android::base::StartsWith(name, "ctl.")) {
    if (check_control_mac_perms(value.c_str(), source_ctx, &cr)) {
       //property_set("ctl.start", "bootanim"),刚好是ctl.开头,所以执行到这里

      handle_control_message(name.c_str() + 4, value.c_str());
      
    } else {

      .....省略

    }
  } else {

    .....省略

  }

  freecon(source_ctx);
}

在handle_control_message中,执行了 svc->Start()之后,会fork出进程,然后调用ExpandArgsAndExecve方法启动BootAnimation进程 

// init.cpp

void handle_control_message(const std::string& msg, const std::string& name) {
    Service* svc = ServiceManager::GetInstance().FindServiceByName(name);
    if (svc == nullptr) {
        LOG(ERROR) << "no such service '" << name << "'";
        return;
    }
    if (msg == "start") {
        //执行这里,将会启动进程
        svc->Start();
    } else if (msg == "stop") {
        svc->Stop();
    } else if (msg == "restart") {
        svc->Restart();
    } else {
       
    }
}

至此,BootAnimation启动完成,总的来说,BootAnimation是还是由init进程fork出来的 

Logo

分享最新的 NVIDIA AI Software 资源以及活动/会议信息,精选收录AI相关技术内容,欢迎大家加入社区并参与讨论。

更多推荐