Android开机动画启动到结束流程(上)

总体流程

在这里插入图片描述

涉及代码路径

bootanimation frameworks/base/cmds/bootanimation/
surfaceflinger frameworks/native/services/surfaceflinger/
init system/core/init/

启动流程详细分析

1.init进程启动

内核起来后会启动第一个进程,即init进程。
init进程会根据init.rc配置启动surfaceflinger进程
surfaceflinger代码路径中有surfaceflinger.rc
在这里插入图片描述

surfaceflinger进程便启动了,跟着就会跑进程的main()函数。

顺便说一句bootanimation里面也有一个bootanim.rc文件,但是里面有个disabled,因此init.rc执行时,不会启动bootanimation进程,什么时候启动请看后文
Android开机动画启动到结束流程(上)_第1张图片

2.SurfaceFlinger进程启动

frameworks/native/services/surfaceflinger/main_surfaceflinger.cpp

int main(int, char**) {
    startHidlServices();

    signal(SIGPIPE, SIG_IGN);
    // When SF is launched in its own process, limit the number of
    // binder threads to 4.
    ProcessState::self()->setThreadPoolMaxThreadCount(4);

    // start the thread pool
    sp<ProcessState> ps(ProcessState::self());
    ps->startThreadPool();

    // instantiate surfaceflinger
    sp<SurfaceFlinger> flinger = new SurfaceFlinger();

    setpriority(PRIO_PROCESS, 0, PRIORITY_URGENT_DISPLAY);

    set_sched_policy(0, SP_FOREGROUND);

    // Put most SurfaceFlinger threads in the system-background cpuset
    // Keeps us from unnecessarily using big cores
    // Do this after the binder thread pool init
    if (cpusets_enabled()) set_cpuset_policy(0, SP_SYSTEM);

    // initialize before clients can connect
    flinger->init();

    // publish surface flinger
    sp<IServiceManager> sm(defaultServiceManager());
    sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false);

    // publish GpuService
    sp<GpuService> gpuservice = new GpuService();
    sm->addService(String16(GpuService::SERVICE_NAME), gpuservice, false);

    struct sched_param param = {0};
    param.sched_priority = 2;
    if (sched_setscheduler(0, SCHED_FIFO, &param) != 0) {
        ALOGE("Couldn't set SCHED_FIFO");
    }

    // run surface flinger in this thread
    flinger->run();

    return 0;
}

这段代码的核心部分,首先new一个SurfaceFlinger实例 sp flinger = new SurfaceFlinger();(这个SurfaceFlinger是#include "SurfaceFlinger.h",正真的实现是在SurfaceFlinger.cpp中),初始化flinger->init();(SurfaceFlinger.cpp中的init方法),然后注册到service manager里sm->addService(String16(GpuService::SERVICE_NAME), gpuservice, false);,最后在这个线程中运行SurfaceFlingerflinger->run();

2.SurfaceFlinger初始化和启动StartPropertySetThread线程

frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

// Do not call property_set on main thread which will be blocked by init
// Use StartPropertySetThread instead.
void SurfaceFlinger::init() {
    ALOGI(  "SurfaceFlinger's main thread ready to run. "
            "Initializing graphics H/W...");

    ALOGI("Phase offest NS: %" PRId64 "", vsyncPhaseOffsetNs);
    
   ......
   
    // Inform native graphics APIs whether the present timestamp is supported:
    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");
}

初始化graphics之后,创建StartPropertySetThread对象,mStartPropertySetThread->Start()启动设置bootanimation的属性线程,下面我们继续看看StartPropertySetThread做了什么

3.StartPropertySetThread线程执行和设置动画属性

frameworks/native/services/surfaceflinger/StartPropertySetThread.cpp

#include 
#include "StartPropertySetThread.h"

namespace android {

StartPropertySetThread::StartPropertySetThread(bool timestampPropertyValue):
        Thread(false), mTimestampPropertyValue(timestampPropertyValue) {}

status_t StartPropertySetThread::Start() {
    return run("SurfaceFlinger::StartPropertySetThread", PRIORITY_NORMAL);
}

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;
}

} // namespace android

之前我们提到过看开机动画的bootanim.rc文件可以看到,其默认是disable的,也就是说,开机动画进程,默认是不会自启动的,需要有其他地方(即StartPropertySetThread)来触发而通过此处的ctl.start属性,能够触发bootanim进程,从而开始显示开机动画
从代码中可以看出StartPropertySetThread主要设置了开机动画相关的关键属性。property_set("service.bootanim.exit", "0")设置service.bootanim.exit 为0,该属性值决定开机动画是否退出,然后通过property_set("ctl.start", "bootanim")启动bootanim service。

4.通知init进程启动bootanim服务

为什么设置一个属性bootanim进程就会启动了呢?
当系统属性发生改变时,init进程就会接收到一个系统属性变化通知,这个通知最终是由在init进程中的函数handle_property_set_fd来处理。下面我们来看看init的main方法

init的main()

system/core/init/init.cpp

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

    property_init();

    ......

    signal_handler_init();

    property_load_boot_defaults();
    export_oem_lock_status();
    start_property_service();
    set_usb_controller();

   ......

    return 0;
}

这个方法中property_init()对属性服务进行初始化,然后start_property_service()启动属性的service。

start_property_service()

system/core/init/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);
}

在init进程中创建了一个CreateSocket用于跨进程通信,并且使用listen(property_set_fd, 8)监听,
register_epoll_handler(property_set_fd, handle_property_set_fd)使用epoll机制来轮询事件,其中一个事件是系统属性值被修改。得到该事件后,会执行handle_property_set_fd()。
简而言之,以我们的开机动画为例,假如有用进程对之前提到的设置动画的属性感兴趣就接受并处理。

handle_property_set_fd()

handle_property_set_fd方法仍在property_service.cpp中

static void handle_property_set_fd() {
    ......

    switch (cmd) {
    case PROP_MSG_SETPROP: {
        char prop_name[PROP_NAME_MAX];
        char prop_value[PROP_VALUE_MAX];

        if (!socket.RecvChars(prop_name, PROP_NAME_MAX, &timeout_ms) ||
            !socket.RecvChars(prop_value, PROP_VALUE_MAX, &timeout_ms)) {
          PLOG(ERROR) << "sys_prop(PROP_MSG_SETPROP): error while reading name/value from the socket";
          return;
        }

        prop_name[PROP_NAME_MAX-1] = 0;
        prop_value[PROP_VALUE_MAX-1] = 0;

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

    case PROP_MSG_SETPROP2: {
        std::string name;
        std::string value;
        if (!socket.RecvString(&name, &timeout_ms) ||
            !socket.RecvString(&value, &timeout_ms)) {
          PLOG(ERROR) << "sys_prop(PROP_MSG_SETPROP2): error while reading name/value from the socket";
          socket.SendUint32(PROP_ERROR_READ_DATA);
          return;
        }

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

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

这些case都执行了handle_property_set方法,继续跟踪该方法。

handle_property_set()

该方法同样在property_service.cpp中

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)) {
      handle_control_message(name.c_str() + 4, value.c_str());
      if (!legacy_protocol) {
        socket.SendUint32(PROP_SUCCESS);
      }
    } else {
      LOG(ERROR) << "sys_prop(" << cmd_name << "): Unable to " << (name.c_str() + 4)
                 << " service ctl [" << value << "]"
                 << " uid:" << cr.uid
                 << " gid:" << cr.gid
                 << " pid:" << cr.pid;
      if (!legacy_protocol) {
        socket.SendUint32(PROP_ERROR_HANDLE_CONTROL_MESSAGE);
      }
    }
  } else {
    ......
  }

  freecon(source_ctx);
}

android::base::StartsWith(name, "ctl.")从这里我们可以看出是在匹配条件,前面动画设置的属性是property_set("ctl.start", "bootanim"),正好匹配。 该函数会进一步执行handle_control_message(name.c_str() + 4, value.c_str()),启动开机动画会传入的参数name.c_str() + 4=start,value.c_str()=bootanim。
继续看这个方法做了什么。

handle_control_message()

/system/core/init/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 {
        LOG(ERROR) << "unknown control msg '" << msg << "'";
    }
}

前面调用handle_control_message(name.c_str() + 4, value.c_str()),传递实参是start,bootanim,即对应这个方法中的形参msg,name
ServiceManager::GetInstance().FindServiceByName(name)找到对应的Service* 对象,从service_list中查询要启动的服务是否有存在,若存在,返回服务的相关信息。因为init.rc中有bootanimation的定义,因此在init进程执行parse_config()时,会将该服务添加到service_list中。这里的name是bootanim如果找到了该服务,就调用start启动服务,首先会执行bootanimation_main.cpp中的main方法。

你可能感兴趣的:(Android,Framework从入门到入土,Android,android)