切换语言为:繁体
Android开机动画源码详细分析

Android开机动画源码详细分析

  • 爱糖宝
  • 2024-11-22
  • 2009
  • 0
  • 0
介绍:Android开机动画是相对简单的逻辑,其中主要代码也不到两百行,但开机动画进程的启动用到了其他进程启动类似的逻辑。这里分析清楚了之后,后面其他进程启动就更加容易理解

1. surfaceflinger启动

为什么要先从surfaceflinger开始呢?

因为surfaceflinger是设备显示模块,而开机动画必定跟显示有关,所以先从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

surfacegflinger启动之后,必定要看surfaceflinger的main方法;在源码的这个路径下 frameworks\native\services\surfaceflinger\main_surfaceflinger.cpp

//删除了跟开机启动无关的代码,这里主要就是设置线程池,给surfaceflinger添加到ServiceManager;
//以及开始执行surfaceflinger相关代码 flinger->init();和flinger->run();
int main(int, char**) {

    ProcessState::self()->setThreadPoolMaxThreadCount(4);

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

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


    sp<IServiceManager> sm(defaultServiceManager());
    sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false,
                   IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);

    sm->addService(String16("SurfaceFlingerAIDL"), composerAIDL, false,
                   IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);

    flinger->run();

    return 0;
}

这里就是执行到frameworks\native\services\surfaceflinger\SurfaceFlinger.cpp

先看init方法


//这里和开机有关的是StartPropertySetThread,相当于一个线程,这里开启的一个线程,并调用start方法
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!");
    }

}

// \frameworks\native\services\surfaceflinger\StartPropertySetThread.cpp
//其头文件中,继承自Thread 也就是:class StartPropertySetThread : public Thread
//这里mStartPropertySetThread->Start()直接调用了线程的run方法,
// 这里开始后就会执行threadLoop方法,这个我们先记住,后面有空再分析下native的Thread类
status_t StartPropertySetThread::Start() {
    return run("SurfaceFlinger::StartPropertySetThread", PRIORITY_NORMAL);
}

bool StartPropertySetThread::threadLoop() {
    //这里设置了两个属性
    property_set(kTimestampProperty, mTimestampPropertyValue ? "1" : "0");
    property_set("service.bootanim.exit", "0");
    //设置了这个属性后,意味着开机动画就可以启动了
    property_set("ctl.start", "bootanim");
    
    return false;
}

为什么设置了service.bootanim.exit和ctl.start这两个属性后,开机动画就启动了呢?

这里先记录下,我们接着看

2. init进程

我们都知道,init进程是Android启动的第一个进程,比zygote还要早。 我们看下init进程里和开机动画相关的逻辑

// \system\core\init\init.cpp
int main(int argc, char** argv) {
    //其他的逻辑先不看,我们先看下与开机启动动画相关的逻辑
    start_property_service();
    return 0;
}


// \system\core\init\property_service.cpp
//这里相当于创建了一个socket(用于跨进程通讯)
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);
    }
    //这里接收了其他进程的socket发来了消息,然后执行handle_property_set_fd这个方法
    listen(property_set_fd, 8);
    register_epoll_handler(property_set_fd, handle_property_set_fd);
}



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

    }
}


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


// \system\core\init\init.cpp
void handle_control_message(const std::string& msg, const std::string& name) {
    //这里就是开机动画相关的进程启动,就进入bootanimation进程
    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 << "'";
    }
}

3. bootanimation进程

// \frameworks\base\cmds\bootanimation\bootanimation_main.cpp
这里进入bootanimation进程后,就开始执行开机动画
int main()
{
    setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);

    bool noBootAnimation = bootAnimationDisabled();
    ALOGI_IF(noBootAnimation,  "boot animation disabled");
    if (!noBootAnimation) {

        sp<ProcessState> proc(ProcessState::self());
        ProcessState::self()->startThreadPool();

        waitForSurfaceFlinger();

        // create the boot animation object
        sp<BootAnimation> boot = new BootAnimation(new AudioAnimationCallbacks());
        ALOGV("Boot animation set up. Joining pool.");

        IPCThreadState::self()->joinThreadPool();
    }
    ALOGV("Boot animation exit");
    return 0;
}

到这里有点乱了,稍微整理一下

  1. 首先应该是init进程启动,

  2. 接着应该是surfaceflinger进程启动,

  3. init进程启动的时候为什么不直接启动bootanimation进程呢,因为开机动画需要surfaceflinger进程,所以要等surfaceflinger进程启动完成之后,才能启动bootanimation进程,并执行开机动画

  4. 所以init进程就有了一个socket,用于监听surfaceflinger进程传递过来的消息

  5. 也就是说surfaceflinger进程启动结束后,会发送给init进程一个消息,让init进程去启动开机动画

画一个图解释一下

Android开机动画源码详细分析

0条评论

您的电子邮件等信息不会被公开,以下所有项均必填

OK! You can skip this field.