赞
踩
应用启动过程快的都不需要一秒钟,但这整个过程的执行是比较复杂的,无论是对手机厂商、应用开发来说启动速度也是核心用户体验指标之一,本文采用Android14源码与perfetto工具进行解析。
源码参考地址:Search
trace分析工具:Perfetto UI
Input 是Android系统最常见的事件驱动之一,用户的点击、滑动、长按等操作,都属于 input 事件驱动,其中跑在 SystemServer进程的两个 native 循环线程InputReader 和 InputDispatcher就是input的核心,负责读取和分发 Input 事件。整个处理过程大致流程如下:
从trace上分析如下:
这个过程可以先看一下trace的整体表现,然后再看对应的源码流程
launcher进程接收到input触控事件后调用binder调用框架AMS的的startActivity接口启动应用
相关简化代码如下:
/frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
- private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
- IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
- int startFlags, ActivityOptions options, Task inTask,
- TaskFragment inTaskFragment, @BalCode int balCode,
- NeededUriGrants intentGrants, int realCallingUid) {
- int result = START_CANCELED;
- final Task startedActivityRootTask;
-
- // Create a transition now to record the original intent of actions taken within
- // startActivityInner. Otherwise, logic in startActivityInner could start a different
- // transition based on a sub-action.
- // Only do the create here (and defer requestStart) since startActivityInner might abort.
- ....
- try {
- //添加"startActivityInner"tag
- Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner");
- // 执行startActivityInner启动应用的逻辑
- result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
- startFlags, options, inTask, inTaskFragment, balCode,
- intentGrants, realCallingUid);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
- startedActivityRootTask = handleStartResult(r, options, result, newTransition,
- remoteTransition);
- }
- }
- ....
-
- return result;
- }
在启动app前,需要检查当前前台resume状态的activity,一般为launcher应用,所以第一步需要让launcher的 activity 进入pause状态。相关简化代码逻辑如下:
/frameworks/base/services/core/java/com/android/server/wm/TaskFragment.java
- final boolean resumeTopActivity(ActivityRecord prev, ActivityOptions options,
- boolean deferPause) {
- boolean pausing = !deferPause && taskDisplayArea.pauseBackTasks(next);
- // mResumedActivity不为null,说明当前存在处于resume状态的Activity且不是新需要启动的应用
- if (mResumedActivity != null) {
- ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Pausing %s", mResumedActivity);
- // 执行startPausing通知桌面应用进入paused状态
- pausing |= startPausing(mTaskSupervisor.mUserLeaving, false /* uiSleeping */,
- next, "resumeTopActivity");
- }
- }
-
-
- boolean startPausing(boolean userLeaving, boolean uiSleeping, ActivityRecord resuming,
- String reason) {
- ......
- schedulePauseActivity(prev, userLeaving, pauseImmediately,
- false /* autoEnteringPip */, reason);
- ......
- }
-
-
- void schedulePauseActivity(ActivityRecord prev, boolean userLeaving,
- boolean pauseImmediately, boolean autoEnteringPip, String reason) {
- ProtoLog.v(WM_DEBUG_STATES, "Enqueueing pending pause: %s", prev);
- try {
- .....
- // 相关执行动作封装事务,binder通知mResumedActivity也就是桌面执行pause动作
- mAtmService.getLifecycleManager().scheduleTransaction(prev.app.getThread(),
- prev.token, PauseActivityItem.obtain(prev.finishing, userLeaving,
- prev.configChangeFlags, pauseImmediately, autoEnteringPip));
- } catch (Exception e) {
- // Ignore exception, if process died other code will cleanup.
- ....
- }
- }
桌面应用进程这边执行收到pause消息后执行Activity的onPause生命周期,并在执行完成后,会binder调用AMS的activityPaused接口通知系统执行完activity的pause动作,相关代码如下:
/frameworks/base/core/java/android/app/servertransaction/PauseActivityItem.java
- @Override
- public void postExecute(ClientTransactionHandler client, IBinder token,
- PendingTransactionActions pendingActions) {
- if (mDontReport) {
- return;
- }
- // TODO(lifecycler): Use interface callback instead of actual implementation.
- ActivityClient.getInstance().activityPaused(token);
- }
AMS这边收到应用的activityPaused调用后,继续执行启动应用的逻辑,判断需要启动的应用Activity所在的进程不存在,所以接下来需要先startProcessAsync创建应用进程,相关简化代码如下:
/frameworks/base/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
- void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {
- // Is this activity's application already running?
- final WindowProcessController wpc =
- mService.getProcessController(r.processName, r.info.applicationInfo.uid);
- ....
- // 1.如果wpc不为null且hasThread表示应用Activity所属进程存在,直接realStartActivityLocked启动Activity
- if (wpc != null && wpc.hasThread()) {
- try {
- realStartActivityLocked(r, wpc, andResume, checkConfig);
- return;
- }
- .......
- final boolean isTop = andResume && r.isTopRunningActivity();
- mService.startProcessAsync(r, knownToBeDead, isTop,
- isTop ? HostingRecord.HOSTING_TYPE_TOP_ACTIVITY
- : HostingRecord.HOSTING_TYPE_ACTIVITY);
- }
在桌面点击图标启动一个应用的组件如Activity时,如果Activity所在的进程不存在,就会创建并启动进程。Android系统中一般应用进程的创建都是统一由zygote进程fork创建的,AMS在需要创建应用进程时,会通过socket连接并通知到到zygote进程在开机阶段就创建好的socket服务端,然后由zygote进程fork创建出应用进程。整体架构如下图所示:
应用进程创建流程图.png
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
- @GuardedBy("this")
- final ProcessRecord startProcessLocked(...) {
- return mProcessList.startProcessLocked(...);
- }
frameworks/base/services/core/java/com/android/server/am/ProcessList.java
- private Process.ProcessStartResult startProcess(HostingRecord hostingRecord, String entryPoint,
- ProcessRecord app, int uid, int[] gids, int runtimeFlags, int zygotePolicyFlags,
- int mountExternal, String seInfo, String requiredAbi, String instructionSet,
- String invokeWith, long startTime) {
- try {
- // 原生标识应用进程创建所加的systrace tag
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
- app.processName);
- ...
- // 调用Process的start方法创建进程
- startResult = Process.start(...);
- ...
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- }
- }
frameworks/base/core/java/android/os/Process.java
- public static ProcessStartResult start(...) {
- // 调用ZygoteProcess的start函数
- return ZYGOTE_PROCESS.start(...);
- }
frameworks/base/core/java/android/os/ZygoteProcess.java
- public final Process.ProcessStartResult start(...){
- try {
- return startViaZygote(...);
- } catch (ZygoteStartFailedEx ex) {
- ...
- }
- }
-
- private Process.ProcessStartResult startViaZygote(...){
- ArrayList<String> argsForZygote = new ArrayList<String>();
- ...
- //在ZygoteProcess#startViaZygote中,最后创建应用进程的逻辑:
- 1. openZygoteSocketIfNeeded函数中打开本地socket客户端连接到zygote进程的socket服务端;
- 2. zygoteSendArgsAndGetResult发送socket请求参数,带上了创建的应用进程参数信息;
- 3. return返回的数据结构ProcessStartResult中会有新创建的进程的pid字段。
- return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
- }
其实早在系统开机阶段,zygote进程创建时,就会在ZygoteInit#main入口函数中创建服务端socket,并预加载系统资源和框架类(加速应用进程启动速度)
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
- public static void main(String[] argv) {
- ZygoteServer zygoteServer = null;
- ...
- try {
- ...
- // 1.preload提前加载框架通用类和系统资源到进程,加速进程启动
- preload(bootTimingsTraceLog);
- ...
- // 2.创建zygote进程的socket server服务端对象
- zygoteServer = new ZygoteServer(isPrimaryZygote);
- ...
- // 3.进入死循环,等待AMS发请求过来
- caller = zygoteServer.runSelectLoop(abiList);
- } catch (Throwable ex) {
- ...
- } finally {
- ...
- }
- ...
- }
继续往下看ZygoteServer#runSelectLoop如何监听并处理AMS客户端的请求:
frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
- Runnable runSelectLoop(String abiList) {
- // 进入死循环监听
- while (true) {
- while (--pollIndex >= 0) {
- if (pollIndex == 0) {
- ...
- } else if (pollIndex < usapPoolEventFDIndex) {
- // Session socket accepted from the Zygote server socket
- // 得到一个请求连接封装对象ZygoteConnection
- ZygoteConnection connection = peers.get(pollIndex);
- // processCommand函数中处理AMS客户端请求
- final Runnable command = connection.processCommand(this, multipleForksOK);
- }
- }
- }
- }
继续往下看ZygoteConnection#processCommand如何监听并处理AMS客户端的请求:
/frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
- Runnable processCommand(ZygoteServer zygoteServer, boolean multipleOK) {
- ...
- // 1.fork创建应用子进程
- pid = Zygote.forkAndSpecialize(...);
- try {
- if (pid == 0) {
- ...
- // 2.pid为0,当前处于新创建的子应用进程中,处理请求参数
- return handleChildProc(parsedArgs, childPipeFd, parsedArgs.mStartChildZygote);
- } else {
- ...
- handleParentProc(pid, serverPipeFd);
- }
- } finally {
- ...
- }
- }
-
- private Runnable handleChildProc(ZygoteArguments parsedArgs,
- FileDescriptor pipeFd, boolean isZygote) {
- ...
- // 关闭从父进程zygote继承过来的ZygoteServer服务端地址
- closeSocket();
- ...
- if (parsedArgs.mInvokeWith != null) {
- ...
- } else {
- if (!isZygote) {
- // 继续进入ZygoteInit#zygoteInit继续完成子应用进程的相关初始化工作
- return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
- parsedArgs.mDisabledCompatChanges,
- parsedArgs.mRemainingArgs, null /* classLoader */);
- } else {
- ...
- }
- }
- }
接上一节中的分析,zygote进程监听接收AMS的请求,fork创建子应用进程,然后pid为0时进入子进程空间,然后在 ZygoteInit#zygoteInit中完成进程的初始化动作
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
- public static Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,
- String[] argv, ClassLoader classLoader) {
- ...
- // 原生添加名为“ZygoteInit ”的systrace tag以标识进程初始化流程
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
- RuntimeInit.redirectLogStreams();
- // 1.RuntimeInit#commonInit中设置应用进程默认的java异常处理机制
- RuntimeInit.commonInit();
- // 2.ZygoteInit#nativeZygoteInit函数中JNI调用启动进程的binder线程池
- ZygoteInit.nativeZygoteInit();
- // 3.RuntimeInit#applicationInit中反射创建ActivityThread对象并调用其“main”入口方法
- return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv,
- classLoader);
- }
我们继续看RuntimeInit#applicationInit简化的代码流程:
frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
- protected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges,
- String[] argv, ClassLoader classLoader) {
- ...
- // 结束“ZygoteInit ”的systrace tag
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- // Remaining arguments are passed to the start class's static main
- return findStaticMain(args.startClass, args.startArgs, classLoader);
- }
-
- protected static Runnable findStaticMain(String className, String[] argv,
- ClassLoader classLoader) {
- Class<?> cl;
- try {
- // 1.反射加载创建ActivityThread类对象
- cl = Class.forName(className, true, classLoader);
- } catch (ClassNotFoundException ex) {
- ...
- }
- Method m;
- try {
- // 2.反射调用其main方法
- m = cl.getMethod("main", new Class[] { String[].class });
- } catch (NoSuchMethodException ex) {
- ...
- } catch (SecurityException ex) {
- ...
- }
- ...
- // 3.触发执行以上逻辑
- return new MethodAndArgsCaller(m, argv);
- }
我们继续往下看ActivityThread的main函数中又干了什么:
frameworks/base/core/java/android/app/ActivityThread.java
- public static void main(String[] args) {
- // 原生添加的标识进程ActivityThread初始化过程的systrace tag,名为“ActivityThreadMain”
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
- ...
- // 1.创建并启动主线程的loop消息循环
- Looper.prepareMainLooper();
- ...
- // 2.attachApplication注册到系统AMS中
- ActivityThread thread = new ActivityThread();
- thread.attach(false, startSeq);
- ...
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- Looper.loop();
- ...
- }
-
- private void attach(boolean system, long startSeq) {
- ...
- if (!system) {
- ...
- final IActivityManager mgr = ActivityManager.getService();
- try {
- // 通过binder调用AMS的attachApplication接口将自己注册到AMS中
- mgr.attachApplication(mAppThread, startSeq);
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
- }
- }
可以看到进程ActivityThread#main函数初始化的主要逻辑是:
主线程初始化完成后,主线程就有了完整的 Looper、MessageQueue、Handler,此时 ActivityThread 的 Handler 就可以开始处理 Message,包括 Application、Activity、ContentProvider、Service、Broadcast 等组件的生命周期函数,都会以 Message 的形式,在主线程按照顺序处理,这就是 App 主线程的初始化和运行原理。
主线程初始化完成后,主线程就进入阻塞状态,等待 Message,一旦有 Message 发过来,主线程就会被唤醒,处理 Message,处理完成之后,如果没有其他的 Message 需要处理,那么主线程就会进入休眠阻塞状态继续等待。可以说Android系统的运行是受消息机制驱动的,而整个消息机制是由上面所说的四个关键角色相互配合实现的(Handler、Looper、MessageQueue、Message):
应用进程启动初始化执行ActivityThread#main函数过程中,在开启主线程loop消息循环之前,会通过Binder调用系统核心服务AMS的attachApplication接口将自己注册到AMS中。下面我们接着这个流程往下看,我们先从systrace上看看AMS服务的attachApplication接口是如何处理应用进程的attach注册请求的:
attachApplication.png
我们继续来看相关代码的简化流程:
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
- @GuardedBy("this")
- private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
- int pid, int callingUid, long startSeq) {
- ...
- if (app.isolatedEntryPoint != null) {
- ...
- } else if (instr2 != null) {
- // 1.通过oneway异步类型的binder调用应用进程ActivityThread#IApplicationThread#bindApplication接口
- thread.bindApplication(...);
- } else {
- thread.bindApplication(...);
- }
- ...
- // See if the top visible activity is waiting to run in this process...
- if (normalMode) {
- try {
- // 2.继续执行启动应用Activity的流程
- didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
- } catch (Exception e) {
- Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
- badApp = true;
- }
- }
- }
-
- /*frameworks/base/core/java/android/app/ActivityThread.java*/
- private class ApplicationThread extends IApplicationThread.Stub {
- @Override
- public final void bindApplication(...) {
- ...
- AppBindData data = new AppBindData();
- data.processName = processName;
- data.appInfo = appInfo;
- ...
- // 向应用进程主线程Handler发送BIND_APPLICATION消息,触发在应用主线程执行handleBindApplication初始化动作
- sendMessage(H.BIND_APPLICATION, data);
- }
- ...
- }
-
- class H extends Handler {
- ...
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case BIND_APPLICATION:
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
- AppBindData data = (AppBindData)msg.obj;
- // 在应用主线程执行handleBindApplication初始化动作
- handleBindApplication(data);
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- break;
- ...
- }
- }
- ...
- }
-
- @UnsupportedAppUsage
- private void handleBindApplication(AppBindData data) {
- ...
- }
从上面的代码流程可以看出:AMS服务在执行应用的attachApplication注册请求过程中,会通过oneway类型的binder调用应用进程ActivityThread#IApplicationThread的bindApplication接口,而bindApplication接口函数实现中又会通过往应用主线程消息队列post BIND_APPLICATION消息触发执行handleBindApplication初始化函数,从systrace看如下图所示:
结合代码看看handleBindApplication的关键流程:
frameworks/base/core/java/android/app/ActivityThread.java
- @UnsupportedAppUsage
- private void handleBindApplication(AppBindData data) {
- ...
- // 1.创建应用的LoadedApk对象
- data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
- ...
- // 2.创建应用Application的Context、触发Art虚拟机加载应用APK的Dex文件到内存中,并加载应用APK的Resource资源
- final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
- ...
- // 3.调用LoadedApk的makeApplication函数,实现创建应用的Application对象
- app = data.info.makeApplicationInner(data.restrictedBackupMode, null);
- ...
- // 4.执行应用Application#onCreate生命周期函数
- mInstrumentation.onCreate(data.instrumentationArgs);
- ...
- }
在ActivityThread#**handleBindApplication初始化过程中在应用主线程中主要完成如下几件事件:
下面我们结合代码重点看看APK Dex文件的加载和Resource资源的加载流程。
frameworks/base/core/java/android/app/ContextImpl.java
- static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo,
- String opPackageName) {
- if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
- // 1.创建应用Application的Context对象
- ContextImpl context = new ContextImpl(null, mainThread, packageInfo,
- ContextParams.EMPTY, null, null, null, null, null, 0, null, opPackageName);
- // 2.触发加载APK的DEX文件和Resource资源
- context.setResources(packageInfo.getResources());
- context.mContextType = isSystemOrSystemUI(context) ? CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI
- : CONTEXT_TYPE_NON_UI;
- return context;
- }
-
-
-
frameworks/base/core/java/android/app/LoadedApk.java
-
- @UnsupportedAppUsage
- public Resources getResources() {
- if (mResources == null) {
- ...
- // 加载APK的Resource资源
- mResources = ResourcesManager.getInstance().getResources(null, mResDir,
- splitPaths, mLegacyOverlayDirs, mOverlayPaths,
- mApplicationInfo.sharedLibraryFiles, null, null, getCompatibilityInfo(),
- getClassLoader()//触发加载APK的DEX文件, null);
- }
- return mResources;
-
- @UnsupportedAppUsage
- public ClassLoader getClassLoader() {
- synchronized (mLock) {
- if (mClassLoader == null) {
- createOrUpdateClassLoaderLocked(null /*addedPaths*/);
- }
- return mClassLoader;
- }
- }
- private void createOrUpdateClassLoaderLocked(List<String> addedPaths) {
- if (!mIncludeCode) {
- if (mDefaultClassLoader == null) {
- StrictMode.ThreadPolicy oldPolicy = allowThreadDiskReads();
- //创建默认的mDefaultClassLoader对象,触发art虚拟机加载dex文件
- mDefaultClassLoader = ApplicationLoaders.getDefault().getClassLoader(
- "" /* codePath */, mApplicationInfo.targetSdkVersion, isBundledApp,
- librarySearchPath, libraryPermittedPath, mBaseClassLoader,
- null /* classLoaderName */);
- setThreadPolicy(oldPolicy);
- mAppComponentFactory = AppComponentFactory.DEFAULT;
- }
- }
- ...
- if (mClassLoader == null) {
- // 赋值给mClassLoader对象
- mClassLoader = mAppComponentFactory.instantiateClassLoader(mDefaultClassLoader,
- new ApplicationInfo(mApplicationInfo));
- }
- }
-
-
frameworks/base/core/java/android/app/ResourcesManager.java
- ClassLoader getClassLoaderWithSharedLibraries(...) {
- // For normal usage the cache key used is the same as the zip path.
- return getClassLoader(zip, targetSdkVersion, isBundled, librarySearchPath,
- libraryPermittedPath, parent, zip, classLoaderName, sharedLibraries,
- nativeSharedLibraries, sharedLibrariesLoadedAfterApp);
- }
-
- private ClassLoader getClassLoader(String zip, ...) {
- ...
- synchronized (mLoaders) {
- ...
- if (parent == baseParent) {
- ...
- // 1.创建BootClassLoader加载系统框架类,并增加相应的systrace tag
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
- ClassLoader classloader = ClassLoaderFactory.createClassLoader(
- zip, librarySearchPath, libraryPermittedPath, parent,
- targetSdkVersion, isBundled, classLoaderName, sharedLibraries,
- nativeSharedLibraries, sharedLibrariesLoadedAfterApp);
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- ...
- return classloader;
- }
- // 2.创建PathClassLoader加载应用APK的Dex类,并增加相应的systrace tag
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
- ClassLoader loader = ClassLoaderFactory.createClassLoader(
- zip, null, parent, classLoaderName, sharedLibraries,
- null /*sharedLibrariesLoadedAfterApp*/);
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- return loader;
- }
- }
frameworks/base/core/java/com/android/internal/os/ClassLoaderFactory.java
- public static ClassLoader createClassLoader(...) {
-
- ClassLoader[] arrayOfSharedLibraries = (sharedLibraries == null)
- ? null
- : sharedLibraries.toArray(new ClassLoader[sharedLibraries.size()]);
- if (isPathClassLoaderName(classloaderName)) {
- return new PathClassLoader(dexPath, librarySearchPath, parent, arrayOfSharedLibraries);
- }
- ...
- }
- public static ClassLoader createClassLoader(String dexPath,
- String librarySearchPath, ClassLoader parent, String classloaderName,
- List<ClassLoader> sharedLibraries, List<ClassLoader> sharedLibrariesLoadedAfter) {
- // 通过new的方式创建ClassLoader对象,最终会触发art虚拟机加载APK的dex文件
- ClassLoader[] arrayOfSharedLibraries = (sharedLibraries == null)
- ? null
- : sharedLibraries.toArray(new ClassLoader[sharedLibraries.size()]);
- ClassLoader[] arrayOfSharedLibrariesLoadedAfterApp = (sharedLibrariesLoadedAfter == null)
- ? null
- : sharedLibrariesLoadedAfter.toArray(
- new ClassLoader[sharedLibrariesLoadedAfter.size()]);
- if (isPathClassLoaderName(classloaderName)) {
- return new PathClassLoader(dexPath, librarySearchPath, parent, arrayOfSharedLibraries,
- arrayOfSharedLibrariesLoadedAfterApp);
- .....
- }
从以上代码可以看出:在创建Application的Context对象后会立马尝试去加载APK的Resource资源,而在这之前需要通过LoadedApk去创建类加载器ClassLoader对象,而这个过程最终就会触发Art虚拟机加载应用APK的dex文件,从systrace上看如下图所示:
OpenDexFilesFromOat.png
frameworks/base/core/java/android/app/ResourcesManager.java
- public @Nullable Resources getResources(...) {
- try {
- // 原生Resource资源加载的systrace tag
- Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "ResourcesManager#getResources");
- ...
- resources = createResources(key, classLoader, assetsSupplier);
- }
- return resources;
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
- }
- }
-
- private @Nullable Resources createResources(...) {
- synchronized (this) {
- ...
- // 执行创建Resources资源对象
- ResourcesImpl resourcesImpl = findOrCreateResourcesImplForKeyLocked(key, apkSupplier);
- if (resourcesImpl == null) {
- return null;
- }
- ...
- }
- }
-
- private @Nullable ResourcesImpl findOrCreateResourcesImplForKeyLocked(
- @NonNull ResourcesKey key, @Nullable ApkAssetsSupplier apkSupplier) {
- ...
- impl = createResourcesImpl(key, apkSupplier);
- ...
- }
-
- private @Nullable ResourcesImpl createResourcesImpl(@NonNull ResourcesKey key,
- @Nullable ApkAssetsSupplier apkSupplier) {
- ...
- // 创建AssetManager对象,真正实现的APK文件加载解析动作
- final AssetManager assets = createAssetManager(key, apkSupplier);
- ...
- }
-
- private @Nullable AssetManager createAssetManager(@NonNull final ResourcesKey key,
- @Nullable ApkAssetsSupplier apkSupplier) {
- ...
- for (int i = 0, n = apkKeys.size(); i < n; i++) {
- final ApkKey apkKey = apkKeys.get(i);
- try {
- // 通过loadApkAssets实现应用APK文件的加载
- builder.addApkAssets(
- (apkSupplier != null) ? apkSupplier.load(apkKey) : loadApkAssets(apkKey));
- } catch (IOException e) {
- ...
- }
- }
- ...
- }
-
- private @NonNull ApkAssets loadApkAssets(@NonNull final ApkKey key) throws IOException {
- ...
- if (key.overlay) {
- ...
- } else {
- // 通过ApkAssets从APK文件所在的路径去加载
- apkAssets = ApkAssets.loadFromPath(key.path, flags);
- }
- ...
- }
frameworks/base/core/java/android/content/res/ApkAssets.java
- public static @NonNull ApkAssets loadFromPath(@NonNull String path, @PropertyFlags int flags)
- throws IOException {
- return new ApkAssets(FORMAT_APK, path, flags, null /* assets */);
- }
-
- private ApkAssets(@FormatType int format, @NonNull String path, @PropertyFlags int flags,
- @Nullable AssetsProvider assets) throws IOException {
- ...
- // 通过JNI调用Native层的系统system/lib/libandroidfw.so库中的相关C函数实现对APK文件压缩包的解析与加载
- mNativePtr = nativeLoad(format, path, flags, assets);
- ...
- }
从以上代码可以看出:系统对于应用APK文件资源的加载过程其实就是创建应用进程中的Resources资源对象的过程,其中真正实现APK资源文件的I/O解析作,最终是借助于AssetManager中通过JNI调用系统Native层的相关C函数实现。整个过程从systrace上看如下图所示:
getResources.png
AMS在收到应用进程的attachApplication注册请求后,先通过oneway类型的binder调用应用及进程的IApplicationThread#bindApplication接口,触发应用进程在主线程执行handleBindeApplication初始化操作,然后继续执行启动应用Activity的操作,下面我们来看看系统是如何启动创建应用Activity的,简化代码流程如下:
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
- @GuardedBy("this")
- private boolean attachApplicationLocked(...) {
- ...
- if (app.isolatedEntryPoint != null) {
- ...
- } else if (instr2 != null) {
- // 1.通过oneway异步类型的binder调用应用进程ActivityThread#IApplicationThread#bindApplication接口
- thread.bindApplication(...);
- } else {
- thread.bindApplication(...);
- }
- ...
- // See if the top visible activity is waiting to run in this process...
- if (normalMode) {
- try {
- // 2.继续执行启动应用Activity的流程
- didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
- } catch (Exception e) {
- Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
- badApp = true;
- }
- }
- }
frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
- public boolean attachApplication(WindowProcessController wpc) throws RemoteException {
- synchronized (mGlobalLockWithoutBoost) {
- if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
- // 原生标识attachApplication过程的systrace tag
- Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "attachApplication:" + wpc.mName);
- }
- try {
- return mRootWindowContainer.attachApplication(wpc);
- } finally {
- Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
- }
- }
- }
frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java
- boolean attachApplication(WindowProcessController app) throws RemoteException {
- try {
- return mAttachApplicationHelper.process(app);
- } finally {
- mAttachApplicationHelper.reset();
- }
- }
- ......
- private class AttachApplicationHelper implements Consumer<Task>, Predicate<ActivityRecord> {
- private boolean mHasActivityStarted;
- private RemoteException mRemoteException;
- private WindowProcessController mApp;
- private ActivityRecord mTop;
- try {
- // realStartActivityLocked真正实现启动应用Activity流程
- if (mTaskSupervisor.realStartActivityLocked(r, mApp,
- mTop == r && r.getTask().canBeResumed(r) /* andResume */,
- true /* checkConfig */)) {
- mHasActivityStarted = true;
- }
- } catch (RemoteException e) {
- Slog.w(TAG, "Exception in new application when starting activity " + mTop, e);
- mRemoteException = e;
- return true;
- }
- return false;
- }
- }
- }
/frameworks/base/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
-
- boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
- boolean andResume, boolean checkConfig) throws RemoteException {
- ...
- // 1.先通过LaunchActivityItem封装Binder通知应用进程执行Launch Activity动作
- clientTransaction.addCallback(LaunchActivityItem.obtain(...);
- // Set desired final state.
- final ActivityLifecycleItem lifecycleItem;
- if (andResume) {
- // 2.再通过ResumeActivityItem封装Binder通知应用进程执行Launch Resume动作
- lifecycleItem = ResumeActivityItem.obtain(dc.isNextTransitionForward());
- }
- ...
- clientTransaction.setLifecycleStateRequest(lifecycleItem);
- // 执行以上封装的Binder调用
- mService.getLifecycleManager().scheduleTransaction(clientTransaction);
- ...
- }
从以上代码分析可以看到,框架system_server进程最终是通过ActivityTaskSupervisor#realStartActivityLocked函数中,通过LaunchActivityItem和ResumeActivityItem两个类的封装,依次实现binder调用通知应用进程这边执行Activity的Launch和Resume动作的,我们继续往下看相关代码流程:
frameworks/base/core/java/android/app/servertransaction/LaunchActivityItem.java
- public void execute(ClientTransactionHandler client, IBinder token,
- PendingTransactionActions pendingActions) {
- // 原生标识Activity Launch的systrace tag
- Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
- ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
- mOverrideConfig, mReferrer, mVoiceInteractor, mState, mPersistentState,
- mPendingResults, mPendingNewIntents, mActivityOptions, mIsForward, mProfilerInfo,
- client, mAssistToken, mShareableActivityToken, mLaunchedFromBubble,
- mTaskFragmentToken);
- // 调用到ActivityThread的handleLaunchActivity函数在主线程执行应用Activity的Launch创建动作
- client.handleLaunchActivity(r, pendingActions, mDeviceId, null /* customIntent */);
- Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
- }
frameworks/base/core/java/android/app/ActivityThread.java
- @Override
- public Activity handleLaunchActivity(ActivityClientRecord r,
- PendingTransactionActions pendingActions, Intent customIntent) {
- ...
- final Activity a = performLaunchActivity(r, customIntent);
- ...
- }
-
- /** Core implementation of activity launch. */
- private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
- ...
- // 1.创建Activity的Context
- ContextImpl appContext = createBaseContextForActivity(r);
- try {
- //2.反射创建Activity对象
- activity = mInstrumentation.newActivity(
- cl, component.getClassName(), r.intent);
- ...
- } catch (Exception e) {
- ...
- }
- try {
- ...
- if (activity != null) {
- ...
- // 3.执行Activity的attach动作
- activity.attach(...);
- ...
- // 4.执行应用Activity的onCreate生命周期函数,并在setContentView调用中创建DecorView对象
- mInstrumentation.callActivityOnCreate(activity, r.state);
- ...
- }
- ...
- } catch (SuperNotCalledException e) {
- ...
- }
- }
frameworks/base/core/java/android/app/Activity.java
- @UnsupportedAppUsage
- final void attach(...) {
- ...
- // 1.创建表示应用窗口的PhoneWindow对象
- mWindow = new PhoneWindow(this, window, activityConfigCallback);
- ...
- // 2.为PhoneWindow配置WindowManager
- mWindow.setWindowManager(
- (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
- mToken, mComponent.flattenToString(),
- (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
- ...
- }
从上面代码可以看出,应用进程这边在收到系统binder调用后,在主线程中创建Activiy的流程主要步骤如下:
ActivityStart.png
frameworks/base/core/java/android/app/servertransaction/ResumeActivityItem.java
- @Override
- public void execute(ClientTransactionHandler client, ActivityClientRecord r,
- PendingTransactionActions pendingActions) {
- // 原生标识Activity Resume的systrace tag
- Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
- client.handleResumeActivity(r, true /* finalStateRequest */, mIsForward,
- mShouldSendCompatFakeFocus, "RESUME_ACTIVITY");
- Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
- }
frameworks/base/core/java/android/app/ActivityThread.java
- @Override
- public void handleResumeActivity(...){
- ...
- // 1.执行performResumeActivity流程,执行应用Activity的onResume生命周期函数
- if (!performResumeActivity(r, finalStateRequest, reason)) {
- return;
- } ...
- if (r.window == null && !a.mFinished && willBeVisible) {
- ...
- if (a.mVisibleFromClient) {
- if (!a.mWindowAdded) {
- ...
- // 2.执行WindowManager#addView动作开启视图绘制逻辑
- wm.addView(decor, l);
- } else {
- ...
- }
- }
- }
- ...
- }
- public ActivityClientRecord performResumeActivity(...) {
- ...
- // 执行应用Activity的onResume生命周期函数
- r.activity.performResume(r.startsNotResumed, reason);
- ...
- }
frameworks/base/core/java/android/view/WindowManagerGlobal.java
- public void addView(...) {
- // 创建ViewRootImpl对象
- root = new ViewRootImpl(view.getContext(), display);
- ...
- try {
- // 执行ViewRootImpl的setView函数
- root.setView(view, wparams, panelParentView, userId);
- } catch (RuntimeException e) {
- ...
- }
- }
从上面代码可以看出,应用进程这边在接收到系统Binder调用请求后,在主线程中Activiy Resume的流程主要步骤如下:
activityResume.png
Choreographer 的引入,主要是配合系统Vsync垂直同步机制,在 Android 渲染链路扮演中承上启下的角色
承上:负责接收和处理 App 的各种更新消息和回调,等到 Vsync 到来的时候统一处理。比如集中处理 Input(主要是 Input 事件的处理) 、Animation(动画相关)、Traversal(包括 measure、layout、draw 等操作) ,判断卡顿掉帧情况,记录 CallBack 耗时等
启下:负责请求和接收 Vsync 信号。接收 Vsync 事件回调(通过 FrameDisplayEventReceiver.onVsync );请求 Vsync(FrameDisplayEventReceiver.scheduleVsync)
从上面可以看出来, Choreographer 担任的是一个工具人的角色,他之所以重要,是因为通过 Choreographer + SurfaceFlinger + Vsync + TripleBuffer 这一套从上到下的机制,保证了 Android App 可以以一个稳定的帧率运行(20fps、90fps 或者 60fps),减少帧率波动带来的不适感。
接上一节的分析,应用主线程中在执行Activity的Resume流程的最后,会创建ViewRootImpl对象并调用其setView函数,从此并开启了应用界面UI布局与绘制的流程。
我们从ViewRootImpl的setView流程继续结合代码往下看:
frameworks/base/core/java/android/view/ViewRootImpl.java
- public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
- int userId) {
- synchronized (this) {
- if (mView == null) {
- mView = view;
- }
- ...
- // 开启绘制硬件加速,初始化RenderThread渲染线程运行环境
- enableHardwareAcceleration(attrs);
- ...
- // 1.触发绘制动作
- requestLayout();
- ...
- inputChannel = new InputChannel();
- ...
- // 2.Binder调用访问系统窗口管理服务WMS接口,实现addWindow添加注册应用窗口的操作,并传入inputChannel用于接收触控事件
- res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
- getHostVisibility(), mDisplay.getDisplayId(), userId,
- mInsetsController.getRequestedVisibleTypes(), inputChannel, mTempInsets,
- mTempControls, attachedFrame, compatScale);
- ...
- // 3.创建WindowInputEventReceiver对象,实现应用窗口接收触控事件
- mInputEventReceiver = new WindowInputEventReceiver(inputChannel,
- Looper.myLooper());
- ...
- // 4.设置DecorView的mParent为ViewRootImpl
- view.assignParent(this);
- ...
- }
- }
从以上代码可以看出ViewRootImpl的setView内部关键流程如下:
我们顺着ViewRootImpl的requestLayout动作继续往下看界面绘制的流程代码:
frameworks/base/core/java/android/view/ViewRootImpl.java
- public void requestLayout() {
- if (!mHandlingLayoutInLayoutRequest) {
- // 检查当前UI绘制操作是否发生在主线程,如果发生在子线程则会抛出异常
- checkThread();
- mLayoutRequested = true;
- // 触发绘制操作
- scheduleTraversals();
- }
- }
-
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- void scheduleTraversals() {
- if (!mTraversalScheduled) {
- ...
- // 注意此处会往主线程的MessageQueue消息队列中添加同步栏删,因为系统绘制消息属于异步消息,需要更高优先级的处理
- mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
- // 通过Choreographer往主线程消息队列添加CALLBACK_TRAVERSAL绘制类型的待执行消息,用于触发后续UI线程真正实现绘制动作
- mChoreographer.postCallback(
- Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
- ...
- }
- }
ViewRootImpl会调用Choreographer的postCallback接口放入待执行的绘制消息后,Choreographer会先向系统申请APP 类型的vsync信号,然后等待系统vsync信号到来后,去回调到ViewRootImpl的doTraversal函数中执行真正的绘制动作(measure、layout、draw)。
我们接着ViewRootImpl的doTraversal函数的简化代码流程往下看:
frameworks/base/core/java/android/view/ViewRootImpl.java
- void doTraversal() {
- if (mTraversalScheduled) {
- mTraversalScheduled = false;
- // 调用removeSyncBarrier及时移除主线程MessageQueue中的Barrier同步栏删,以避免主线程发生“假死”
- mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
- ...
- // 执行具体的绘制任务
- performTraversals();
- ...
- }
- }
-
- private void performTraversals() {
- ...
- // 1.从DecorView根节点出发,遍历整个View控件树,完成整个View控件树的measure测量操作
- windowSizeMayChange |= measureHierarchy(...);
- ...
- if (mFirst...) {
- // 2.第一次执行traversals绘制任务时,Binder调用访问系统窗口管理服务WMS的relayoutWindow接口,实现WMS计算应用窗口尺寸并向系统surfaceflinger正式申请Surface“画布”操作
- relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
- }
- ...
- // 3.从DecorView根节点出发,遍历整个View控件树,完成整个View控件树的layout测量操作
- performLayout(lp, mWidth, mHeight);
- ...
- // 4.从DecorView根节点出发,遍历整个View控件树,完成整个View控件树的draw测量操作
- performDraw();
- ...
- }
-
- private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
- boolean insetsPending) throws RemoteException {
- ...
- // 通过Binder IPC访问系统WMS服务的relayout接口,申请Surface“画布”操作
- relayoutResult = mWindowSession.relayout(mWindow, params,
- requestedWidth, requestedHeight, viewVisibility,
- insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, mRelayoutSeq,
- mLastSyncSeqId, mTmpFrames, mPendingMergedConfiguration, mSurfaceControl,
- mTempInsets, mTempControls, mRelayoutBundle);
- ....
- if (mSurfaceControl.isValid()) {
- if (!useBLAST()) {
- // 本地Surface对象获取指向远端分配的Surface的引用
- mSurface.copyFrom(mSurfaceControl);
- } else {
- ...
- }
- }
- ...
- }
-
- private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
- ...
- // 原生标识View树的measure测量过程的trace tag
- Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
- try {
- // 从mView指向的View控件树的根节点DecorView出发,遍历访问整个View树,并完成整个布局View树的测量工作
- mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIEW);
- }
- }
-
- private void performDraw() {
- ...
- boolean canUseAsync = draw(fullRedrawNeeded);
- ...
- }
-
- private boolean draw(boolean fullRedrawNeeded) {
- ...
- if (mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled()) {
- ...
- // 如果开启并支持硬件绘制加速,则走硬件绘制的流程(从Android 4.+开始,默认情况下都是支持跟开启了硬件加速的)
- mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this);
- } else {
- // 否则走drawSoftware软件绘制的流程
- if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset,
- scalingRequired, dirty, surfaceInsets)) {
- return false;
- }
- }
- }
从上面的代码流程可以看出,ViewRootImpl中负责的整个应用界面绘制的主要流程如下:
借用一张图来总结应用UI绘制的流程,如下所示:
UI绘制流程.png
目前为止,用户依然看不到屏幕上显示的应用界面内容,因为整个Android系统的显示流程除了前面讲到的UI线程的绘制外,界面还需要经过RenderThread线程的渲染处理,渲染完成后,还需要通过Binder调用“上帧”交给surfaceflinger进程中进行合成后送显才能最终显示到屏幕上。
我们将接上一节中ViewRootImpl中最后draw的流程继续往下分析开启硬件加速情况下,RenderThread渲染线程的工作流程。由于目前Android 4.X之后系统默认界面是开启硬件加速的,所以本文我们重点分析硬件加速条件下的界面渲染流程,我们先分析一下简化的代码流程:
frameworks/base/core/java/android/view/ViewRootImpl.java
- private boolean draw(boolean fullRedrawNeeded) {
- ...
- if (mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled()) {
- ...
- // 硬件加速条件下的界面渲染流程
- mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this);
- } else {
- ...
- }
- }
frameworks/base/core/java/android/view/ThreadedRenderer.java
- void draw(View view, AttachInfo attachInfo, DrawCallbacks callbacks) {
- ...
- // 1.从DecorView根节点出发,递归遍历View控件树,记录每个View节点的绘制操作命令,完成绘制操作命令树的构建
- updateRootDisplayList(view, callbacks);
- ...
- // 2.JNI调用同步Java层构建的绘制命令树到Native层的RenderThread渲染线程,并唤醒渲染线程利用OpenGL执行渲染任务;
- int syncResult = syncAndDrawFrame(frameInfo);
- ...
- }
从上面的代码可以看出,硬件加速绘制主要包括两个阶段:
我们先来看看第一阶段构建绘制命令树的代码简化流程:
frameworks/base/core/java/android/view/ThreadedRenderer.java
- private void updateRootDisplayList(View view, DrawCallbacks callbacks) {
- // 原生标记构建View绘制操作命令树过程的systrace tag
- Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Record View#draw()");
- // 递归子View的updateDisplayListIfDirty实现构建DisplayListOp
- updateViewTreeDisplayList(view);
- ...
- if (mRootNodeNeedsUpdate || !mRootNode.hasDisplayList()) {
- // 获取根View的SkiaRecordingCanvas
- RecordingCanvas canvas = mRootNode.beginRecording(mSurfaceWidth, mSurfaceHeight);
- try {
- ...
- // 利用canvas缓存DisplayListOp绘制命令
- canvas.drawRenderNode(view.updateDisplayListIfDirty());
- ...
- } finally {
- // 将所有DisplayListOp绘制命令填充到RootRenderNode中
- mRootNode.endRecording();
- }
- }
- Trace.traceEnd(Trace.TRACE_TAG_VIEW);
- }
-
- private void updateViewTreeDisplayList(View view) {
- ...
- // 从DecorView根节点出发,开始递归调用每个View树节点的updateDisplayListIfDirty函数
- view.updateDisplayListIfDirty();
- ...
- }
frameworks/base/core/java/android/view/View.java
- public RenderNode updateDisplayListIfDirty() {
- ...
- // 1.利用`View`对象构造时创建的`RenderNode`获取一个`SkiaRecordingCanvas`“画布”;
- final RecordingCanvas canvas = renderNode.beginRecording(width, height);
- try {
- ...
- if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
- // 如果仅仅是ViewGroup,并且自身不用绘制,直接递归子View
- dispatchDraw(canvas);
- ...
- } else {
- // 2.利用SkiaRecordingCanvas,在每个子View控件的onDraw绘制函数中调用drawLine、drawRect等绘制操作时,创建对应的DisplayListOp绘制命令,并缓存记录到其内部的SkiaDisplayList持有的DisplayListData中;
- draw(canvas);
- }
- } finally {
- // 3.将包含有`DisplayListOp`绘制命令缓存的`SkiaDisplayList`对象设置填充到`RenderNode`中;
- renderNode.endRecording();
- ...
- }
- ...
- }
-
- @CallSuper
- public void draw(@NonNull Canvas canvas) {
- ...
- // draw the content(View自己实现的onDraw绘制,由应用开发者自己实现)
- onDraw(canvas);
- ...
- // draw the children
- dispatchDraw(canvas);
- ...
- }
frameworks/base/graphics/java/android/graphics/RenderNode.java
- public void endRecording() {
- if (mCurrentRecordingCanvas == null) {
- throw new IllegalStateException(
- "No recording in progress, forgot to call #beginRecording()?");
- }
- RecordingCanvas canvas = mCurrentRecordingCanvas;
- mCurrentRecordingCanvas = null;
- // 从SkiaRecordingCanvas中获取SkiaDisplayList对象
- canvas.finishRecording(this);
- // 将SkiaDisplayList对象填充到RenderNode中
- canvas.recycle();
- }
从以上代码可以看出,构建绘制命令树的过程是从View控件树的根节点DecorView触发,递归调用每个子View节点的updateDisplayListIfDirty函数,最终完成绘制树的创建,简述流程如下:
构建View绘制命令树.png
经过上一小节中的分析,应用在UI线程中从根节点DecorView出发,递归遍历每个子View节点,搜集其drawXXX绘制动作并转换成DisplayListOp命令,将其记录到DisplayListData并填充到RenderNode中,最终完成整个View绘制命令树的构建。从此UI线程的绘制任务就完成了。下一步UI线程将唤醒RenderThread渲染线程,触发其利用OpenGL执行界面的渲染任务,本小节中我们将重点分析这个流程。
frameworks/base/graphics/java/android/graphics/HardwareRenderer.java
- public int syncAndDrawFrame(@NonNull FrameInfo frameInfo) {
- // JNI调用native层的相关函数
- return nSyncAndDrawFrame(mNativeProxy, frameInfo.frameInfo, frameInfo.frameInfo.length);
- }
frameworks/base/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
- static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
- jlong proxyPtr, jlongArray frameInfo,
- jint frameInfoSize) {
- ...
- RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
- env->GetLongArrayRegion(frameInfo, 0, frameInfoSize, proxy->frameInfo());
- return proxy->syncAndDrawFrame();
- }
RenderProxy.cpp
frameworks/base/libs/hwui/renderthread/RenderProxy.cpp
- int RenderProxy::syncAndDrawFrame() {
- // 唤醒RenderThread渲染线程,执行DrawFrame绘制任务
- return mDrawFrameTask.drawFrame();
- }
frameworks/base/libs/hwui/renderthread/DrawFrameTask.cpp
- int DrawFrameTask::drawFrame() {
- ...
- postAndWait();
- ...
- }
-
- void DrawFrameTask::postAndWait() {
- AutoMutex _lock(mLock);
- // 向RenderThread渲染线程的MessageQueue消息队列放入一个待执行任务,以将其唤醒执行run函数
- mRenderThread->queue().post([this]() { run(); });
- // UI线程暂时进入wait等待状态
- mSignal.wait(mLock);
- }
-
- void DrawFrameTask::run() {
- // 原生标识一帧渲染绘制任务的systrace tag
- ATRACE_NAME("DrawFrame");
- ...
- {
- TreeInfo info(TreeInfo::MODE_FULL, *mContext);
- //1.将UI线程构建的DisplayListOp绘制命令树同步到RenderThread渲染线程
- canUnblockUiThread = syncFrameState(info);
- ...
- }
- ...
- // 同步完成后则可以唤醒UI线程
- // From this point on anything in "this" is *UNSAFE TO ACCESS*
- if (canUnblockUiThread) {
- unblockUiThread();
- }
- ...
- if (CC_LIKELY(canDrawThisFrame)) {
- // 2.执行draw渲染绘制动作
- context->draw(solelyTextureViewUpdates);
- } else {
- ...
- }
- ...
- }
-
- bool DrawFrameTask::syncFrameState(TreeInfo& info) {
- ATRACE_CALL();
- ...
- // 调用CanvasContext的prepareTree函数实现绘制命令树同步的流程
- mContext->prepareTree(info, mFrameInfo, mSyncQueued, mTargetNode);
- ...
- }
- void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t syncQueued,
- RenderNode* target) {
- ...
- for (const sp<RenderNode>& node : mRenderNodes) {
- ...
- // 递归调用各个子View对应的RenderNode执行prepareTree动作
- node->prepareTree(info);
- ...
- }
- ...
- }
frameworks/base/libs/hwui/RenderNode.cpp
-
- void RenderNode::prepareTree(TreeInfo& info) {
- ATRACE_CALL();
- ...
- prepareTreeImpl(observer, info, false);
- ...
- }
-
- void RenderNode::prepareTreeImpl(TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer) {
- ...
- if (info.mode == TreeInfo::MODE_FULL) {
- // 同步绘制命令树
- pushStagingDisplayListChanges(observer, info);
- }
- if (mDisplayList) {
- // 遍历调用各个子View对应的RenderNode的prepareTreeImpl
- bool isDirty = mDisplayList.prepareListAndChildren(
- observer, info, childFunctorsNeedLayer,
- [this](RenderNode* child, TreeObserver& observer, TreeInfo& info,
- bool functorsNeedLayer) {
- child->prepareTreeImpl(observer, info, functorsNeedLayer);
- mHasHolePunches |= child->hasHolePunches();
- });
- .....
- }.
- }
-
- void RenderNode::pushStagingDisplayListChanges(TreeObserver& observer, TreeInfo& info) {
- ...
- syncDisplayList(observer, &info);
- ...
- }
-
- void RenderNode::syncDisplayList(TreeObserver& observer, TreeInfo* info) {
- ...
- // 完成赋值同步DisplayList对象
- deleteDisplayList(observer, info);
- mDisplayList = std::move(mStagingDisplayList);
- ...
- }
/frameworks/base/libs/hwui/renderthread/CanvasContext.cpp
- void CanvasContext::draw() {
- ...
- // 1.调用OpenGL库使用GPU,按照构建好的绘制命令完成界面的渲染
- drawResult = mRenderPipeline->draw(frame, windowDirty, dirty, mLightGeometry,
- &mLayerUpdateQueue, mContentDrawBounds, mOpaque,
- mLightInfo, mRenderNodes, &(profiler()), mBufferParams);
- ...
- // 2.将前面已经绘制渲染好的图形缓冲区Binder上帧给SurfaceFlinger合成和显示
- bool didSwap = mRenderPipeline->swapBuffers(frame, drawResult.success, windowDirty,
- mCurrentFrameInfo, &requireSwap);
- }
从以上代码可以看出:UI线程利用RenderProxy向RenderThread线程发送一个DrawFrameTask任务请求,RenderThread被唤醒,开始渲染,大致流程如下:
RenderThread实现界面渲染.png
SurfaceFlinger合成显示部分完全属于Android系统GUI中图形显示的内容,逻辑结构也比较复杂,但不属于本文介绍内容的重点。所以本小节中只是总体上介绍一下其工作原理与思想,不再详细分析源码,感兴趣的读者可以关注笔者后续的文章再来详细分析讲解。简单的说SurfaceFlinger作为系统中独立运行的一个Native进程,借用Android官网的描述,其职责就是负责接受来自多个来源的数据缓冲区,对它们进行合成,然后发送到显示设备。如下图所示:
SurfaceFlinger工作原理.jpg
从上图可以看出,其实SurfaceFlinger在Android系统的整个图形显示系统中是起到一个承上启下的作用:
图形的传递是通过Buffer作为载体,Surface是对Buffer的进一步封装,也就是说Surface内部具有多个Buffer供上层使用,如何管理这些Buffer呢?答案就是BufferQueue ,下面我们来看看BufferQueue的工作原理:
借用一张经典的图来描述BufferQueue的工作原理:
BufferQueue状态转换图.jpg
BufferQueue是一个典型的生产者-消费者模型中的数据结构。在Android应用的渲染流程中,应用扮演的就是“生产者”的角色,而SurfaceFlinger扮演的则是“消费者”的角色,其配合工作的流程如下:
Vysnc垂直同步是Android在“黄油计划”中引入的一个重要机制,本质上是为了协调BufferQueue的应用生产者生成UI数据动作和SurfaceFlinger消费者的合成消费动作,避免出现画面撕裂的Tearing现象。Vysnc信号分为两种类型:
Vsync信号的生成是参考屏幕硬件的刷新周期的,其架构如下图所示:
vsync.png
SurfaceFlinger处理.png
本文结合Android 14源码和Perfetto分析了从用户手指点击桌面上的应用图标到屏幕上显示出应用主Activity界面第一帧画面的完整流程,这其中涉及了App应用、system_server框架、surfaceflinger等一系列Android系统核心模块的相互配合,有很多的细节也由于篇幅所限无法完全展开分析,感兴趣的读者可以结合AOSP源码继续深入分析。而优化应用启动打开的速度这个系统核心用户体验的指标,也是多少年来谷歌、SOC芯片厂商、ODM手机厂商以及各个应用开发者共同努力优化的方向:
https://www.androidperformance.com/2021/04/24/android-systrace-smooth-in-action-1/
史上最全Android渲染机制讲解(长文源码深度剖析)https://mp.weixin.qq.com/s?__biz=MzU2MTk0ODUxOQ==&mid=2247483782&idx=1&sn=f9eae167b217c83036b3a24cd4182cd1&chksm=fc71b38ecb063a9847f4518802fc541091d7f708b112399ec39827e68a6f590249748d643747&mpshare=1&scene=1&srcid=0224RGsfWeG5GyMpxLwEhx7N&sharer_sharetime=1582507745901&sharer_shareid=2d76fc4769fc55b6ca84ec3820ba5821#rd
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。