当前位置: 首页 > news >正文

Android Framework开机动画开发

1.开机动画总体介绍

1.开机动画启动流程

代码路径

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

启动流程详细分析:
内核起来后会启动第一个进程,即init进程。

init进程会根据init.rc配置启动surfaceflinger进程。

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()函数。
frameworks/native/services/surfaceflinger/main_surfaceflinger.cpp

int main(int, char**) {
...
...// instantiate surfaceflinger  创建surfaceflinger实例sp<SurfaceFlinger> flinger = surfaceflinger::createSurfaceFlinger();...
...// initialize before clients can connectflinger->init();// publish surface flinger  注册服务sp<IServiceManager> sm(defaultServiceManager());sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false,IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);// publish gui::ISurfaceComposer, the new AIDL interfacesp<SurfaceComposerAIDL> composerAIDL = new SurfaceComposerAIDL(flinger);sm->addService(String16("SurfaceFlingerAIDL"), composerAIDL, false,IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);startDisplayService(); // dependency on SF getting registered aboveif (SurfaceFlinger::setSchedFifo(true) != NO_ERROR) {ALOGW("Couldn't set to SCHED_FIFO: %s", strerror(errno));}// run surface flinger in this thread  开始运行flinger->run();return 0;
}

这段代码主要是为了获取一个SurfaceFlinger实例,然后init,然后run

frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

    // Inform native graphics APIs whether the present timestamp is supported:const bool presentFenceReliable =!getHwComposer().hasCapability(Capability::PRESENT_FENCE_IS_NOT_RELIABLE);mStartPropertySetThread = getFactory().createStartPropertySetThread(presentFenceReliable);if (mStartPropertySetThread->Start() != NO_ERROR) {ALOGE("Run StartPropertySetThread failed!");}

init函数中有段代码是和StartPropertySetThread有关,这里面主要做的是初始化某些属性值,可以看到注释里面写的,ctl.start这个属性值是为了start BootAnimation的。

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 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;
}} // namespace android

这里bootanim的启动流程为什么可以被prop控制,下面继续分析

/system/core/init/init.cpp 

system/core/init/property_service.cpp

在init进程启动的SecondStageMain过程中,会去调用 StartPropertyService

void StartPropertyService(int* epoll_socket) {InitPropertySet("ro.property_service.version", "2");int sockets[2];if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sockets) != 0) {PLOG(FATAL) << "Failed to socketpair() between property_service and init";}*epoll_socket = from_init_socket = sockets[0];init_socket = sockets[1];StartSendingMessages();if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,false, 0666, 0, 0, {});result.ok()) {property_set_fd = *result;} else {LOG(FATAL) << "start_property_service socket creation failed: " << result.error();}listen(property_set_fd, 8);auto new_thread = std::thread{PropertyServiceThread};property_service_thread.swap(new_thread);
}static void PropertyServiceThread() {Epoll epoll;if (auto result = epoll.Open(); !result.ok()) {LOG(FATAL) << result.error();}if (auto result = epoll.RegisterHandler(property_set_fd, handle_property_set_fd);!result.ok()) {LOG(FATAL) << result.error();}if (auto result = epoll.RegisterHandler(init_socket, HandleInitSocket); !result.ok()) {LOG(FATAL) << result.error();}while (true) {auto pending_functions = epoll.Wait(std::nullopt);if (!pending_functions.ok()) {LOG(ERROR) << pending_functions.error();} else {for (const auto& function : *pending_functions) {(*function)();}}}
}

在StartPropertyService中会中国epoll来监听事件和fd的变化,其中handle_property_set_fd这里专门监听prop的变化。

如果有fd的变化, 该函数会进一步执行handle_control_message(),在/system/core/init/init.cpp,传入的参数msg.name=ctl.start,msg.value=bootanim,最后通过匹配ctl.来匹配prop,然后获取服务,ServiceList::GetInstance().FindInterface(name);

调用服务中特定函数来启动服务。到这里,bootanim启动服务就被正式启动,在这之前是空有进程,但无服务。

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;std::string source_context;if (!socket.GetSourceContext(&source_context)) {PLOG(ERROR) << "Unable to set property '" << prop_name << "': getpeercon() failed";return;}const auto& cr = socket.cred();std::string error;uint32_t result =HandlePropertySet(prop_name, prop_value, source_context, cr, nullptr, &error);if (result != PROP_SUCCESS) {LOG(ERROR) << "Unable to set property '" << prop_name << "' from uid:" << cr.uid<< " gid:" << cr.gid << " pid:" << cr.pid << ": " << error;}break;}......
}static bool HandleControlMessage(std::string_view message, const std::string& name,pid_t from_pid) {std::string cmdline_path = StringPrintf("proc/%d/cmdline", from_pid);std::string process_cmdline;if (ReadFileToString(cmdline_path, &process_cmdline)) {std::replace(process_cmdline.begin(), process_cmdline.end(), '\0', ' ');process_cmdline = Trim(process_cmdline);} else {process_cmdline = "unknown process";}Service* service = nullptr;auto action = message;if (ConsumePrefix(&action, "interface_")) {service = ServiceList::GetInstance().FindInterface(name);} else {service = ServiceList::GetInstance().FindService(name);}if (service == nullptr) {LOG(ERROR) << "Control message: Could not find '" << name << "' for ctl." << message<< " from pid: " << from_pid << " (" << process_cmdline << ")";return false;}const auto& map = GetControlMessageMap();const auto it = map.find(action);if (it == map.end()) {LOG(ERROR) << "Unknown control msg '" << message << "'";return false;}const auto& function = it->second;if (auto result = function(service); !result.ok()) {LOG(ERROR) << "Control message: Could not ctl." << message << " for '" << name<< "' from pid: " << from_pid << " (" << process_cmdline<< "): " << result.error();return false;}LOG(INFO) << "Control message: Processed ctl." << message << " for '" << name<< "' from pid: " << from_pid << " (" << process_cmdline << ")";return true;
}

2.开机动画的播放过程

frameworks/base/cmds/bootanimation/bootanimation_main.cpp

frameworks/base/cmds/bootanimation/BootAnimation.cpp

int main()
{sp<ProcessState> proc(ProcessState::self());ProcessState::self()->startThreadPool();// create the boot animation object (may take up to 200ms for 2MB zip)//创建BootAnimation实例sp<BootAnimation> boot = new BootAnimation(audioplay::createAnimationCallbacks());waitForSurfaceFlinger();//等待surfaceflinger启动成功boot->run("BootAnimation", PRIORITY_DISPLAY);ALOGV("Boot animation set up. Joining pool.");IPCThreadState::self()->joinThreadPool();//binder线程池,与surfaceflinger通信用的。return 0;
}

接下来到BootAnimation的构造函数中

BootAnimation::BootAnimation(sp<Callbacks> callbacks): Thread(false), mLooper(new Looper(false)), mClockEnabled(true), mTimeIsAccurate(false),mTimeFormat12Hour(false), mTimeCheckThread(nullptr), mCallbacks(callbacks) {//mSession属于与SurfaceFlinger通信的Client端对象,通过这个对象来进行对应的Surface创建与申请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());
}//因为在创建BootAnimation时使用强引用计数,所以第一个引用时会调用这个函数
void BootAnimation::onFirstRef() {//在preload函数中会根据设备的不同状态(加密、关机、用户空间重启等)来选择对应的动画文件preloadAnimation();
}

在main函数中调用run函数后就进入readyToRun函数,这里面主要是为了获取一块画布,初始化opengl

status_t BootAnimation::readyToRun() {mAssets.addDefaultAssets();mDisplayToken = SurfaceComposerClient::getInternalDisplayToken();if (mDisplayToken == nullptr)return NAME_NOT_FOUND;DisplayMode displayMode;const status_t error =SurfaceComposerClient::getActiveDisplayMode(mDisplayToken, &displayMode);if (error != NO_ERROR)return error;mMaxWidth = android::base::GetIntProperty("ro.surface_flinger.max_graphics_width", 0);mMaxHeight = android::base::GetIntProperty("ro.surface_flinger.max_graphics_height", 0);ui::Size resolution = displayMode.resolution;resolution = limitSurfaceSize(resolution.width, resolution.height);// create the native surfacesp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"),resolution.getWidth(), resolution.getHeight(), PIXEL_FORMAT_RGB_565);SurfaceComposerClient::Transaction t;// this guest property specifies multi-display IDs to show the boot animation// multiple ids can be set with comma (,) as separator, for example:// setprop persist.boot.animation.displays 19260422155234049,19261083906282754Vector<PhysicalDisplayId> physicalDisplayIds;char displayValue[PROPERTY_VALUE_MAX] = "";property_get(DISPLAYS_PROP_NAME, displayValue, "");bool isValid = displayValue[0] != '\0';if (isValid) {char *p = displayValue;while (*p) {if (!isdigit(*p) && *p != ',') {isValid = false;break;}p ++;}if (!isValid)SLOGE("Invalid syntax for the value of system prop: %s", DISPLAYS_PROP_NAME);}if (isValid) {std::istringstream stream(displayValue);for (PhysicalDisplayId id; stream >> id.value; ) {physicalDisplayIds.add(id);if (stream.peek() == ',')stream.ignore();}// In the case of multi-display, boot animation shows on the specified displays// in addition to the primary displayconst auto ids = SurfaceComposerClient::getPhysicalDisplayIds();for (const auto id : physicalDisplayIds) {if (std::find(ids.begin(), ids.end(), id) != ids.end()) {if (const auto token = SurfaceComposerClient::getPhysicalDisplayToken(id)) {t.setDisplayLayerStack(token, ui::DEFAULT_LAYER_STACK);}}}t.setLayerStack(control, ui::DEFAULT_LAYER_STACK);}t.setLayer(control, 0x40000000).apply();sp<Surface> s = control->getSurface();// initialize opengl and eglEGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);eglInitialize(display, nullptr, nullptr);EGLConfig config = getEglConfig(display);EGLSurface surface = eglCreateWindowSurface(display, config, s.get(), nullptr);// Initialize egl context with client version number 2.0.EGLint contextAttributes[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};EGLContext context = eglCreateContext(display, config, nullptr, contextAttributes);EGLint w, h;eglQuerySurface(display, surface, EGL_WIDTH, &w);eglQuerySurface(display, surface, EGL_HEIGHT, &h);if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)return NO_INIT;mDisplay = display;mContext = context;mSurface = surface;mInitWidth = mWidth = w;mInitHeight = mHeight = h;mFlingerSurfaceControl = control;mFlingerSurface = s;mTargetInset = -1;projectSceneToWindow();// Register a display event receivermDisplayEventReceiver = std::make_unique<DisplayEventReceiver>();status_t status = mDisplayEventReceiver->initCheck();SLOGE_IF(status != NO_ERROR, "Initialization of DisplayEventReceiver failed with status: %d",status);mLooper->addFd(mDisplayEventReceiver->getFd(), 0, Looper::EVENT_INPUT,new DisplayEventCallback(this), nullptr);return NO_ERROR;
}

BootAnimation类的成员函数session用来返回BootAnimation类的成员变量mSession所描述的一个SurfaceComposerClient对象。通过调用SurfaceComposerClient对象mSession的成员函数createSurface可以获得一个SurfaceControl对象control。

SurfaceComposerClient类的成员函数createSurface首先调用内部的Binder代理对象mClient来请求SurfaceFlinger返回一个类型为SurfaceLayer的Binder代理对象,接着再使用这个Binder代理对象来创建一个SurfaceControl对象。创建出来的SurfaceControl对象的成员变量mSurface就指向了从SurfaceFlinger返回来的类型为SurfaceLayer的Binder代理对象。有了这个Binder代理对象之后,SurfaceControl对象就可以和SurfaceFlinger服务通信了。

调用SurfaceControl对象control的成员函数getSurface会返回一个Surface对象s。这个Surface对象s内部也有一个类型为SurfaceLayer的Binder代理对象mSurface,这个Binder代理对象与前面所创建的SurfaceControl对象control的内部的Binder代理对象mSurface引用的是同一个SurfaceLayer对象。这样,Surface对象s也可以通过其内部的Binder代理对象mSurface来和SurfaceFlinger服务通信。

       Surface类继承了ANativeWindow类。ANativeWindow类是连接OpenGL和Android窗口系统的桥梁,即OpenGL需要通过ANativeWindow类来间接地操作Android窗口系统。这种桥梁关系是通过EGL库来建立的,所有以egl为前缀的函数名均为EGL库提供的接口。

为了能够在OpenGL和Android窗口系统之间的建立一个桥梁,我们需要一个EGLDisplay对象display,一个EGLConfig对象config,一个EGLSurface对象surface,以及一个EGLContext对象context,其中,EGLDisplay对象display用来描述一个EGL显示屏,EGLConfig对象config用来描述一个EGL帧缓冲区配置参数,EGLSurface对象surface用来描述一个EGL绘图表面,EGLContext对象context用来描述一个EGL绘图上下文(状态),它们是分别通过调用egl库函数eglGetDisplay、EGLUtils::selectConfigForNativeWindow、eglCreateWindowSurface和eglCreateContext来获得的。注意,EGLConfig对象config、EGLSurface对象surface和EGLContext对象context都是用来描述EGLDisplay对象display的。有了这些对象之后,就可以调用函数eglMakeCurrent来设置当前EGL库所使用的绘图表面以及绘图上下文。  

还有另外一个地方需要注意的是,每一个EGLSurface对象surface有一个关联的ANativeWindow对象。这个ANativeWindow对象是通过函数eglCreateWindowSurface的第三个参数来指定的。在我们这个场景中,这个ANativeWindow对象正好对应于前面所创建的 Surface对象s。每当OpenGL需要绘图的时候,它就会找到前面所设置的绘图表面,即EGLSurface对象surface。有了EGLSurface对象surface之后,就可以找到与它关联的ANativeWindow对象,即Surface对象s。有了Surface对象s之后,就可以通过其内部的Binder代理对象mSurface来请求  SurfaceFlinger服务返回帧缓冲区硬件设备的一个图形访问接口。这样,OpenGL最终就可以将要绘制的图形渲染到帧缓冲区硬件设备中去,即显示在实际屏幕上。屏幕的大小,即宽度和高度,可以通过函数eglQuerySurface来获得。


在一系列的准备工作后,最后进入开机动画的播放流程,这里默认走android()流程播放开机动画

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());initTexture(&mAndroid[0], mAssets, "images/android-logo-mask.png");initTexture(&mAndroid[1], mAssets, "images/android-logo-shine.png");mCallbacks->init({});// clear screenglDisable(GL_DITHER);glDisable(GL_SCISSOR_TEST);glUseProgram(mImageShader);glClearColor(0,0,0,1);glClear(GL_COLOR_BUFFER_BIT);eglSwapBuffers(mDisplay, mSurface);// Blend stateglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);const nsecs_t startTime = systemTime();do {processDisplayEvents();const GLint xc = (mWidth  - mAndroid[0].w) / 2;const GLint yc = (mHeight - mAndroid[0].h) / 2;const Rect updateRect(xc, yc, xc + mAndroid[0].w, yc + mAndroid[0].h);glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(),updateRect.height());nsecs_t now = systemTime();double time = now - startTime;float t = 4.0f * float(time / us2ns(16667)) / mAndroid[1].w;GLint offset = (1 - (t - floorf(t))) * mAndroid[1].w;GLint x = xc - offset;glDisable(GL_SCISSOR_TEST);glClear(GL_COLOR_BUFFER_BIT);glEnable(GL_SCISSOR_TEST);glDisable(GL_BLEND);glBindTexture(GL_TEXTURE_2D, mAndroid[1].name);drawTexturedQuad(x,                 yc, mAndroid[1].w, mAndroid[1].h);drawTexturedQuad(x + mAndroid[1].w, yc, mAndroid[1].w, mAndroid[1].h);glEnable(GL_BLEND);glBindTexture(GL_TEXTURE_2D, mAndroid[0].name);drawTexturedQuad(xc, yc, mAndroid[0].w, mAndroid[0].h);EGLBoolean res = eglSwapBuffers(mDisplay, mSurface);if (res == EGL_FALSE)break;// 12fps: don't animate too fast to preserve CPUconst nsecs_t sleepTime = 83333 - ns2us(systemTime() - now);if (sleepTime > 0)usleep(sleepTime);checkExit();} while (!exitPending());glDeleteTextures(1, &mAndroid[0].name);glDeleteTextures(1, &mAndroid[1].name);return false;
}

3.开机动画的结束源码分析

这里还有一点就是开机动画的退出流程检测

static const char EXIT_PROP_NAME[] = "service.bootanim.exit";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();}
}

这里可以看到是通过检测prop service.bootanim.exit来判断是否申请退出的。那么这个prop的值是由谁设置的呢?

通过搜索框架中的代码可以看到,这个prop在 WindowManagerService.java  和 SurfaceFlinger.cpp 中都有设置。

先分析WindowManagerService.java 中这个prop的设置流程

通过堆栈打印,可以分析到一部分流程,下面会反向贴出一层层调用流程的代码

frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.javaprivate void performEnableScreen() {android.util.Log.i("test1", "performEnableScreen() ", new Exception());synchronized (mGlobalLock) {
......if (!mBootAnimationStopped) {Trace.asyncTraceBegin(TRACE_TAG_WINDOW_MANAGER, "Stop bootanim", 0);// stop boot animation// formerly we would just kill the process, but we now ask it to exit so it// can choose where to stop the animation.SystemProperties.set("service.bootanim.exit", "1");mBootAnimationStopped = true;}
......try {IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");if (surfaceFlinger != null) {ProtoLog.i(WM_ERROR, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");Parcel data = Parcel.obtain();data.writeInterfaceToken("android.ui.ISurfaceComposer");surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHEDdata, null, 0);data.recycle();}} catch (RemoteException ex) {ProtoLog.e(WM_ERROR, "Boot completed: SurfaceFlinger is dead!");}EventLogTags.writeWmBootAnimationDone(SystemClock.uptimeMillis());Trace.asyncTraceEnd(TRACE_TAG_WINDOW_MANAGER, "Stop bootanim", 0);mDisplayEnabled = true;ProtoLog.i(WM_DEBUG_SCREEN_ON, "******************** ENABLING SCREEN!");// Enable input dispatch.mInputManagerCallback.setEventDispatchingLw(mEventDispatchingEnabled);}try {mActivityManager.bootAnimationComplete();} catch (RemoteException e) {}mPolicy.enableScreenAfterBoot();// Make sure the last requested orientation has been applied.updateRotationUnchecked(false, false);
}public void enableScreenAfterBoot() {synchronized (mGlobalLock) {ProtoLog.i(WM_DEBUG_BOOT, "enableScreenAfterBoot: mDisplayEnabled=%b "+ "mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. "+ "%s",mDisplayEnabled, mForceDisplayEnabled, mShowingBootMessages, mSystemBooted,new RuntimeException("here").fillInStackTrace());if (mSystemBooted) {return;}mSystemBooted = true;hideBootMessagesLocked();// If the screen still doesn't come up after 30 seconds, give// up and turn it on.mH.sendEmptyMessageDelayed(H.BOOT_TIMEOUT, 30 * 1000);}mPolicy.systemBooted();performEnableScreen();
}frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.javapublic void enableScreenAfterBoot(boolean booted) {writeBootProgressEnableScreen(SystemClock.uptimeMillis());mWindowManager.enableScreenAfterBoot();synchronized (mGlobalLock) {updateEventDispatchingLocked(booted);}
}void postFinishBooting(boolean finishBooting, boolean enableScreen) {mH.post(() -> {if (finishBooting) {mAmInternal.finishBooting();}if (enableScreen) {mInternal.enableScreenAfterBoot(isBooted());}});
}frameworks/base/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java/*** Called when all resumed tasks/root-tasks are idle.*/
@GuardedBy("mService")
private void checkFinishBootingLocked() {final boolean booting = mService.isBooting();boolean enableScreen = false;mService.setBooting(false);if (!mService.isBooted()) {mService.setBooted(true);enableScreen = true;}if (booting || enableScreen) {mService.postFinishBooting(booting, enableScreen);}
}void activityIdleInternal(ActivityRecord r, boolean fromTimeout,boolean processPausingActivities, Configuration config) {
......// We are now idle.  If someone is waiting for a thumbnail from// us, we can now deliver.r.idle = true;// Check if able to finish booting when device is booting and all resumed activities// are idle.if ((mService.isBooting() && mRootWindowContainer.allResumedActivitiesIdle())|| fromTimeout) {checkFinishBootingLocked();}
......// When activity is idle, we consider the relaunch must be successful, so let's clear// the flag.r.mRelaunchReason = RELAUNCH_REASON_NONE;}
}frameworks/base/services/core/java/com/android/server/wm/ActivityClientController.javapublic void activityIdle(IBinder token, Configuration config, boolean stopProfiling) {final long origId = Binder.clearCallingIdentity();try {synchronized (mGlobalLock) {Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "activityIdle");final ActivityRecord r = ActivityRecord.forTokenLocked(token);if (r == null) {return;}mTaskSupervisor.activityIdleInternal(r, false /* fromTimeout */,false /* processPausingActivities */, config);if (stopProfiling && r.hasProcess()) {r.app.clearProfilerIfNeeded();}}} finally {Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);Binder.restoreCallingIdentity(origId);}
}frameworks/base/core/java/android/app/ActivityThread.javaprivate class Idler implements MessageQueue.IdleHandler {@Overridepublic final boolean queueIdle() {ActivityClientRecord a = mNewActivities;boolean stopProfiling = false;if (mBoundApplication != null && mProfiler.profileFd != null&& mProfiler.autoStopProfiler) {stopProfiling = true;}if (a != null) {mNewActivities = null;final ActivityClient ac = ActivityClient.getInstance();ActivityClientRecord prev;do {if (localLOGV) Slog.v(TAG, "Reporting idle of " + a +" finished=" +(a.activity != null && a.activity.mFinished));if (a.activity != null && !a.activity.mFinished) {ac.activityIdle(a.token, a.createdConfig, stopProfiling);a.createdConfig = null;}prev = a;a = a.nextIdle;prev.nextIdle = null;} while (a != null);}if (stopProfiling) {mProfiler.stopProfiling();}return false;}
}@Override
public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,boolean isForward, String reason) {
......Looper.myQueue().addIdleHandler(new Idler());
}

在Activity resume函数中注册空闲处理任务,空闲处理在activity空闲时会进入系统流程,最后走到performEnableScreen 中设置prop。

SurfaceFlinger.cpp中的流程如下

void SurfaceFlinger::bootFinished() {
......// stop boot animation// formerly we would just kill the process, but we now ask it to exit so it// can choose where to stop the animation.property_set("service.bootanim.exit", "1");......
}frameworks/native/libs/gui/ISurfaceComposer.cppstatus_t BnSurfaceComposer::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{switch(code) {
......case BOOT_FINISHED: {CHECK_INTERFACE(ISurfaceComposer, data, reply);bootFinished();return NO_ERROR;}
......}
}frameworks/native/services/surfaceflinger/SurfaceFlinger.cppstatus_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* reply,uint32_t flags) {
......status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags);
......
}class BnSurfaceComposer: public BnInterface<ISurfaceComposer> {
public:enum ISurfaceComposerTag {// Note: BOOT_FINISHED must remain this value, it is called from// Java by ActivityManagerService.BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION,
......
}
}private void performEnableScreen() {android.util.Log.i("test1", "performEnableScreen() ", new Exception());try {IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");if (surfaceFlinger != null) {ProtoLog.i(WM_ERROR, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");Parcel data = Parcel.obtain();data.writeInterfaceToken("android.ui.ISurfaceComposer");surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHEDdata, null, 0);data.recycle();}} catch (RemoteException ex) {ProtoLog.e(WM_ERROR, "Boot completed: SurfaceFlinger is dead!");}EventLogTags.writeWmBootAnimationDone(SystemClock.uptimeMillis());Trace.asyncTraceEnd(TRACE_TAG_WINDOW_MANAGER, "Stop bootanim", 0);mDisplayEnabled = true;ProtoLog.i(WM_DEBUG_SCREEN_ON, "******************** ENABLING SCREEN!");// Enable input dispatch.mInputManagerCallback.setEventDispatchingLw(mEventDispatchingEnabled);}}

可以看到,SurfaceFlinger中设置动画退出流程的prop其实也是performEnableScreen 发出去的。

4.开机动画opengl绘制分析

bool BootAnimation::android() {glActiveTexture(GL_TEXTURE0);SLOGD("%sAnimationShownTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot",elapsedRealtime());//初始化两张开机图片initTexture(&mAndroid[0], mAssets, "images/android-logo-mask.png");initTexture(&mAndroid[1], mAssets, "images/android-logo-shine.png");mCallbacks->init({});// clear screen//禁用一些GL功能(抖动和剪裁测试) glDisable(GL_DITHER);glDisable(GL_SCISSOR_TEST);glUseProgram(mImageShader);//设置清屏颜色为黑色,清空颜色缓冲区,并交换缓冲区,从而将黑色屏幕显示出来glClearColor(0,0,0,1);glClear(GL_COLOR_BUFFER_BIT);eglSwapBuffers(mDisplay, mSurface);// Blend stateglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);const nsecs_t startTime = systemTime();do {processDisplayEvents();const GLint xc = (mWidth  - mAndroid[0].w) / 2;const GLint yc = (mHeight - mAndroid[0].h) / 2;const Rect updateRect(xc, yc, xc + mAndroid[0].w, yc + mAndroid[0].h);glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(),updateRect.height());nsecs_t now = systemTime();double time = now - startTime;float t = 4.0f * float(time / us2ns(16667)) / mAndroid[1].w;GLint offset = (1 - (t - floorf(t))) * mAndroid[1].w;GLint x = xc - offset;glDisable(GL_SCISSOR_TEST);glClear(GL_COLOR_BUFFER_BIT);glEnable(GL_SCISSOR_TEST);glDisable(GL_BLEND);//glBindTexture 绘制图片glBindTexture(GL_TEXTURE_2D, mAndroid[1].name);drawTexturedQuad(x,                 yc, mAndroid[1].w, mAndroid[1].h);drawTexturedQuad(x + mAndroid[1].w, yc, mAndroid[1].w, mAndroid[1].h);glEnable(GL_BLEND);//glBindTexture 绘制图片glBindTexture(GL_TEXTURE_2D, mAndroid[0].name);drawTexturedQuad(xc, yc, mAndroid[0].w, mAndroid[0].h);EGLBoolean res = eglSwapBuffers(mDisplay, mSurface);if (res == EGL_FALSE)break;// 12fps: don't animate too fast to preserve CPU//这里配置了帧率const nsecs_t sleepTime = 83333 - ns2us(systemTime() - now);if (sleepTime > 0)usleep(sleepTime);checkExit();} while (!exitPending());//如果动画结束,要对纹理进行删除glDeleteTextures(1, &mAndroid[0].name);glDeleteTextures(1, &mAndroid[1].name);return false;
}

初始化两张图片的样式

status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,const char* name, bool premultiplyAlpha) {//打开图片文件  并获取图片数据Asset* asset = assets.open(name, Asset::ACCESS_BUFFER);if (asset == nullptr)return NO_INIT;AndroidBitmapInfo bitmapInfo;void* pixels = decodeImage(asset->getBuffer(false), asset->getLength(), &bitmapInfo,premultiplyAlpha);auto pixelDeleter = std::unique_ptr<void, decltype(free)*>{ pixels, free };asset->close();delete asset;if (!pixels) {return NO_INIT;}const int w = bitmapInfo.width;const int h = bitmapInfo.height;//从解码后的位图信息中获取宽高texture->w = w;texture->h = h;//opengl 生成纹理glGenTextures(1, &texture->name);//绑定纹理glBindTexture(GL_TEXTURE_2D, texture->name);//根据不同的数据格式将数据放到纹理里面去switch (bitmapInfo.format) {case ANDROID_BITMAP_FORMAT_A_8:glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_ALPHA,GL_UNSIGNED_BYTE, pixels);break;case ANDROID_BITMAP_FORMAT_RGBA_4444:glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,GL_UNSIGNED_SHORT_4_4_4_4, pixels);break;case ANDROID_BITMAP_FORMAT_RGBA_8888:glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,GL_UNSIGNED_BYTE, pixels);break;case ANDROID_BITMAP_FORMAT_RGB_565:glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB,GL_UNSIGNED_SHORT_5_6_5, pixels);break;default:break;}//设置纹理参数  设置纹理的过滤和环绕方式glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);return NO_ERROR;
}
http://www.dtcms.com/a/478800.html

相关文章:

  • 香港大学等提出增量天气预报模型VA-MoE,参数精简 75% 仍达 SOTA 性能
  • 北京企业建站服务中企论坛排名
  • 江门网站推广排名江苏省网站备案系统
  • Shuffle产生的三种场景
  • 公司网站制作的公司百度排名工具
  • 攻防世界-Web-shrine
  • arkTs:UIAbility 生命周期(补充版)
  • wordpress 首页导航代码广告网站建设网站排名优化
  • Synwit UI Creator中文输入法移植指南
  • wordpress tag生成的链接乱张家港优化网站seo
  • 中天建设集团网站wordpress显示不了图片
  • 【React】19.2 新特性全面解析:并发优化与性能提升指南
  • SALSITA AI:3D产品演示、安装动态过程展示
  • 网站建设国内现状松原网站推广
  • 东营区建设局网站湛江城乡建设局网站
  • 多制式基站综合测试线的架构与验证实践(2)
  • 基于单片机智能水产养殖系统设计(论文+源码)
  • 关于STM32L051单片机(Stop)休眠唤醒后初始化USART2,单片机死机问题
  • 做网站的一些好处科技类网站简介怎么做
  • xgboost参数含义以及应付金融数据中的类别不平衡的套路
  • 养殖类网站模板建筑设计网站排行榜
  • Cursor 对话技巧 【Prompt 模板与全局通用规则】
  • 按键控制LED灯
  • 打工人日报#202510012
  • 网站备案 做网站东莞有互联网企业吗
  • 涪城移动网站建设如何自己学建设网站
  • codeforces round1057(div2)AB题解
  • 【ADS】【python基础】jupyter notebook环境极简搭建
  • 【办公类-115-05】20250920职称资料上传04——PDF和PDF合并PDF、图片和PDF合并PDF(十三五PDF+十四五图片)
  • MySQL分库分表方案及优缺点分析