android8.1开机动画启动分析

Posted we1less

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android8.1开机动画启动分析相关的知识,希望对你有一定的参考价值。

init.cpp    AOSP/system/core/init/init.cpp

  SurfaceFlinger是由init进程启动的

int main(int argc, char** argv) {
    ...
    if (bootmode == "charger") {
        am.QueueEventTrigger("charger");
    } else {
        am.QueueEventTrigger("late-init");
    }
    ...
}

  触发trigger  这里可以暂时参考一下https://blog.csdn.net/we1less/article/details/116110137?spm=1001.2014.3001.5501


 

init.rc    AOSP/system/core/rootdir/init.rc 

on late-init
    ...
    trigger boot
    ...
on boot
    ...
    class_start core
    ...

 关于启动相应的函数这里可以参考一下https://blog.csdn.net/we1less/article/details/116139142?spm=1001.2014.3001.5501


builtin_functions    AOSP/system/core/init/builtins.cpp

  可以看出class_start 命令有一个对应的执行函数 do_class_start

onst BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
    constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
    // clang-format off
    static const Map builtin_functions = {
        {"bootchart",               {1,     1,    do_bootchart}},
        {"chmod",                   {2,     2,    do_chmod}},
        {"chown",                   {2,     3,    do_chown}},
        {"class_reset",             {1,     1,    do_class_reset}},
        {"class_restart",           {1,     1,    do_class_restart}},
        {"class_start",             {1,     1,    do_class_start}},
}
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;
}
    
@services.cpp
bool Service::StartIfNotDisabled() {   //定义为disabled不会被启动
    if (!(flags_ & SVC_DISABLED)) {
        return Start();
    } else {
        flags_ |= SVC_DISABLED_START;
    }
    return true;
}

surfaceflinger.rc    AOSP/frameworks/native/services/surfaceflinger/surfaceflinger.rc

service surfaceflinger /system/bin/surfaceflinger
    class core animation
    user system
    group graphics drmrpc readproc
    onrestart restart zygote
    writepid /dev/stune/foreground/tasks
    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

  通过mk文件  LOCAL_MODULE := surfaceflinger   可以寻找到相关的cpp文件


main_surfaceflinger.cpp    AOSP/frameworks/native/services/surfaceflinger/main_surfaceflinger.cpp

int main(int, char**) {
    ...
    // instantiate surfaceflinger
    sp<SurfaceFlinger> flinger = new SurfaceFlinger();
    ...
    // initialize before clients can connect
    flinger->init();
    ...
    // run surface flinger in this thread
    flinger->run();

    return 0;
}

flinger->init()    

void SurfaceFlinger::init() {
    ALOGI(  "SurfaceFlinger's main thread ready to run. "
            "Initializing graphics H/W...");


    // 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) { //真正启动设置bootanimation的属性线程
        ALOGE("Run StartPropertySetThread failed!");
    }

    ALOGV("Done initializing");
}

mStartPropertySetThread->Start()     AOSP/frameworks/native/services/surfaceflinger/StartPropertySetThread.cpp

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

  这样bootanim进程就会启动


为什么设置属性就会启动bootanim服务

init.cpp    AOSP/system/core/init/init.cpp

  关于属性服务参考这篇https://blog.csdn.net/we1less/article/details/116035087?spm=1001.2014.3001.5501

int main(int argc, char** argv) {
    ...
    start_property_service(); //start_property_service
    ...
}

start_property_service     AOSP/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);
}

  在这个函数中注册一个epoll handle 的机制 register_epoll_handler()  简单的来说就是通过监听socket轮询  如果有属性设置上来了  就调用handle_property_set_fd

handle_property_set_fd 

static void handle_property_set_fd() {
    ...

    switch (cmd) {
    case PROP_MSG_SETPROP: {
        ....
          return;
        }
        ...

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

  该函数会进执行handle_property_set()

handle_property_set

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

这里可以看到在判断是否以  ctl.  开头接着调用handle_control_message

当然如果在查看源码的过程中发现无法判断调用链的可以使用相关命令  grep "xxxxx"  ./ -rn  参考https://blog.csdn.net/we1less/article/details/115792043?spm=1001.2014.3001.5501

godv@godv-OptiPlex-7070:~/godv/AOSP/android-8.1.0_r1/system/core/init$ grep "handle_control_message" ./ -rn
./init.cpp:209:void handle_control_message(const std::string& msg, const std::string& name) {
./init.h:35:void handle_control_message(const std::string& msg, const std::string& arg);
./property_service.cpp:427:      handle_control_message(name.c_str() + 4, value.c_str());

这样就能查询到相关方法出现的位置  这里我们可以定位到这是init.cpp中的方法


handle_control_message    AOSP/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 << "'";
    }
}

查询相关service  调用start


bootanim.rc    frameworks/base/cmds/bootanimation/bootanim.rc 

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

根据mk文件找到启动文件  bootanimation_main.cpp


main()     AOSP/frameworks/base/cmds/bootanimation/bootanimation_main.cpp

int main()
{
    setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);

    bool noBootAnimation = bootAnimationDisabled();
    ALOGI_IF(noBootAnimation,  "boot animation disabled");
    if (!noBootAnimation) {
        ...
        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;
}

  进入main函数首先判断开机动画是否被禁用bootAnimationDisabled()

  如果实在无法找到函数调用出可以使用    grep "xxx" ./ -rn

godv@godv-OptiPlex-7070:~/godv/AOSP/android-8.1.0_r1/frameworks/base$ grep "bootAnimationDisabled" ./ -rn
./cmds/bootanimation/iot/iotbootanimation_main.cpp:79:    if (bootAnimationDisabled()) {
./cmds/bootanimation/BootAnimationUtil.h:20:bool bootAnimationDisabled();
./cmds/bootanimation/BootAnimationUtil.cpp:28:bool bootAnimationDisabled() {
./cmds/bootanimation/bootanimation_main.cpp:149:    bool noBootAnimation = bootAnimationDisabled();

  在这里我们可以分析bootAnimationDisabled被定义在BootAnimationUtil.cpp里面

bootAnimationDisabled()  AOSP/frameworks/base/cmds/bootanimation/BootAnimationUtil.cpp

bool bootAnimationDisabled() {
    char value[PROPERTY_VALUE_MAX];
    property_get("debug.sf.nobootanimation", value, "0");
    if (atoi(value) > 0) {
        return true;
    }

    property_get("ro.boot.quiescent", value, "0");
    return atoi(value) > 0;
}

  由此可以看出默认状态下返回的是false  继续分析sp<BootAnimation> boot = new BootAnimation(new AudioAnimationCallbacks());


 1 首先看构造器

BootAnimation(sp<Callbacks> callbacks)  AOSP/frameworks/base/cmds/bootanimation/BootAnimation.cpp

BootAnimation::BootAnimation(sp<Callbacks> callbacks)
        : Thread(false), mClockEnabled(true), mTimeIsAccurate(false),
        mTimeFormat12Hour(false), mTimeCheckThread(NULL), mCallbacks(callbacks) {
    mSession = new SurfaceComposerClient();

    std::string powerCtl = android::base::GetProperty("sys.powerctl", "");
    if (powerCtl.empty()) {
        mShuttingDown = false;
    } else {
        mShuttingDown = true;
    }
}

  2 sp指针在对象第一次初始化的过程中调用onFirstRef()

onFirstRef()

void BootAnimation::onFirstRef() {
    status_t err = mSession->linkToComposerDeath(this);
    ALOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err));
    if (err == NO_ERROR) {
        run("BootAnimation", PRIORITY_DISPLAY);·
    }
}

    在这可以看到调用了run方法  在查看文件  BootAnimation.h  头文件  BootAnimation  继承自  Thread  这样就可以理解这个run方法了

class BootAnimation : public Thread, public IBinder::DeathRecipient
{ 
  ...
}

既然是线程类肯定就要有 readyToRun()

这个方法里面主要创建了surface  和初始化openglegl

status_t BootAnimation::readyToRun() {
    ...
    static const char* bootFiles[] = {OEM_BOOTANIMATION_FILE, SYSTEM_BOOTANIMATION_FILE};
    static const char* shutdownFiles[] =
        {OEM_SHUTDOWNANIMATION_FILE, SYSTEM_SHUTDOWNANIMATION_FILE};

    for (const char* f : (!mShuttingDown ? bootFiles : shutdownFiles)) {
        if (access(f, R_OK) == 0) {
            mZipFileName = f;
            return NO_ERROR;
        }
    }
    return NO_ERROR;
}

bootFiles开机  shutdownFiles关机  重要看bootFiles[]中的两个字符串  这两个字符串就代表了zip放置的路径

static const char OEM_BOOTANIMATION_FILE[] = "/oem/media/bootanimation.zip";
static const char SYSTEM_BOOTANIMATION_FILE[] = "/system/media/bootanimation.zip";

接下来看  threadLoop()

bool BootAnimation::threadLoop()
{
    bool r;
    // We have no bootanimation file, so we use the stock android logo
    // animation.
    if (mZipFileName.isEmpty()) {
        r = android();
    } else {
        r = movie();
    }
    ...
    return r;
}

android()  没有文件使用opengl绘制  movie则代表opengl渲染zip文件  此时开机动画就被播放出来了

以上是关于android8.1开机动画启动分析的主要内容,如果未能解决你的问题,请参考以下文章

android8.1开机动画zip包分析

[Android5.1]开机动画显示工作流程分析

Android Framework学习视频-BootAnimation开机动画启动流程源码分析

Android Framework学习教程-BootAnimation开机动画启动流程源码分析

android8.1启动过程 zygote进程分析2

在ViewPager上,在onPageSelected上的片段上启动动画