青岛网站开发招聘,爱站长工具,现在可以去贵阳吗,电子商务网站建设与维护试题首语
在Android设备开机启动时#xff0c;会展示Android开机动画#xff0c;用于增加用户体验和展示设备品牌等信息。它也是Android系统启动的一部分。开机动画是由bootanimation负责的#xff0c;因此首先先了解下bootanimation是如何启动的。
bootanimation 启动脚本分析…首语
在Android设备开机启动时会展示Android开机动画用于增加用户体验和展示设备品牌等信息。它也是Android系统启动的一部分。开机动画是由bootanimation负责的因此首先先了解下bootanimation是如何启动的。
bootanimation 启动脚本分析
init进程中第二阶段(SecondStageMain)的主要工作有初始化属性服务加载启动脚本解析init.rc文件等。
源码路径system/core/init/init.cpp
int SecondStageMain(int argc, char** argv) {...LoadBootScripts(am, sm);...
}
static void LoadBootScripts(ActionManager action_manager, ServiceList service_list) {Parser parser CreateParser(action_manager, service_list);std::string bootscript GetProperty(ro.boot.init_rc, );if (bootscript.empty()) {parser.ParseConfig(/system/etc/init/hw/init.rc);if (!parser.ParseConfig(/system/etc/init)) {late_import_paths.emplace_back(/system/etc/init);}// late_import is available only in Q and earlier release. As we dont// have system_ext in those versions, skip late_import for system_ext.parser.ParseConfig(/system_ext/etc/init);if (!parser.ParseConfig(/vendor/etc/init)) {late_import_paths.emplace_back(/vendor/etc/init);}if (!parser.ParseConfig(/odm/etc/init)) {late_import_paths.emplace_back(/odm/etc/init);}if (!parser.ParseConfig(/product/etc/init)) {late_import_paths.emplace_back(/product/etc/init);}} else {parser.ParseConfig(bootscript);}
}在init.rc文件中可以看到通过class_start来启动 classname 为 core 的 Service。在bootanimation.rc文件中可以清楚看到Service name为bootanim执行程序路径为/system/bin/bootanimation类名core。disabled表示系统启动时不会自动启动bootanimation。那是谁启动bootanimation呢
SurfaceFlinger它负责管理图形内容的渲染并将多个图层包括应用程序窗口、系统UI元素和硬件覆盖层合成到设备的屏幕上。所以首先需要启动SurfaceFlinger开机动画的渲染和合成是它完成的继续分析SurfaceFlinger启动流程。
源码路径system/core/rootdir/init.rc
...# Start standard binderized HAL daemonsclass_start halclass_start core
...源码路径frameworks/base/cmds/bootanimation/bootanim.rc
service bootanim /system/bin/bootanimationclass core animationuser graphicsgroup graphics audiodisabledoneshotioprio rt 0task_profiles MaxPerformance
SurfaceFlinger启动流程
而surfaceflinger.rc文件中可以清楚看到Service name为surfaceflinger执行程序路径为/system/bin/surfaceflinger类名core。
因此可以知道SurfaceFlinger是在init进程启动第二阶段进行启动的。
源码路径frameworks/native/services/surfaceflinger/surfaceflinger.rc
service surfaceflinger /system/bin/surfaceflingerclass core animationuser systemgroup graphics drmrpc readproccapabilities SYS_NICEonrestart restart --only-if-running zygotetask_profiles HighPerformancesocket pdx/system/vr/display/client stream 0666 system graphics u:object_r:pdx_display_client_endpoint_socket:s0socket pdx/system/vr/display/manager stream 0666 system graphics u:object_r:pdx_display_manager_endpoint_socket:s0socket pdx/system/vr/display/vsync stream 0666 system graphics u:object_r:pdx_display_vsync_endpoint_socket:s0看下SurfaceFlinger的main函数创建了SurfaceFlinger并且初始化调用StartPropertySetThread的Start函数。
源码路径frameworks/native/services/surfaceflinger/main_surfaceflinger.cpp
int main(int, char**) {...// instantiate surfaceflingerspSurfaceFlinger flinger surfaceflinger::createSurfaceFlinger();...// initialize before clients can connectflinger-init();...
}源码路径frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
void SurfaceFlinger::init() {...mStartPropertySetThread getFactory().createStartPropertySetThread(presentFenceReliable);if (mStartPropertySetThread-Start() ! NO_ERROR) {ALOGE(Run StartPropertySetThread failed!);}...
}可以看到将系统属性service.bootanim.exit/service.bootanim.progress设置为0并将ctl.start设置为bootanim当系统属性发生改变时init进程就会接收到一个系统属性变化通知这个通知最终是由在init进程中的函数handle_property_set_fd来处理的。设置ctl.start表示启动一个服务这样bootanimation就被启动了。
源码路径frameworks/native/services/surfaceflinger/StartPropertySetThread.cpp
status_t StartPropertySetThread::Start() {return run(SurfaceFlinger::StartPropertySetThread, PRIORITY_NORMAL);
}bool StartPropertySetThread::threadLoop() {// Set property service.sf.present_timestamp, consumer need check its readinessproperty_set(kTimestampProperty, mTimestampPropertyValue ? 1 : 0);// Clear BootAnimation exit flagproperty_set(service.bootanim.exit, 0);property_set(service.bootanim.progress, 0);// Start BootAnimation if not startedproperty_set(ctl.start, bootanim);// Exit immediatelyreturn false;
}bootanimation启动流程
分析bootanimation的main函数首先判断是否禁用了启动动画没有则创建一个binder线程池再创建BootAnimation等待SurfaceFlinger启动完成。
源码路径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) {//创建binder线程池spProcessState proc(ProcessState::self());ProcessState::self()-startThreadPool();// create the boot animation object (may take up to 200ms for 2MB zip)spBootAnimation boot new BootAnimation(audioplay::createAnimationCallbacks());waitForSurfaceFlinger();boot-run(BootAnimation, PRIORITY_DISPLAY);ALOGV(Boot animation set up. Joining pool.);IPCThreadState::self()-joinThreadPool();}return 0;
}源码路径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);if (atoi(value) 0) {// Only show the bootanimation for quiescent boots if this system property is set to enabled//禁用启动动画if (!property_get_bool(ro.bootanim.quiescent.enabled, false)) {return true;}}return false;
}void waitForSurfaceFlinger() {// TODO: replace this with better waiting logic in future, b/35253872int64_t waitStartTime elapsedRealtime();spIServiceManager sm defaultServiceManager();const String16 name(SurfaceFlinger);const int SERVICE_WAIT_SLEEP_MS 100;const int LOG_PER_RETRIES 10;int retry 0;while (sm-checkService(name) nullptr) {retry;if ((retry % LOG_PER_RETRIES) 0) {ALOGW(Waiting for SurfaceFlinger, waited for % PRId64 ms,elapsedRealtime() - waitStartTime);}usleep(SERVICE_WAIT_SLEEP_MS * 1000);};int64_t totalWaited elapsedRealtime() - waitStartTime;if (totalWaited SERVICE_WAIT_SLEEP_MS) {ALOGI(Waiting for SurfaceFlinger took % PRId64 ms, totalWaited);}
}BootAnimation类有几个重要函数
onFirstRef()属于父类RefBase它用于实现引用计数的对象管理新增引用计数时调用。binderDied() Binder结束时就会回调binderDied()方法。readyToRun() Thread执行前的初始化工作。threadLoop() 线程根据逻辑是否循环执行。android()显示系统默认的开机画面。movie()显示用户自定义的开机动画。loadAnimation()加载动画。playAnimation()播放动画。checkExit()检查是否退出动画。
源码路径frameworks/base/cmds/bootanimation/BootAnimation.h
private:virtual bool threadLoop();virtual status_t readyToRun();virtual void onFirstRef();virtual void binderDied(const wpIBinder who);...//系统默认的开机画面bool android();//用户自定义的开机动画bool movie();...//加载动画Animation* loadAnimation(const String8);//播放动画bool playAnimation(const Animation);void releaseAnimation(Animation*) const;bool parseAnimationDesc(Animation);bool preloadZip(Animation animation);void findBootAnimationFile();bool findBootAnimationFileInternal(const std::vectorstd::string files);bool preloadAnimation();EGLConfig getEglConfig(const EGLDisplay);ui::Size limitSurfaceSize(int width, int height) const;void resizeSurface(int newWidth, int newHeight);void projectSceneToWindow();bool shouldStopPlayingPart(const Animation::Part part, int fadedFramesCount,int lastDisplayedProgress);//检查是否退出动画void checkExit();BootAnimation构造函数中创建了SurfaceComposerClientmSession用来和SurfaceFlinger执行Binder进程间通信执行linkToComposerDeath方法用于获取SurfaceFlinger死亡通知,preloadAnimation方法开始加载动画首先去查询动画文件动画文件的存放位置如代码中定义所示。动画文件是按照指定位置顺序读取如果读取到当前位置动画文件则不读取后续动画文件。
源码路径frameworks/base/cmds/bootanimation/BootAnimation.cpp
static const char OEM_BOOTANIMATION_FILE[] /oem/media/bootanimation.zip;
static const char PRODUCT_BOOTANIMATION_DARK_FILE[] /product/media/bootanimation-dark.zip;
static const char PRODUCT_BOOTANIMATION_FILE[] /product/media/bootanimation.zip;
static const char SYSTEM_BOOTANIMATION_FILE[] /system/media/bootanimation.zip;
static const char APEX_BOOTANIMATION_FILE[] /apex/com.android.bootanimation/etc/bootanimation.zip;
static const char PRODUCT_ENCRYPTED_BOOTANIMATION_FILE[] /product/media/bootanimation-encrypted.zip;
static const char SYSTEM_ENCRYPTED_BOOTANIMATION_FILE[] /system/media/bootanimation-encrypted.zip;
static const char OEM_SHUTDOWNANIMATION_FILE[] /oem/media/shutdownanimation.zip;
static const char PRODUCT_SHUTDOWNANIMATION_FILE[] /product/media/shutdownanimation.zip;
static const char SYSTEM_SHUTDOWNANIMATION_FILE[] /system/media/shutdownanimation.zip;static constexpr const char* PRODUCT_USERSPACE_REBOOT_ANIMATION_FILE /product/media/userspace-reboot.zip;
static constexpr const char* OEM_USERSPACE_REBOOT_ANIMATION_FILE /oem/media/userspace-reboot.zip;
static constexpr const char* SYSTEM_USERSPACE_REBOOT_ANIMATION_FILE /system/media/userspace-reboot.zip;BootAnimation::BootAnimation(spCallbacks callbacks): Thread(false), mLooper(new Looper(false)), mClockEnabled(true), mTimeIsAccurate(false),mTimeFormat12Hour(false), mTimeCheckThread(nullptr), mCallbacks(callbacks) {mSession new SurfaceComposerClient();std::string powerCtl android::base::GetProperty(sys.powerctl, );if (powerCtl.empty()) {mShuttingDown false;} else {mShuttingDown true;}ALOGD(%sAnimationStartTiming start time: % PRId64 ms, mShuttingDown ? Shutdown : Boot,elapsedRealtime());
}
void BootAnimation::onFirstRef() {//接收SurfaceFlinger死亡通知status_t err mSession-linkToComposerDeath(this);SLOGE_IF(err, linkToComposerDeath failed (%s) , strerror(-err));if (err NO_ERROR) {// Load the animation content -- this can be slow (eg 200ms)// called before waitForSurfaceFlinger() in main() to avoid waitALOGD(%sAnimationPreloadTiming start time: % PRId64 ms,mShuttingDown ? Shutdown : Boot, elapsedRealtime());preloadAnimation();ALOGD(%sAnimationPreloadStopTiming start time: % PRId64 ms,mShuttingDown ? Shutdown : Boot, elapsedRealtime());}
}
bool BootAnimation::preloadAnimation() {findBootAnimationFile();if (!mZipFileName.isEmpty()) {//加载动画mAnimation loadAnimation(mZipFileName);return (mAnimation ! nullptr);}return false;
}
void BootAnimation::findBootAnimationFile() {// If the device has encryption turned on or is in process// of being encrypted we show the encrypted boot animation.char decrypt[PROPERTY_VALUE_MAX];property_get(vold.decrypt, decrypt, );bool encryptedAnimation atoi(decrypt) ! 0 ||!strcmp(trigger_restart_min_framework, decrypt);if (!mShuttingDown encryptedAnimation) {static const std::vectorstd::string encryptedBootFiles {PRODUCT_ENCRYPTED_BOOTANIMATION_FILE, SYSTEM_ENCRYPTED_BOOTANIMATION_FILE,};if (findBootAnimationFileInternal(encryptedBootFiles)) {return;}}const bool playDarkAnim android::base::GetIntProperty(ro.boot.theme, 0) 1;static const std::vectorstd::string bootFiles {APEX_BOOTANIMATION_FILE, playDarkAnim ? PRODUCT_BOOTANIMATION_DARK_FILE : PRODUCT_BOOTANIMATION_FILE,OEM_BOOTANIMATION_FILE, SYSTEM_BOOTANIMATION_FILE};static const std::vectorstd::string shutdownFiles {PRODUCT_SHUTDOWNANIMATION_FILE, OEM_SHUTDOWNANIMATION_FILE, SYSTEM_SHUTDOWNANIMATION_FILE, };static const std::vectorstd::string userspaceRebootFiles {PRODUCT_USERSPACE_REBOOT_ANIMATION_FILE, OEM_USERSPACE_REBOOT_ANIMATION_FILE,SYSTEM_USERSPACE_REBOOT_ANIMATION_FILE,};if (android::base::GetBoolProperty(sys.init.userspace_reboot.in_progress, false)) {findBootAnimationFileInternal(userspaceRebootFiles);} else if (mShuttingDown) {findBootAnimationFileInternal(shutdownFiles);} else {findBootAnimationFileInternal(bootFiles);}
}
bool BootAnimation::findBootAnimationFileInternal(const std::vectorstd::string files) {for (const std::string f : files) {if (access(f.c_str(), R_OK) 0) {mZipFileName f.c_str();return true;}}return false;
}
BootAnimation::Animation* BootAnimation::loadAnimation(const String8 fn) {if (mLoadedFiles.indexOf(fn) 0) {SLOGE(File \%s\ is already loaded. Cyclic ref is not allowed,fn.string());return nullptr;}ZipFileRO *zip ZipFileRO::open(fn);if (zip nullptr) {SLOGE(Failed to open animation zip \%s\: %s,fn.string(), strerror(errno));return nullptr;}ALOGD(%s is loaded successfully, fn.string());Animation *animation new Animation;animation-fileName fn;animation-zip zip;animation-clockFont.map nullptr;mLoadedFiles.add(animation-fileName);//解析动画文件parseAnimationDesc(*animation);if (!preloadZip(*animation)) {releaseAnimation(animation);return nullptr;}mLoadedFiles.remove(fn);return animation;
}
bool BootAnimation::parseAnimationDesc(Animation animation) {String8 desString;if (!readFile(animation.zip, desc.txt, desString)) {return false;}char const* s desString.string();std::string dynamicColoringPartName ;bool postDynamicColoring false;// Parse the description file...
}bootanimation.zip
动画文件的压缩包里都存在一个动画配置文件desc.txt它是描述开机动画是如何显示的。我们以device/google/atv/products/bootanimations/bootanimation.zip动画压缩包为例进行分析它是AndroidTV存储动画文件的路径。desc.txt内容如下
第1行用来描述开机动画在屏幕显示的大小及帧率。这个定义指示 bootanimation 的播放分辨率为 512x416 像素帧率为 60 帧/秒。分辨率定义了动画的宽度和高度而帧率定义了动画播放的流畅程度即每秒播放的帧数。
第2行c表示清除命令。1表示清除的起始帧。0表示清除的结束帧。part0表示需要清除的动画帧所在的文件夹路径。这个定义指示在播放动画时从指定的文件夹 part0 中清除第 1 帧。这样可以控制在播放过程中是否清除特定的帧以实现动画效果的变化或平滑的过渡效果。3-5行同理。
最后一行f表示循环命令。0表示循环的起始帧。0表示循环的结束帧。part4表示需要循环的动画帧所在的文件夹路径。10表示循环次数。该行指示在播放动画时从指定的文件夹中的起始帧到结束帧之间的帧进行循环播放重复播放 10 次。
512 416 60
c 1 0 part0
c 1 15 part1
c 1 0 part2
c 1 0 part3
f 0 0 part4 10动画配置文件还有指定播放顺序的例如如下的配置p表示播放顺序命令。1表示播放的顺序。0表示播放的循环次数。0 表示无限循环。folder1表示动画帧所在的文件夹路径。根据这个定义folder1 是一个目录包含了一组 bootanimation 动画帧文件。该行指示在播放动画时按照顺序从 folder1 目录中加载帧并进行播放。
p 1 0 folder1 加载动画执行完成后接下来会执行主体函数threadLoop首先判断自定义开机动画文件是否存在如果不存在则执行Android方法否则执行自定义动画Movie方法。Android和Movie方法最后都返回false。因此threadloop也返回false代表代码只执行一次。最后获取service.bootanim.exit属性如果值为1循环就会退出开机动画就会结束。service.bootanim.exit属性是在AMS中被修改为1的在后面AMS中会讲到。
static const char EXIT_PROP_NAME[] service.bootanim.exit;
bool BootAnimation::threadLoop() {bool result;initShaders();// We have no bootanimation file, so we use the stock android logo// animation.if (mZipFileName.isEmpty()) {ALOGD(No animation file);//系统默认开机画面result android();} else {//自定义开机动画显示result movie();}mCallbacks-shutdown();eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);eglDestroyContext(mDisplay, mContext);eglDestroySurface(mDisplay, mSurface);mFlingerSurface.clear();mFlingerSurfaceControl.clear();eglTerminate(mDisplay);eglReleaseThread();IPCThreadState::self()-stopProcess();return result;
}bool BootAnimation::android() {glActiveTexture(GL_TEXTURE0);SLOGD(%sAnimationShownTiming start time: % PRId64 ms, mShuttingDown ? Shutdown : Boot,elapsedRealtime());//android-logo-mask.png和android-logo-shine.png保存在frameworks/base/core/res/assets/images/路径下initTexture(mAndroid[0], mAssets, images/android-logo-mask.png);initTexture(mAndroid[1], mAssets, images/android-logo-shine.png);mCallbacks-init({});...return false;
}
bool BootAnimation::movie() {if (mAnimation nullptr) {mAnimation loadAnimation(mZipFileName);}if (mAnimation nullptr)return false;...playAnimation(*mAnimation);releaseAnimation(mAnimation);mAnimation nullptr;return false;
}
bool BootAnimation::playAnimation(const Animation animation) {...checkExit();
}
void BootAnimation::checkExit() {// Allow surface flinger to gracefully request shutdownchar value[PROPERTY_VALUE_MAX];property_get(EXIT_PROP_NAME, value, 0);int exitnow atoi(value);if (exitnow) {requestExit();}
}总结
init进程是Android系统中的第一个用户空间进程。它负责启动各个系统服务和应用程序。在init进程启动过程中SurfaceFlinger也被启动SurfaceFlinger是Android中的显示系统服务负责管理屏幕显示和图形渲染。开机动画需要使用SurfaceFlinger来显示。然后bootanimation也启动进行开机动画的播放。bootanimation.zip中包含动画文件和动画配置文件。最终当所有系统服务和应用程序启动完毕开机动画结束进入系统主界面。