2018 年 12 月 ,Google 宣布 Flutter 1.0 版本正式发布。截至目前, Flutter 在 Github 上已获得 88000+ 的关注和 11000+ 的 Fork ,其发展速度相当惊人,是今年移动端最火热的开发框架之一。 Flutter 大火背后的原因是什么?为什么越来越多的企业和开发者会选择使用 Flutter?Flutter 会成为跨平台开发的终极之选吗?我认为“ Flutter 并非跨平台终极之选,最初选择 Flutter,不是因为它一定会成为未来终极之选,而是因为它有可能成为不一样的未来。” Flutter 大火的原因 有人说 Flutter 大火主要原因是它选择了 Dart 语言,Dart 有着高性能的表现和可快速分配内存的能力,能同时支持 JIT 和 AOT 模式,允许在带类型的语言中支持形变和有状态热重载,能编译出高效率的 ARM 机器码指令,Dart 作为面向对象的语言也能让绝大多数开发者更快速上手。我认可 Dart 语言有一定的优势,但这样的优势并非 Dart 独有,我想这更不会是大家选择 Flutter 的核心原因,这是因果倒置。事实上,Dart 是 2011 年推出的,在 Flutter 出现之前,Dart 曾一度几乎被人遗忘。正是因为近年来 Flutter 的火爆,才让 Dart 重新进入大众的视线。Flutter 当初选择 Dart,或者仅因为 Google 的 Flutter 和 Dart 这两个团队离得比较近,交流比较方便。 我认为 Flutter 之所以大火,主要是以下几个原因: 1. 现有跨平台技术存在缺陷 在移动互联网时代,Android 和 iOS 两大阵营长期共存,再加上体系成熟的 Web 前端技术,导致出现同一个应用需多端重复开发的人力成本问题。正因如此,移动时代下的跨平台技术是一个需要长期研究的课题。如果当下的跨平台技术已经有比较完美的解决方案,可能就没有新技术萌芽的机会。而事实上,目前业界比较成熟的跨平台技术都存在一定的缺陷,比如小程序(WebView)渲染耗时过长,白屏率会影响转化收益,能实现的功能非常受限;再比如 React Native 的性能不足、问题排除难、维护成本高等。而 Flutter 的出现,让这些跨平台开发问题有所改善,它还是 Google 开源的技术,自身也具备一定的热度。另外,一直备受关注且神秘的 Fuchsia 系统在 UI 框架上使用的也是 Flutter,可作为长期战略投入,这也增强了大家对 Flutter 的信心。 2. 研发效率就是竞争力 移动互联网进入下半场,出现一些新兴互联网独角兽、小巨头,在没有历史包袱的情况下,更愿意尝试技术上限更高的新技术。从校招和社招的难度上不难发现:客户端的人才相比之前更为稀缺,尤其是 iOS 工程师。而下半场会有更多竞争和更为激烈的赛道,比如教育等方向。Flutter 本身非常适合从零开始的没有历史包袱的应用开发,对于新业务尤其是在团队人力紧缺的情况下,在技术选型上考虑 Flutter,能加快产品在多端落地、快速试错。 3. 集漂亮与流畅集于一身 Flutter “一出生”就以“UI 漂亮、像素级可控、性能流畅、可媲美原生性能”等特点吸引广大开发者的眼球,自渲染引擎甚至具备开发游戏的能力。移动下半场,没有人口红利,竞争更为激烈,如何能更好地满足用户对高品质、高流畅的需求,便是移动端一种强有力的竞争力。跨平台技术想要拥有更高的流畅度,采用自渲染技术的方案便是更优解,也是一个更为彻底的跨平台技术方向。 字节跳动选择 Flutter 的初心 说到这里,先分享一下 Flutter 最初是如何诞生的故事。Flutter 创始人 Eric 之前在 Chrome 团队工作,期间遇到一些难以解决的问题, 希望 Web 中的一部分能够拥有更加平滑的体验, 为此他花了几周时间做了一个实验,不考虑 Web 的兼容方式,删除了大量为了兼容访问的代码和一些 Web 开发者不常用的功能, 删除到有不少 Web 元素的渲染已经不支持了,然后做了一个基准测试,得出结论是某些关注指标的速度快了 20 倍。于是,Eric 决定再做点什么,后面投入了大量研究和开发,便有了现在的 Flutter 。 听到这里给人的感觉是,对于 Web 工程师而言 Flutter 应该容易上手。我跟公司很多正在使用或者调研 Flutter 的业务团队做过沟通,发现客户端比前端的同学对 Flutter 接受度更高,我个人从 Android 端技术出身,的确觉得学习 Flutter 还是非常容易上手的,但公司内前端的同学对 Flutter 使用的吐槽会多一点。所以,我认为 Flutter 更像是以客户端视角的跨平台技术,Flutter 与其说是大前端技术,不如说是大移动端技术。Flutter 发展的 Roadmap 也是先全面支持 Android/iOS 端能力,再进一步完善 Web 端能力支持的。 字节跳动对于客户端技术还是非常重视的,字节跳动有很多客户端工程师,之前客户端深入点的基础技术更多是搞插件化、热修复、性能优化、安全加固等,跨平台方向一直都是前端工程师在不遗余力地推进,属于大前端方向。而 Flutter 是客户端更有主导的跨平台技术方案。另外说明,字节跳动并不是说只有一套跨平台技术栈,公司内部也是多套跨端技术栈并存,也包括自研的方案。 在字节跳动,跨平台技术并没有形成大规模的落地,之前也提到没有历史包袱,所以在面对跨平台技术选型的时候,更关注跨平台技术的技术上限以及发展潜力,自渲染技术的 Flutter 可以理解为更彻底更纯粹的跨平台技术,伴随着媲美原生的流畅度,这便是我们选择 Flutter 的初心。 Flutter 落地过程中的“坑” 截至目前,字节跳动有很多业务落地了 Flutter 技术方案,包括今日头条、西瓜视频、皮皮虾等 20 多个业务在使用 Flutter 开发,有纯 Flutter 工程,也有 Flutter 与 Native 的混合工程。如果大家想要了解更多业务落地情况,后续我会在今年的 QCon 北京 2020 大会上分享。 Flutter 虽潜力上限很高,但仍需打磨和雕琢,我们在 Flutter 推动过程中遇到很多问题,比如包体积过大的问题、性能达不到预期、对混合工程的支持不够友好、各宿主 Flutter 引擎版本不一致、基础库不完善、Flutter 改造后各项数据打平等。除此之外,还有很多非技术的困难,比如业务团队并不认可 Flutter 新技术,工程师缺乏 Flutter 经验,担忧审核风险等,都会影响业务方是否采用 Flutter 技术,每一个困难都需要去解决,不然就难以落地。下面就其中两个难点,我来展开聊一下。 1. 包体积问题 字节跳动内的大型 APP,比如今日头条、抖音等对包体积的增量非常敏感,Flutter 的包体积涉及两个部分,一个是一次性 Flutter 引擎的包体积问题,一个是每次写 Dart 代码比写 OC 代码代码增量的问题。这两个问题对我们来说都非常棘手,我们成立了包体积优化专项进行全力攻坚,同时跟 Google 工程师多次会议沟通,不断精简包体积。最终我们通过一系列优化手段,包含 Data 压缩、编译优化、Skia 裁剪、BoringSSL/ICU 库 / 文字渲染 /libwebp 等库裁剪取得了不少的效果;通过实践我们发现用 OC 代码和 Dart 代码写相同的业务逻辑,Dart 生成的机器码指令比 OC 多,主要在生成的二进制指令头、指令冗余、指令对齐的精简,以及 StackMap 和 CodeSourceMap 的精简等方面。同时我们也向 Google 反馈了这些情况。关于指令精简,可以查看 Issue 进展,里面有记录详细的推进过程: https://github.com/flutter/flutter/issues/40345 2. 性能优化问题 这是我们遇到的棘手问题之一,我们用 Flutter 官方提供的性能分析工具 Timeline 来分析一个比较诡异的性能问题,始终无法发现任何异常。困扰已久,后来干脆重新撸了一遍 Timeline 整个性能分析工具的源码,最终找到了其缺陷,并向 Flutter 社区提及,合入了 10 个 PR ,基于此让我有幸成为了 Flutter Member ,后续会持续向社区贡献更多力量:https://github.com/flutter/flutter/issues/47771. Flutter 是一个自渲染的跨平台技术,有着很高的性能上限,但并不代表现在性能各方面都很优秀,毕竟 Flutter 作为一个“新生儿”,还是有一些需要进一步改造的地方。除性能工具改造之外,其实在 Flutter 落地场景中,我们也解决了不少性能问题,同时优化了自身的引擎,比如 UI 预加载策略、Flutter Turbo 技术、Vsync 调度策略等,让引擎提速,争取让 Flutter 性能发挥到极致。 Flutter 在业务层面的发展阻力 引入 Flutter 之后,在公司的业务也创造了不少价值。主要体现在这几个方面:其一,Flutter 多端一致性上表现良好,能做到所见即所得,无需针对某一平台做额外适配工作;其二,热重载技术使得设计团队和工程团队可以非常快速的修改和调试 UI,设计师只需要关注一个平台实现,UI 验收效率明显提高,跨端开发可以提高工程师的人效(有团队初步估算人效大致提升了 1.8 倍);其三,性能流畅度提升,相较于 H5 版本首屏时间有较大提升,最后,产品商业化数据都有明显的收益,能直观地看到 Flutter 给公司带来的创收。 不过,现阶段 Flutter 的发展仍有一些阻力: 1. Flutter 采用的是 Dart 语言,没能引入前端成熟的生态体系 作为前端工程师可能更希望是 Flutter 上层采用的是 JavaScript 或者 TypeScript,未来可考虑提供高性能的 Dart 与 JS 互转能力。另外,Flutter 开发对于前端开发工程师而言,还是有一些挑战的,纯前端不一定能 Cover 的技术,比如 Flutter 的一个硬件相关的 Plugin 只在某款手机出现 Bug,如果社区没有现存解决方案,可能就需要花比较大的时间成本去学习 Native 技术,或者请教客户端工程师。 2. 开源库相对比较欠缺,更新频次不足 Flutter 生态还不够完善,新业务接入需要自己造轮子,尤其是在业务团队对 Flutter 掌握不够熟练的情况下,会增加额外的成本,Flutter 在大中型企业会更容易推广起来,有人力可以去造轮子让公司内其他的业务复用;另外,Flutter 文档有点少,能借鉴的经验不多,未来需加强和鼓励更多开发者加入到生态共建。 3. 跟原生系统生态存在着一定的竞争关系 有朋友跟我说起过这样一件事,看到 Flutter 这么火,Android 开发团队就问他,“大家为什么要用 Flutter 开发 App,我们 Android 哪一点不好,告诉我们,我们可以改进它”。姑且不说他们对跨平台理解不够,但至少能看出原生平台对跨端技术的担忧,不少 Android 团队在推出 Kotlin Multiplatform ,希望能争夺更多市场。 另外,苹果商店的审核风险也是大家所担忧的,官方的公告原意是说应用程序的核心特性和功能必须包含在软件的二进制文件中,而不是通过类似 HTML5 的技术来实现动态更新,苹果要打压的是动态更新技术,考虑到 Flutter 的合规性,Google 主动把 Flutter 的 iOS 动态化能力去掉了,Flutter 最终打包生成的产物就是 IPA,Flutter 其实是完全符合规范的,甚至还有使用 Flutter 开发的应用还被 Apple 推荐过。相反,React Native、Weex、H5 等技术都是一种动态化解决方案,这正是苹果要管控的,目前苹果的态度更多的是不提倡,但也不保证不封杀。即便如此,苹果不希望原生开发生态被其他跨平台技术抢占,苹果也在不断推行 SwiftUI 框架,力图抵挡 Flutter 等跨平台技术对原生开发的蚕食。Flutter 未来要加强推进步伐,让更多的大型 App 通过 Flutter 技术得到收益,只有用户群体上来,未来的地位和话语权才会更高,就像现在小程序,原则上是不符合苹果的审核要求的,但各大型应用基本都上线了小程序功能,目前来看不至于说苹果把小程序直接干掉。 Flutter 并非跨平台终极之选 从 Hybrid App 到 React Native,再到 Flutter,跨平台技术层出不穷。目前来看,Flutter 是跨平台开发的最热门技术,但我并不认为 Flutter 就一定是跨平台开发的终极之选,它有着历史局限性,我只能说 Flutter 可能是当下最有潜力的跨平台技术。如果你对性能流畅度有高要求,或者有多个产品希望快速在多端试错迭代,我会推荐你尝试 Flutter。 未来一段时间,还应该是多套跨平台技术并存的时代, 目前 Flutter 也没有全面做到可以碾压其他跨平台技术,可根据团队以及业务特点来考虑更适合的方案。有一定客户端经验的同学入手 Flutter 会更快一些,如果团队在 React Native 上有很好落地,业务没有遇到性能等瓶颈,且团队缺少客户端能力,建议先做技术调研和沉淀,不要盲目追求新技术,只有当团队有能力且业务有需求的情况下,建议再考虑切换技术栈。 我们前面提到过,一直备受关注且神秘的 Fuchsia 系统在 UI 框架上使用的也是 Flutter。Fuchsia 是 Google 开发的下一代操作系统。Fuchsia 是采用全新模块化设计思想、跨平台框架技术的系统。它能支持快捷裁剪定制,更能适应未来的多元化设备,包含手机、平板、笔记本、路由器、智能设备、机器人等,Fuchsia 有可能成为一个全新的跨全平台的通用操作系统。 在现阶段,开始尝试探索和积累沉淀 Flutter 技术能力,并在业务上使用 Flutter 技术的应用,从战略上来将已经处于领先。选择 Flutter,正可谓是“进可攻退可守”,往前进一步,Flutter 应用未来可无缝迁移到 Fuchsia 系统,借用 Fuchsia 系统的能量扩展到更广泛的用户场景;退一步,Flutter 技术自身在 Android/iOS 平台的表现相比其他跨平台技术已经是很优秀。 最初选择 Flutter,不是因为它一定会成为未来终极之选,而是它有可能成为不一样的未来。 Flutter 展望:终将走向多端一体化 回顾整移动操作系统的演变历程,从塞班功能机到 Android/iOS 智能机,从小屏手机到全面屏、刘海屏、水滴屏。任何系统的演变最终体现在输入和输出两个环节,接收到输入信号后经过操作系统处理后输出信息给用户。从按键式交互到触屏式交互,伴随着塞班系统到 Android 系统的转变,未来的交互方式一定会更加生物智能化,当下的触屏交互可以理解成人类的触觉输入方式,未来将朝着人们更常见的听觉(语音)输入和视觉(身体姿势、表情等)输入,甚至嗅觉(气味变化)输入,这些都会伴随着新的操作系统而诞生。屏幕从小尺寸到大尺寸,并没有引发操作系统变革,因为技术创新是非连续性,非连续性才会引发第二曲线,诞生新技术。从 1960 年大型机,到 1990 年个人笔记本,再到现在的智能手机,设备本身越来越小。未来的设备如果发展非连续变革,可能不再需要实体硬件,随处可输出,一张白纸、一面墙,到那时操作系统的 UI 架构必然会有全新的变化。 随着科技的发展,5G 时代的到来,人工智能的日趋成熟,端到底会有哪些变化?是否会出现新的操作系统?系统的 UI 架构是否会出现新的变革?Android/iOS 平台是否能与之并存?搭载 Flutter UI 框架的 Fuchsia 系统能否在 IOT 领域以及新的交互方式大放异彩,再领风骚?是否有万物互联互通的超级平台出现? 技术在不断演变中螺旋前进,平台自身也随之演进,未来 Flutter 会朝着多端一体化的方向发展,能支持更多的端(包括平板、笔记本、智能设备等)。作为一套跨平台的 UI 框架,Flutter 采用自渲染的技术方案,是一个上限很高的跨平台技术,但 Flutter 更重要的是需要提升工程化能力以及生态圈的建设,才能吸引更多的开发者加入。 加入我们 欢迎更多小伙伴加入字节跳动移动平台部,探索和深耕移动端技术,团队技术氛围浓厚,和我们开创可能成为不一样的未来,Android/iOS/Flutter等在北上深杭招聘各级别岗位,可简历发送至yuanhuihui@bytedance.com, 详细内推岗位见 http://gityuan.com/job。
一、概述 1.1 Timeline事件总览 C++引擎层层采用的是采用的是Embedder Stream; Dart应用层采用的是Dart Stream; DartVM采用的API Stream; 1.2 C++层Timeline用法 1.2.1 C++同步事件 #include "flutter/fml/trace_event.h" #define TRACE_EVENT0(category_group, name) #define TRACE_EVENT1(category_group, name, arg1_name, arg1_val) #define TRACE_EVENT2(category_group, name, arg1_name, arg1_val, arg2_name, arg2_val) #define FML_TRACE_EVENT(category_group, name, ...) fml::tracing::TraceEvent0(category_group, name); fml::tracing::TraceEventEnd(name); //示例: TRACE_EVENT0("flutter", "PipelineConsume"); TRACE_EVENT2("flutter", "Framework Workload", "mode", "basic", "frame", FrameParity()); 1.2.2 C++异步事件 #include "flutter/fml/trace_event.h" #define TRACE_EVENT_ASYNC_BEGIN0(category_group, name, id) #define TRACE_EVENT_ASYNC_END0(category_group, name, id) #define TRACE_EVENT_ASYNC_BEGIN1(category_group, name, id, arg1_name, arg1_val) #define TRACE_EVENT_ASYNC_END1(category_group, name, id, arg1_name, arg1_val) void TraceEventAsyncComplete(TraceArg category_group, TraceArg name, TimePoint begin, TimePoint end) //示例: TRACE_EVENT_ASYNC_BEGIN0("flutter", "Frame Request Pending", frame_number); TRACE_EVENT_ASYNC_END0("flutter", "Frame Request Pending", frame_number_++); 另外,这里还有一种比较特别的异步事件,事件的开始和结束都是可以手动指定的,TraceEventAsyncComplete 等于TRACE_EVENT_ASYNC_BEGIN0 + TRACE_EVENT_ASYNC_END0, 如下所示: void TraceEventAsyncComplete(TraceArg category_group, TraceArg name, TimePoint begin, TimePoint end); 1.2.3 C++事件流 #include "flutter/fml/trace_event.h" #define TRACE_FLOW_BEGIN(category, name, id) #define TRACE_FLOW_STEP(category, name, id) #define TRACE_FLOW_END(category, name, id) //示例: TRACE_FLOW_BEGIN("flutter", "PipelineItem", trace_id_) TRACE_FLOW_STEP("flutter", "PipelineItem", trace_id_) TRACE_FLOW_END("flutter", "PipelineItem", trace_id_) 1.2.4 DartVM事件 #define API_TIMELINE_DURATION(thread) #define API_TIMELINE_BEGIN_END(thread) // 示例: #define T (thread()) API_TIMELINE_DURATION(T); API_TIMELINE_BEGIN_END(T); 1.3 dart层Timeline用法 1.3.1 dart同步事件 import 'dart:developer'; Timeline.startSync(String name, {Map arguments, Flow flow}); Timeline.finishSync(); //示例: Timeline.startSync('Warm-up frame'); //静态方法 Timeline.finishSync(); 1.3.2 dart异步事件 import 'dart:developer'; TimelineTask.start(String name, {Map arguments}); TimelineTask.finish(); //示例: final TimelineTask timelineTask = TimelineTask(); //普通方法,需要实例化 timelineTask.start('Warm-up shader'); timelineTask.finish(); 1.3.3 dart事件流 Timeline.timeSync('flow_test', () { doSomething(); }, flow: flow); Timeline.timeSync('flow_test', () { doSomething(); }, flow: Flow.step(flow.id)); Timeline.timeSync('flow_test', () { doSomething(); }, flow: Flow.end(flow.id)); 1.4 TimelineEventRecorder总览 TimelineEventRingRecorder默认大小为32KB,也就是说该Recorder共有512个TimelineEventBlock(事件块),每个TimelineEventBlock有64个TimelineEvent(事件)。 1)TimelineEventRecorder:主要还有以下四种:ring, endless, startup, systrace TimelineEventRingRecorder:这是默认的记录器,其父类TimelineEventFixedBufferRecorder有固定缓存区, capacity_: 记录当前缓存区可记录的事件总数,默认值为32KB个; num_blocks_: 记录事件块的数量,默认值为512个,其中每个事件块能记录64个事件; TimelineEventEndlessRecorder:用于记录无上限的trace TimelineEventStartupRecorder:用于记录有限缓存,且记录满则不再记录trace TimelineEventSystraceRecorder:systrace_fd_记录的是/sys/kernel/debug/tracing/trace_marker的文件描述符; 2)TimelineEventBlock length_:记录该事件块已记录的事件个数,每一次StartEvent()则执行加1操作,上限为64; block_index_:记录当前事件块的索引ID,用于无限缓存大小的记录器; 另外关于时间计数,以Android为例,此处调用的是clock_gettime()系统方法,精确到纳秒,这里有CLOCK_MONOTONIC和CLOCK_THREAD_CPUTIME_ID两种不同的参数,Timeline最终记录的事件事件信息单位是微秒。 _start:采用参数CLOCK_MONOTONIC,记录从系统启动开始的计时时间点; _startCpu: 采用参数CLOCK_THREAD_CPUTIME_ID,记录当前线程执行代码所花费的CPU时间; 二、c++层Timeline 所有的这些最终都调用Dart_TimelineEvent()方法。 2.1 事件类型 2.1.1 同步事件 [-> flutter/fml/trace_event.cc] #define TRACE_EVENT0(category_group, name) \ ::fml::tracing::TraceEvent0(category_group, name); \ //事件开始 __FML__AUTO_TRACE_END(name) #define __FML__AUTO_TRACE_END(name) \ ::fml::tracing::ScopedInstantEnd __FML__TOKEN_CAT__2(__trace_end_, __LINE__)(name); class ScopedInstantEnd { public: ScopedInstantEnd(const char* str) : label_(str) {} ~ScopedInstantEnd() { TraceEventEnd(label_); } //事件结束 private: const char* label_; }; void TraceEvent0(TraceArg category_group, TraceArg name) { Dart_TimelineEvent(DCHECK_LITERAL(name), Dart_TimelineGetMicros(), 0, Dart_Timeline_Event_Begin, 0, nullptr, nullptr); } void TraceEventEnd(TraceArg name) { Dart_TimelineEvent(DCHECK_LITERAL(name), Dart_TimelineGetMicros(), 0, Dart_Timeline_Event_End, 0, nullptr, nullptr); } 2.1.2 异步事件 [-> flutter/fml/trace_event.cc] void TraceEventAsyncBegin0(TraceArg category_group, TraceArg name, TraceIDArg id) { Dart_TimelineEvent(DCHECK_LITERAL(name), Dart_TimelineGetMicros(), id, Dart_Timeline_Event_Async_Begin, 0, nullptr, nullptr); } void TRACE_EVENT_ASYNC_END0(TraceArg category_group, TraceArg name, TraceIDArg id) { Dart_TimelineEvent(DCHECK_LITERAL(name), Dart_TimelineGetMicros(), id, Dart_Timeline_Event_Async_End, 0, nullptr, nullptr); } void TraceEventAsyncComplete(TraceArg category_group, TraceArg name, TimePoint begin, TimePoint end) { auto identifier = TraceNonce(); if (begin > end) { std::swap(begin, end); } Dart_TimelineEvent(DCHECK_LITERAL(name), begin.ToEpochDelta().ToMicroseconds(), identifier, Dart_Timeline_Event_Async_Begin, 0, nullptr, nullptr); Dart_TimelineEvent(DCHECK_LITERAL(name), begin.ToEpochDelta().ToMicroseconds(), identifier, Dart_Timeline_Event_Async_End, 0, nullptr, nullptr); } 2.1.3 流事件 [-> flutter/fml/trace_event.cc] void TraceEventFlowBegin0(TraceArg category_group, TraceArg name, TraceIDArg id) { Dart_TimelineEvent(DCHECK_LITERAL(name), Dart_TimelineGetMicros(), id, Dart_Timeline_Event_Flow_Begin, 0, nullptr, nullptr); } void TraceEventFlowStep0(TraceArg category_group, TraceArg name, TraceIDArg id) { Dart_TimelineEvent(DCHECK_LITERAL(name), Dart_TimelineGetMicros(), id, Dart_Timeline_Event_Flow_Step, 0, nullptr, nullptr); } void TraceEventFlowEnd0(TraceArg category_group, TraceArg name, TraceIDArg id) { Dart_TimelineEvent(DCHECK_LITERAL(name), Dart_TimelineGetMicros(), id, Dart_Timeline_Event_Flow_End, 0, nullptr, nullptr); } 可见,所有这些事件最终都是调用Dart_TimelineEvent,不同的主要在事件类型: Dart_Timeline_Event_Begin:同步事件开始 Dart_Timeline_Event_End:同步事件结束 Dart_Timeline_Event_Async_Begin:同步事件开始 Dart_Timeline_Event_Async_End:同步事件结束 Dart_Timeline_Event_Flow_Begin:流事件开始 时间戳的获取除了TraceEventAsyncComplete()是直接传递的时间参数,其他都是通过Dart_TimelineGetMicros()命令获取执行该命令当下的时间戳,单位是微秒。 Dart_TimelineGetMicros DART_EXPORT int64_t Dart_TimelineGetMicros() { return OS::GetCurrentMonotonicMicros(); } //以Android为例 int64_t OS::GetCurrentMonotonicMicros() { int64_t ticks = GetCurrentMonotonicTicks(); return ticks / kNanosecondsPerMicrosecond; } int64_t OS::GetCurrentMonotonicTicks() { struct timespec ts; if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) { return 0; } int64_t result = ts.tv_sec; result *= kNanosecondsPerSecond; result += ts.tv_nsec; return result; } 通过clock_gettime系统调用获取CLOCK_MONOTONIC类型的时间,也就是系统从启动到现在的时间戳; 2.2 Dart_TimelineEvent [-> third_party/dart/runtime/vm/dart_api_impl.cc] DART_EXPORT void Dart_TimelineEvent(const char* label, int64_t timestamp0, int64_t timestamp1_or_async_id, Dart_Timeline_Event_Type type, intptr_t argument_count, const char** argument_names, const char** argument_values) { #if defined(SUPPORT_TIMELINE) //采用的是Embedder Stream TimelineStream* stream = Timeline::GetEmbedderStream(); //[见小节2.3.1] TimelineEvent* event = stream->StartEvent(); switch (type) { case Dart_Timeline_Event_Begin: event->Begin(label, timestamp0); //[见小节2.3.3] break; case Dart_Timeline_Event_End: event->End(label, timestamp0); break; case Dart_Timeline_Event_Instant: event->Instant(label, timestamp0); break; case Dart_Timeline_Event_Duration: event->Duration(label, timestamp0, timestamp1_or_async_id); break; case Dart_Timeline_Event_Async_Begin: event->AsyncBegin(label, timestamp1_or_async_id, timestamp0); break; case Dart_Timeline_Event_Async_End: event->AsyncEnd(label, timestamp1_or_async_id, timestamp0); break; case Dart_Timeline_Event_Async_Instant: event->AsyncInstant(label, timestamp1_or_async_id, timestamp0); break; case Dart_Timeline_Event_Counter: event->Counter(label, timestamp0); break; case Dart_Timeline_Event_Flow_Begin: event->FlowBegin(label, timestamp1_or_async_id, timestamp0); break; case Dart_Timeline_Event_Flow_Step: event->FlowStep(label, timestamp1_or_async_id, timestamp0); break; case Dart_Timeline_Event_Flow_End: event->FlowEnd(label, timestamp1_or_async_id, timestamp0); break; default: FATAL("Unknown Dart_Timeline_Event_Type"); } event->SetNumArguments(argument_count); for (intptr_t i = 0; i CopyArgument(i, argument_names[i], argument_values[i]); } // [见小节2.3.4] event->Complete(); #endif } 先以目前timeline的默认记录器TimelineEventRingRecorder来展开说明。 2.3 ring类型记录器 2.3.1 StartEvent [-> third_party/dart/runtime/vm/timeline.cc] TimelineEvent* TimelineEventFixedBufferRecorder::StartEvent() { return ThreadBlockStartEvent(); //【见下方】 } TimelineEvent* TimelineEventRecorder::ThreadBlockStartEvent() { OSThread* thread = OSThread::Current(); Mutex* thread_block_lock = thread->timeline_block_lock(); thread_block_lock->Lock(); //这个锁会一直持有,直到调用CompleteEvent() TimelineEventBlock* thread_block = thread->timeline_block(); if ((thread_block != NULL) && thread_block->IsFull()) { MutexLocker ml(&lock_); //加锁,保证每次只有一个线程申请新的事件块 thread_block->Finish(); //该事件块已满【见小节2.3.5】 thread_block = GetNewBlockLocked(); //分配新的事件块 thread->set_timeline_block(thread_block); } else if (thread_block == NULL) { MutexLocker ml(&lock_); thread_block = GetNewBlockLocked(); //没有事件块,则创建事件块 thread->set_timeline_block(thread_block); } if (thread_block != NULL) { //持锁状态退出该函数 见下方】 TimelineEvent* event = thread_block->StartEvent(); return event; } thread_block_lock->Unlock(); //没有任何事件,则释放锁 return NULL; } TimelineEvent* TimelineEventBlock::StartEvent() { return &events_[length_++]; } 说明: 如果当前线程中的thread_block为空,则创建新的事件块,并将当前线程id记录到该事件块,同时将该事件块再记录其成员变量timeline_block_事件块; 如果当前线程中的thread_block已满,则先将该事件块finish,再创建新的事件块; 从当前线程的事件块中分配一个可用的TimelineEvent事件; 2.3.2 GetNewBlockLocked TimelineEventBlock* TimelineEventRingRecorder::GetNewBlockLocked() { if (block_cursor_ == num_blocks_) { block_cursor_ = 0; } TimelineEventBlock* block = &blocks_[block_cursor_++]; block->Reset(); //事件重置 block->Open(); // [见下文] return block; } void TimelineEventBlock::Open() { OSThread* os_thread = OSThread::Current(); //将当前线程id记录到该事件块中的thread_id_ thread_id_ = os_thread->trace_id(); in_use_ = true; } OSThread对象里面有一个TimelineEventBlock指针,记录着当前正在操作的事件块。事件块里面有一个events_,记录着TimelineEvent数组,大小为kBlockSize=64。 2.3.3 TimelineEvent::Begin void Begin(const char* label, int64_t micros = OS::GetCurrentMonotonicMicros(), int64_t thread_micros = OS::GetCurrentThreadCPUMicros()); void AsyncBegin(const char* label, int64_t async_id, int64_t micros = OS::GetCurrentMonotonicMicros()); 事件定义过程会设置默认值,同步与异步的区别是异步事件会记录async_id,同步事件会记录当前线程的cpu运行时间戳。 void TimelineEvent::Begin(const char* label, int64_t micros, int64_t thread_micros) { Init(kBegin, label); set_timestamp0(micros); //系统启动后运行的时间戳 set_thread_timestamp0(thread_micros); //该线程CPU运行的时间戳 } void TimelineEvent::End(const char* label, int64_t micros, int64_t thread_micros) { Init(kEnd, label); set_timestamp0(micros); //系统启动后运行的时间戳 set_thread_timestamp0(thread_micros);//该线程CPU运行的时间戳 } void TimelineEvent::AsyncBegin(const char* label, int64_t async_id, int64_t micros) { Init(kAsyncBegin, label); set_timestamp0(micros); set_timestamp1(async_id); //async_id记录到timestamp1_ } void TimelineEvent::AsyncEnd(const char* label, int64_t async_id, int64_t micros) { Init(kAsyncEnd, label); set_timestamp0(micros); set_timestamp1(async_id); //async_id记录到timestamp1_ } void TimelineEvent::Init(EventType event_type, const char* label) { state_ = 0; timestamp0_ = 0; timestamp1_ = 0; thread_timestamp0_ = -1; thread_timestamp1_ = -1; OSThread* os_thread = OSThread::Current(); thread_ = os_thread->trace_id(); //记录线程id Isolate* isolate = Isolate::Current(); if (isolate != NULL) { isolate_id_ = isolate->main_port(); //记录isolate端口号 } else { isolate_id_ = ILLEGAL_PORT; } label_ = label; //事件标签名 arguments_.Free(); set_event_type(event_type); //事件类型,比如kBegin,kEnd set_pre_serialized_args(false); set_owns_label(false); } 2.3.4 Complete void TimelineEvent::Complete() { TimelineEventRecorder* recorder = Timeline::recorder(); if (recorder != NULL) { recorder->CompleteEvent(this); //[见下文] } } void TimelineEventFixedBufferRecorder::CompleteEvent(TimelineEvent* event) { ThreadBlockCompleteEvent(event); //[见下文] } void TimelineEventRecorder::ThreadBlockCompleteEvent(TimelineEvent* event) { OSThread* thread = OSThread::Current(); Mutex* thread_block_lock = thread->timeline_block_lock(); thread_block_lock->Unlock(); //释放同步锁 } 当OSThread的thread_block写满,则需要执行Finish(),将该事件块的数据发送给ServiceIsolate来处理,如下所示。 2.3.5 TimelineEventBlock::Finish void TimelineEventBlock::Finish() { in_use_ = false; #ifndef PRODUCT if (Service::timeline_stream.enabled()) { ServiceEvent service_event(NULL, ServiceEvent::kTimelineEvents); service_event.set_timeline_event_block(this); Service::HandleEvent(&service_event); //[见下文] } #endif } 2.3.6 Service::HandleEvent [-> third_party/dart/runtime/vm/service.cc] void Service::HandleEvent(ServiceEvent* event) { if (event->stream_info() != NULL && !event->stream_info()->enabled()) { return; //当没有地方监听事件流,则忽略 } if (!ServiceIsolate::IsRunning()) { return; //当ServiceIsolate没有运行,则停止 } JSONStream js; const char* stream_id = event->stream_id(); { JSONObject jsobj(&js); jsobj.AddProperty("jsonrpc", "2.0"); jsobj.AddProperty("method", "streamNotify"); JSONObject params(&jsobj, "params"); params.AddProperty("streamId", stream_id); params.AddProperty("event", event); } //此处isoalte为空,[见小节] PostEvent(event->isolate(), stream_id, event->KindAsCString(), &js); if (event->stream_info() != nullptr && event->stream_info()->consumer() != nullptr) { auto length = js.buffer()->length(); event->stream_info()->consumer()( reinterpret_cast(js.buffer()->buf()), length); } } 可通过Dart_SetNativeServiceStreamCallback()来设置Dart_NativeStreamConsumer回调方法。 2.3.7 Service::PostEvent [-> third_party/dart/runtime/vm/service.cc] void Service::PostEvent(Isolate* isolate, const char* stream_id, const char* kind, JSONStream* event) { //消息格式[, ] Dart_CObject list_cobj; Dart_CObject* list_values[2]; list_cobj.type = Dart_CObject_kArray; list_cobj.value.as_array.length = 2; list_cobj.value.as_array.values = list_values; Dart_CObject stream_id_cobj; stream_id_cobj.type = Dart_CObject_kString; stream_id_cobj.value.as_string = const_cast(stream_id); //stream_id list_values[0] = &stream_id_cobj; Dart_CObject json_cobj; json_cobj.type = Dart_CObject_kString; json_cobj.value.as_string = const_cast(event->ToCString()); //event list_values[1] = &json_cobj; auto thread = Thread::Current(); if (thread != nullptr) { TransitionVMToNative transition(thread); //向service isolate发送事件 Dart_PostCObject(ServiceIsolate::Port(), &list_cobj); } else { Dart_PostCObject(ServiceIsolate::Port(), &list_cobj); } } 2.3.8 Dart_PostCObject DART_EXPORT bool Dart_PostCObject(Dart_Port port_id, Dart_CObject* message) { return PostCObjectHelper(port_id, message); } static bool PostCObjectHelper(Dart_Port port_id, Dart_CObject* message) { ApiMessageWriter writer; Message* msg = writer.WriteCMessage(message, port_id, Message::kNormalPriority); if (msg == NULL) { return false; } return PortMap::PostMessage(msg); } 最终会把数据传递给ServiceIsolate来进行处理。 2.4 systrace类型记录器 2.4.1 StartEvent [-> third_party/dart/runtime/vm/timeline.cc] TimelineEvent* TimelineEventPlatformRecorder::StartEvent() { TimelineEvent* event = new TimelineEvent(); return event; } 2.4.2 TimelineEvent初始化 [-> third_party/dart/runtime/vm/timeline.cc] TimelineEvent::TimelineEvent() : timestamp0_(0), timestamp1_(0), thread_timestamp0_(-1), thread_timestamp1_(-1), state_(0), label_(NULL), stream_(NULL), thread_(OSThread::kInvalidThreadId), isolate_id_(ILLEGAL_PORT) {} 2.4.3 TimelineEvent::Begin [-> third_party/dart/runtime/vm/timeline.cc] void TimelineEvent::Begin(const char* label, int64_t micros, int64_t thread_micros) { Init(kBegin, label); set_timestamp0(micros); //系统启动后运行的时间戳 set_thread_timestamp0(thread_micros); //该线程CPU运行的时间戳 } 2.4.4 Complete [-> third_party/dart/runtime/vm/timeline.cc] void TimelineEvent::Complete() { TimelineEventRecorder* recorder = Timeline::recorder(); if (recorder != NULL) { recorder->CompleteEvent(this); //[见下文] } } void TimelineEventPlatformRecorder::CompleteEvent(TimelineEvent* event) { OnEvent(event); delete event; } 2.4.5 OnEvent [-> third_party/dart/runtime/vm/timeline_android.cc] void TimelineEventSystraceRecorder::OnEvent(TimelineEvent* event) { const intptr_t kBufferLength = 1024; char buffer[kBufferLength]; //[小节2.4.6] const intptr_t event_length = PrintSystrace(event, &buffer[0], kBufferLength); if (event_length > 0) { ssize_t result; do { result = write(systrace_fd_, buffer, event_length); } while ((result == -1L) && (errno == EINTR)); } } 此处的systrace_fd_是指/sys/kernel/debug/tracing/trace_marker,也就是ftrace的buffer。 其中PrintSystrace过程如下所示: 2.4.6 PrintSystrace intptr_t TimelineEventSystraceRecorder::PrintSystrace(TimelineEvent* event, char* buffer, intptr_t buffer_size) { buffer[0] = '\0'; intptr_t length = 0; int64_t pid = OS::ProcessId(); switch (event->event_type()) { case TimelineEvent::kBegin: { length = Utils::SNPrint(buffer, buffer_size, "B|%" Pd64 "|%s", pid, event->label()); break; } case TimelineEvent::kEnd: { length = Utils::SNPrint(buffer, buffer_size, "E"); break; } case TimelineEvent::kCounter: { if (event->arguments_length() > 0) { length = Utils::SNPrint(buffer, buffer_size, "C|%" Pd64 "|%s|%s", pid, event->label(), event->arguments()[0].value); } break; } default: break; } return length; } 可见kBegin、kEnd、kCounter记录的信息如下所示: B|pid|name E C|pid|name|count 2.5 小结 每一个Timeline时间的执行流程: 通过StartEvent来获取TimelineEvent; 根据不同事件类型来填充相应event; 最后执行Complete; ring和endless、startup记录器实现方式非常相近,都需要ServiceIsolate才能工作,其核心区别是GetNewBlockLocked()中buffer分配的方式。ring和startup都是采用的是固定大小,ring是在buffer已满的情况下循环写;startup则是写满buffer则不再写入;endless采用的是无上限的buffer空间。 systrace实现方式则跟前三者完全不同,systrace依赖的是linux底层的ftrace,无需额外开辟buffer。 三、dart层Timeline 3.1 同步事件类型 3.1.1 Timeline.startSync [-> third_party/dart/sdk/lib/developer/timeline.dart] class Timeline { static final List _stack = new List(); static void startSync(String name, {Map arguments, Flow flow}) { if (!_hasTimeline) return; if (!_isDartStreamEnabled()) { _stack.add(null); return; } //创建同步块 var block = new _SyncBlock._(name, _getTraceClock(), _getThreadCpuClock()); if (arguments != null) { block._arguments = arguments; } if (flow != null) { block.flow = flow; } _stack.add(block); } } 该过程如果出现_stack列表为空,则会抛出异常,说明调用startSync/finishSync不是成对出现; 调用finishSync()过程,从列表弹出最近加入的一个数据然后调用其finish()方法; 每一条timeline都是通过创建_SyncBlock对象来记录,并保存到_stack列表。其中_hasTimeline是通过判断dart.developer.timeline值来决定,默认为true。 关于时间的两个方法如下所示: DEFINE_NATIVE_ENTRY(Timeline_getTraceClock, 0, 0) { return Integer::New(OS::GetCurrentMonotonicMicros(), Heap::kNew); } DEFINE_NATIVE_ENTRY(Timeline_getThreadCpuClock, 0, 0) { return Integer::New(OS::GetCurrentThreadCPUMicros(), Heap::kNew); } 3.1.2 _SyncBlock初始化 class _SyncBlock { final String category = 'Dart'; final String name; Map _arguments; final int _start; //启动运行时间戳 final int _startCpu; //该线程CPU运行时间戳 Flow _flow; _SyncBlock._(this.name, this._start, this._startCpu); } 3.1.3 Timeline.finishSync [-> third_party/dart/sdk/lib/developer/timeline.dart] class Timeline { static void finishSync() { if (!_hasTimeline) { return; } if (_stack.length == 0) { throw new StateError('Uneven calls to startSync and finishSync'); } var block = _stack.removeLast(); block.finish(); //[见小节] } } 3.1.4 _SyncBlock.finish [-> third_party/dart/sdk/lib/developer/timeline.dart] class _SyncBlock { void finish() { // [见小节] _reportCompleteEvent( _start, _startCpu, category, name, _argumentsAsJson(_arguments)); if (_flow != null) { _reportFlowEvent(_start, _startCpu, category, name, _flow._type, _flow.id, _argumentsAsJson(null)); } } } 3.1.5 _reportCompleteEvent [-> third_party/dart/runtime/lib/timeline.cc] DEFINE_NATIVE_ENTRY(Timeline_reportCompleteEvent, 0, 5) { #if defined(SUPPORT_TIMELINE) GET_NON_NULL_NATIVE_ARGUMENT(Integer, start, arguments->NativeArgAt(0)); GET_NON_NULL_NATIVE_ARGUMENT(Integer, start_cpu, arguments->NativeArgAt(1)); GET_NON_NULL_NATIVE_ARGUMENT(String, category, arguments->NativeArgAt(2)); GET_NON_NULL_NATIVE_ARGUMENT(String, name, arguments->NativeArgAt(3)); GET_NON_NULL_NATIVE_ARGUMENT(String, args, arguments->NativeArgAt(4)); TimelineEventRecorder* recorder = Timeline::recorder(); //获取TimelineEvent对象 TimelineEvent* event = Timeline::GetDartStream()->StartEvent(); //见小节 DartTimelineEventHelpers::ReportCompleteEvent( thread, event, start.AsInt64Value(), start_cpu.AsInt64Value(), category.ToCString(), name.ToMallocCString(), args.ToMallocCString()); #endif return Object::null(); } 3.1.6 ReportCompleteEvent [-> third_party/dart/runtime/vm/timeline.cc] void DartTimelineEventHelpers::ReportCompleteEvent(Thread* thread, TimelineEvent* event, int64_t start, int64_t start_cpu, const char* category, char* name, char* args) { const int64_t end = OS::GetCurrentMonotonicMicros(); const int64_t end_cpu = OS::GetCurrentThreadCPUMicros(); //将四个时间戳记录到TimelineEvent event->Duration(name, start, end, start_cpu, end_cpu); event->set_owns_label(true); // 见小节 event->CompleteWithPreSerializedArgs(args); } void TimelineEvent::Duration(const char* label, int64_t start_micros, int64_t end_micros, int64_t thread_start_micros, int64_t thread_end_micros) { Init(kDuration, label); set_timestamp0(start_micros); set_timestamp1(end_micros); set_thread_timestamp0(thread_start_micros); set_thread_timestamp1(thread_end_micros); } 将名字记录到TimelineEvent的成员变量label_,将四个时间戳记录到TimelineEvent的相应成员变量。 3.1.7 CompleteWithPreSerializedArgs [-> third_party/dart/runtime/vm/timeline.cc] void TimelineEvent::CompleteWithPreSerializedArgs(char* args_json) { set_pre_serialized_args(true); SetNumArguments(1); SetArgument(0, "Dart Arguments", args_json); Complete(); } 接着执行Complete(),根据不同的recorder回到了前面已介绍[小节2.3.4]/[小节2.4.4]过程。 3.2 异步事件类型 3.2.1 TimelineTask.start class TimelineTask { final int _taskId; final List _stack = []; //需要先初始化 TimelineTask() : _taskId = _getNextAsyncId() {} void start(String name, {Map arguments}) { if (!_hasTimeline) return; var block = new _AsyncBlock._(name, _taskId); if (arguments != null) { block._arguments = arguments; } _stack.add(block); block._start(); //[见小节] } } 3.2.2 _AsyncBlock._start class _AsyncBlock { final String category = 'Dart'; final String name; final int _taskId; Map _arguments; void _start() { _reportTaskEvent( _getTraceClock(), _taskId, 'b', category, name, _argumentsAsJson(null)); } } _AsyncBlock相比_SyncBlock少了,少了两个时间相关的成员变量,多了一个记录taskid的成员变量 3.2.3 TimelineTask.finish class TimelineTask { void finish() { if (!_hasTimeline) { return; } var block = _stack.removeLast(); block._finish(); //[见小节] } } 3.2.4 _AsyncBlock._finish class TimelineTask { void _finish() { _reportTaskEvent(_getTraceClock(), _taskId, 'e', category, name, _argumentsAsJson(_arguments)); } } 3.2.5 _reportTaskEvent DEFINE_NATIVE_ENTRY(Timeline_reportTaskEvent, 0, 6) { #if defined(SUPPORT_TIMELINE) GET_NON_NULL_NATIVE_ARGUMENT(Integer, start, arguments->NativeArgAt(0)); GET_NON_NULL_NATIVE_ARGUMENT(Integer, id, arguments->NativeArgAt(1)); GET_NON_NULL_NATIVE_ARGUMENT(String, phase, arguments->NativeArgAt(2)); GET_NON_NULL_NATIVE_ARGUMENT(String, category, arguments->NativeArgAt(3)); GET_NON_NULL_NATIVE_ARGUMENT(String, name, arguments->NativeArgAt(4)); GET_NON_NULL_NATIVE_ARGUMENT(String, args, arguments->NativeArgAt(5)); TimelineEventRecorder* recorder = Timeline::recorder(); //获取TimelineEvent对象 TimelineEvent* event = Timeline::GetDartStream()->StartEvent(); //见小节 DartTimelineEventHelpers::ReportTaskEvent( thread, event, start.AsInt64Value(), id.AsInt64Value(), phase.ToCString(), category.ToCString(), name.ToMallocCString(), args.ToMallocCString()); #endif // SUPPORT_TIMELINE return Object::null(); } 3.2.6 ReportTaskEvent void DartTimelineEventHelpers::ReportTaskEvent(Thread* thread, TimelineEvent* event, int64_t start, int64_t id, const char* phase, const char* category, char* name, char* args) { switch (phase[0]) { case 'n': event->AsyncInstant(name, id, start); break; case 'b': event->AsyncBegin(name, id, start); break; case 'e': event->AsyncEnd(name, id, start); break; default: UNREACHABLE(); } event->set_owns_label(true); event->CompleteWithPreSerializedArgs(args); } 3.2.7 CompleteWithPreSerializedArgs void TimelineEvent::CompleteWithPreSerializedArgs(char* args_json) { set_pre_serialized_args(true); SetNumArguments(1); SetArgument(0, "Dart Arguments", args_json); Complete(); } 接着执行Complete(),根据不同的recorder回到了前面已介绍[小节2.3.4]/[小节2.4.4]过程。 四、dart虚拟机Timeline 这两个宏目前主要用于dart_api_impl.cc文件 #define API_TIMELINE_DURATION(thread) \ TimelineDurationScope api_tds(thread, Timeline::GetAPIStream(), CURRENT_FUNC) #define API_TIMELINE_BEGIN_END(thread) \ TimelineBeginEndScope api_tbes(thread, Timeline::GetAPIStream(), CURRENT_FUNC) 4.1 API_TIMELINE_DURATION 4.1.1 TimelineDurationScope初始化 TimelineDurationScope::TimelineDurationScope(Thread* thread, TimelineStream* stream, const char* label) : TimelineEventScope(thread, stream, label) { if (!enabled()) { return; } timestamp_ = OS::GetCurrentMonotonicMicros(); thread_timestamp_ = OS::GetCurrentThreadCPUMicros(); } 该timeline事件的标签名为CURRENT_FUNC,也就是函数名; 4.1.2 TimelineDurationScope析构 TimelineDurationScope::~TimelineDurationScope() { if (!ShouldEmitEvent()) { return; } TimelineEvent* event = stream()->StartEvent(); if (event == NULL) { return; } //创建事件 event->Duration(label(), timestamp_, OS::GetCurrentMonotonicMicros(), thread_timestamp_, OS::GetCurrentThreadCPUMicros()); StealArguments(event); //事件完成 event->Complete(); } 4.2 API_TIMELINE_BEGIN_END 4.1.1 TimelineBeginEndScope TimelineBeginEndScope::TimelineBeginEndScope(Thread* thread, TimelineStream* stream, const char* label) : TimelineEventScope(thread, stream, label) { EmitBegin(); } TimelineBeginEndScope::~TimelineBeginEndScope() { EmitEnd(); } 该timeline事件的标签名为CURRENT_FUNC,也就是函数名 4.1.2 EmitBegin void TimelineBeginEndScope::EmitBegin() { if (!ShouldEmitEvent()) { return; } TimelineEvent* event = stream()->StartEvent(); if (event == NULL) { set_enabled(false); return; } event->Begin(label()); //事件开始 event->Complete(); } 4.1.3 EmitEnd void TimelineBeginEndScope::EmitEnd() { if (!ShouldEmitEvent()) { return; } TimelineEvent* event = stream()->StartEvent(); if (event == NULL) { set_enabled(false); return; } event->End(label()); //事件结束 StealArguments(event); event->Complete(); } 对于timeline来说功能是一致的,但对于systrace则不同,因为事件的方式不同,建议时候用API_TIMELINE_BEGIN_END,不推荐使用API_TIMELINE_DURATION。 五、总结 TimelineEventRecorder:主要还有以下四种:ring, endless, startup, systrace,本身timeline是能够转换为systrace的,但是在转换过程中有很多坑,需要去解决,下一篇文章再进一步讲解如何解决对systrace更友好的支持。 附录: flutter/fml/trace_event.cc third_party/dart/sdk/lib/developer/timeline.dart third_party/dart/runtime/lib/timeline.cc third_party/dart/runtime/vm/ - dart_api_impl.cc - timeline.cc - timeline_android.cc - service.cc
一、概述 在前面文章深入理解Dart虚拟机启动中,有讲到Dart虚拟机中有一个比较重要的isolate,创建的isolate名为”vm-service”,运行在独立的线程,也就是ServiceIsolate,这是用于系统调试相关功能的一个isolate,提供虚拟机相关服务, 比如hot reload,timeline等。这里先来看看ServiceIsolate的启动过程以及监听处理流程。 二、启动ServiceIsolate 在dart虚拟机启动过程,会执行Dart::Init()操作,该过程中初始化timeline以及在线程池中启动ServiceIsolate。 2.1 Dart::Init [-> third_party/dart/runtime/vm/dart.cc] char* Dart::Init(Dart_IsolateCreateCallback create, Dart_IsolateShutdownCallback shutdown, Dart_IsolateCleanupCallback cleanup, Dart_ThreadExitCallback thread_exit, ...) { ... #if defined(SUPPORT_TIMELINE) Timeline::Init(); #endif Isolate::SetCreateCallback(create); Isolate::SetShutdownCallback(shutdown); Isolate::SetCleanupCallback(cleanup); const bool is_dart2_aot_precompiler = FLAG_precompiled_mode && !kDartPrecompiledRuntime; if (!is_dart2_aot_precompiler && (FLAG_support_service || !kDartPrecompiledRuntime)) { ServiceIsolate::Run(); //[见小节] } ... } 启动ServiceIsolate的条件,需要满足以下两者之一: 当kDartPrecompiledRuntime = true,且FLAG_support_service = true; 当kDartPrecompiledRuntime = false,且FLAG_precompiled_mode = false; 再来看一看DartVM初始化过程 DartVM::DartVM(std::shared_ptr vm_data, std::shared_ptr isolate_name_server) { ... TRACE_EVENT0("flutter", "Dart_Initialize"); Dart_InitializeParams params = {}; params.create = reinterpret_cast( DartIsolate::DartIsolateCreateCallback); params.shutdown = reinterpret_cast( DartIsolate::DartIsolateShutdownCallback); params.cleanup = reinterpret_cast( DartIsolate::DartIsolateCleanupCallback); params.thread_exit = ThreadExitCallback; ... } 可见,ServiceIsolate的创建callback方法是指DartIsolate::DartIsolateCreateCallback(),后面会用到这个信息。 2.2 ServiceIsolate::Run [-> third_party/dart/runtime/vm/service_isolate.cc] void ServiceIsolate::Run() { { MonitorLocker ml(monitor_); state_ = kStarting; ml.NotifyAll(); } //将任务交给线程池中的worker线程来执行任务[见小节] bool task_started = Dart::thread_pool()->Run(new RunServiceTask()); } 将RunServiceTask任务交给线程池中的worker线程来执行任务,过程会创建创建名为“vm-service”的isolate。 2.3 RunServiceTask [-> third_party/dart/runtime/vm/service_isolate.cc] class RunServiceTask : public ThreadPool::Task { public: virtual void Run() { char* error = NULL; Isolate* isolate = NULL; Dart_IsolateCreateCallback create_callback = ServiceIsolate::create_callback(); Dart_IsolateFlags api_flags; Isolate::FlagsInitialize(&api_flags); //创建ServiceIsolate [见小节2.3] isolate = reinterpret_cast( create_callback(ServiceIsolate::kName, ServiceIsolate::kName, NULL, NULL, &api_flags, NULL, &error)); bool got_unwind; { StartIsolateScope start_scope(isolate); //[见小节2.4] got_unwind = RunMain(isolate); } ... isolate->message_handler()->Run(Dart::thread_pool(), NULL, ShutdownIsolate, reinterpret_cast(isolate)); } 此处的create_callback便是DartIsolate::DartIsolateCreateCallback,如下所示。 2.3.1 DartIsolateCreateCallback [-> flutter/runtime/dart_isolate.cc] Dart_Isolate DartIsolate::DartIsolateCreateCallback( const char* advisory_script_uri, const char* advisory_script_entrypoint, const char* package_root, const char* package_config, Dart_IsolateFlags* flags, std::shared_ptr* parent_embedder_isolate, char** error) { if (parent_embedder_isolate == nullptr && strcmp(advisory_script_uri, DART_VM_SERVICE_ISOLATE_NAME) == 0) { return DartCreateAndStartServiceIsolate(package_root,package_config, flags, error ); } ... } 此处DART_VM_SERVICE_ISOLATE_NAME就是”vm-service”。 Dart_Isolate DartIsolate::DartCreateAndStartServiceIsolate( const char* package_root, const char* package_config, Dart_IsolateFlags* flags, char** error) { auto vm_data = DartVMRef::GetVMData(); const auto& settings = vm_data->GetSettings(); if (!settings.enable_observatory) { return nullptr; } TaskRunners null_task_runners("io.flutter." DART_VM_SERVICE_ISOLATE_NAME, nullptr, nullptr, nullptr, nullptr); flags->load_vmservice_library = true; std::weak_ptr weak_service_isolate = DartIsolate::CreateRootIsolate( vm_data->GetSettings(), // settings vm_data->GetIsolateSnapshot(), // isolate snapshot vm_data->GetSharedSnapshot(), // shared snapshot null_task_runners, // task runners nullptr, // window {}, // snapshot delegate {}, // IO Manager DART_VM_SERVICE_ISOLATE_NAME, // script uri DART_VM_SERVICE_ISOLATE_NAME, // script entrypoint flags // flags ); tonic::DartState::Scope scope(service_isolate); //[见小节2.3.2] if (!DartServiceIsolate::Startup( settings.ipv6 ? "::1" : "127.0.0.1", // server IP address settings.observatory_port, // server observatory port tonic::DartState::HandleLibraryTag, // embedder library tag handler false, // disable websocket origin check settings.disable_service_auth_codes, // disable VM service auth codes error // error (out) )) { return nullptr; } ... return service_isolate->isolate(); } 可通过settings.enable_observatory来决定是否开启observatory的isolate; 启动ip为127.0.0.1的服务; 2.3.2 DartServiceIsolate::Startup [-> flutter/runtime/dart_service_isolate.cc] bool DartServiceIsolate::Startup(std::string server_ip, intptr_t server_port, Dart_LibraryTagHandler embedder_tag_handler, bool disable_origin_check, bool disable_service_auth_codes, char** error) { Dart_Isolate isolate = Dart_CurrentIsolate(); ... Dart_Handle uri = Dart_NewStringFromCString("dart:vmservice_io"); Dart_Handle library = Dart_LookupLibrary(uri); Dart_Handle result = Dart_SetRootLibrary(library); result = Dart_SetNativeResolver(library, GetNativeFunction, GetSymbol); Dart_ExitScope(); Dart_ExitIsolate(); //该过程会执行Isolate::Run()方法 Dart_IsolateMakeRunnable(isolate); Dart_EnterIsolate(isolate); Dart_EnterScope(); library = Dart_RootLibrary(); //设置HTTP server的ip地址,对于ipv4则为127.0.0.1 Dart_SetField(library, Dart_NewStringFromCString("_ip"), Dart_NewStringFromCString(server_ip.c_str())); //当指定端口号,则立即启动服务;如果没有指定,则找到第一个可用的端口号 bool auto_start = server_port >= 0; if (server_port third_party/dart/runtime/vm/service_isolate.cc] bool RunMain(Isolate* I) { Thread* T = Thread::Current(); StackZone zone(T); HANDLESCOPE(T); const Library& root_library = Library::Handle(Z, I->object_store()->root_library()); const String& entry_name = String::Handle(Z, String::New("main")); const Function& entry = Function::Handle( Z, root_library.LookupFunctionAllowPrivate(entry_name)); //找到并执行dart:vmservice_io库的main()方法 [见小节2.5] const Object& result = Object::Handle( Z, DartEntry::InvokeFunction(entry, Object::empty_array())); const ReceivePort& rp = ReceivePort::Cast(result); ServiceIsolate::SetLoadPort(rp.Id()); return false; } 2.5 vmservice_io.main [-> third_party/dart/runtime/bin/vmservice/vmservice_io.dart] main() { new VMService(); if (_autoStart) { _lazyServerBoot(); //[见小节2.5.1] server.startup(); //[见小节2.6] Timer.run(() {}); //用于执行所有的microtasks. } scriptLoadPort.handler = _processLoadRequest; _registerSignalHandlerTimer = new Timer(shortDelay, _registerSignalHandler); return scriptLoadPort; } 2.5.1 _lazyServerBoot [-> third_party/dart/runtime/bin/vmservice/vmservice_io.dart] _lazyServerBoot() { if (server != null) { return; } //[见小节2.5.2] var service = new VMService(); //[见小节2.5.4] server = new Server(service, _ip, _port, _originCheckDisabled, _authCodesDisabled); } 该过程创建VMService和Server对象 2.5.2 VMService初始化 [-> third_party/dart/sdk/lib/vmservice/vmservice.dart] final RawReceivePort isolateControlPort = new RawReceivePort(); class VMService extends MessageRouter { factory VMService() { if (VMService._instance == null) { VMService._instance = new VMService._internal(); //如下文 _onStart(); //通知虚拟机,服务正在运行 } return _instance; } VMService._internal() : eventPort = isolateControlPort { eventPort.handler = messageHandler; //设置消息处理handler } } 2.5.3 messageHandler [-> third_party/dart/sdk/lib/vmservice/vmservice.dart] void messageHandler(message) { if (message is List) { if (message.length == 2) { // 事件处理 _eventMessageHandler(message[0], new Response.from(message[1])); return; } if (message.length == 1) { _exit(); //vm service退出的消息 return; } if (message.length == 3) { final opcode = message[0]; if (opcode == Constants.METHOD_CALL_FROM_NATIVE) { _handleNativeRpcCall(message[1], message[2]); return; } else { assert((opcode == Constants.WEB_SERVER_CONTROL_MESSAGE_ID) || (opcode == Constants.SERVER_INFO_MESSAGE_ID)); _serverMessageHandler(message[0], message[1], message[2]); return; } } if (message.length == 4) { //关于isolate的创建和销毁的消息 _controlMessageHandler(message[0], message[1], message[2], message[3]); return; } } } 根据消息长度调用相应的Handler: 当长度等于1,则调用_exit来退出vm service; 当长度等于2,则调用_eventMessageHandler来处理事件; 当长度等于3,分为两种情况: 当消息opcode等于METHOD_CALL_FROM_NATIVE,则调用_handleNativeRpcCall来处理Native的RPC调用; 否则,则调用_serverMessageHandler来处理消息; 当长度等于4,则调用_controlMessageHandler来通知创建或销毁一个isolate; 2.5.4 Server初始化 [-> third_party/dart/runtime/bin/vmservice/server.dart] class Server { static const WEBSOCKET_PATH = '/ws'; static const ROOT_REDIRECT_PATH = '/index.html'; final VMService _service; final String _ip; final int _port; final bool _originCheckDisabled; final bool _authCodesDisabled; HttpServer _server; Server(this._service, this._ip, this._port, this._originCheckDisabled, bool authCodesDisabled) : _authCodesDisabled = (authCodesDisabled || Platform.isFuchsia); } 2.6 server.startup [-> third_party/dart/runtime/bin/vmservice/server.dart] Future startup() async { ... Future poll() async { try { var address; var addresses = await InternetAddress.lookup(_ip); for (var i = 0; i maxAttempts) { _notifyServerState(""); onServerAddressChange(null); return this; } await new Future.delayed(const Duration(seconds: 1)); } //进入监听状态 _server.listen(_requestHandler, cancelOnError: true); //这便是熟悉的那行,标志着服务启动成功 serverPrint('Observatory listening on $serverAddress'); //将服务地址通知到VmService,写入其成员变量server_uri_ _notifyServerState(serverAddress.toString()); //将服务地址通知到ServiceIsolate,写入其成员变量server_address_ onServerAddressChange('$serverAddress'); return this; } 服务进入监听状态,一旦收到请求,则会调用_requestHandler。 三、处理请求 Server._requestHandler client.onRequest vmservice.routeRequest vmservice._routeRequestImpl message.sendToVM message.sendRootServiceMessage (接下来进入C++) Service::HandleRootMessage Service::InvokeMethod 3.1 Server._requestHandler [-> third_party/dart/runtime/bin/vmservice/server.dart] Future _requestHandler(HttpRequest request) async { ... final String path = _checkAuthTokenAndGetPath(request.uri); //创建一个client对象,内有vmservice [见小节3.1.1] final client = new HttpRequestClient(request, _service); //创建message对象,[见小节3.1.3] final message = new Message.fromUri(client, Uri.parse(path)); // [见小节3.2] client.onRequest(message); } 3.1.1 HttpRequestClient初始化 [-> third_party/dart/runtime/bin/vmservice/server.dart] class HttpRequestClient extends Client { final HttpRequest request; HttpRequestClient(this.request, VMService service) : super(service, sendEvents: false); //见下文 } [-> third_party/dart/sdk/lib/vmservice/client.dart] abstract class Client { final VMService service; final bool sendEvents; Client(this.service, {bool sendEvents: true}) : this.sendEvents = sendEvents { service._addClient(this); //将当前的client添加到VMService } } 3.1.2 VMService._addClient [-> third_party/dart/sdk/lib/vmservice/vmservice.dart] class VMService extends MessageRouter { static const serviceNamespace = 's'; final NamedLookup clients = new NamedLookup(prologue: serviceNamespace); void _addClient(Client client) { clients.add(client); } } 3.1.3 Message.fromUri [-> third_party/dart/sdk/lib/vmservice/message.dart] Message.fromUri(this.client, Uri uri) : type = MessageType.Request, serial = '', method = _methodNameFromUri(uri) { //从uri中获取方法名 params.addAll(uri.queryParameters); } Message对象都有一个成员变量method 方法名method,对于fromUri是从分割后的第一部分 消息类型type有有3大类:Request, Notification, Response 3.2 client.onRequest [-> third_party/dart/sdk/lib/vmservice/client.dart] abstract class Client { final VMService service; void onRequest(Message message) { // 【见小节3.3/38】 service.routeRequest(service, message).then(post); } } 这里有两个过程: vmservice.routeRequest post 3.3 vmservice.routeRequest [-> third_party/dart/sdk/lib/vmservice/vmservice.dart] Future routeRequest(VMService _, Message message) async { return new Response.from(await _routeRequestImpl(message)); } Future _routeRequestImpl(Message message) async { try { if (message.completed) { return await message.response; } if (message.method == 'streamListen') { return await _streamListen(message); } if (message.method == 'streamCancel') { return await _streamCancel(message); } if (message.method == '_registerService') { return await _registerService(message); } if (message.method == '_spawnUri') { return await _spawnUri(message); } if (devfs.shouldHandleMessage(message)) { return await devfs.handleMessage(message); } if (_hasNamespace(message.method)) { return await _handleService(message); } if (message.params['isolateId'] != null) { return await runningIsolates.routeRequest(this, message); } return await message.sendToVM(); //[见小节3.4] } catch (e, st) { return message.response; } } 3.4 message.sendToVM [-> third_party/dart/sdk/lib/vmservice/message.dart] Future sendToVM() { final receivePort = new RawReceivePort(); receivePort.handler = (value) { receivePort.close(); _setResponseFromPort(value); }; var keys = params.keys.toList(growable: false); var values = params.values.toList(growable: false); if (!_methodNeedsObjectParameters(method)) { keys = _makeAllString(keys); values = _makeAllString(values); } final request = new List(6) ..[0] = 0 ..[1] = receivePort.sendPort ..[2] = serial ..[3] = method ..[4] = keys ..[5] = values; if (_methodNeedsObjectParameters(method)) { sendObjectRootServiceMessage(request); //[见小节3.5] } else { sendRootServiceMessage(request); //[见小节3.5] } return _completer.future; } sendRootServiceMessage,这是一个native方法,调用到vmservice.cc中相应的方法 3.5 message.sendRootServiceMessage [-> third_party/dart/runtime/lib/vmservice.cc] DEFINE_NATIVE_ENTRY(VMService_SendRootServiceMessage, 0, 1) { #ifndef PRODUCT GET_NON_NULL_NATIVE_ARGUMENT(Array, message, arguments->NativeArgAt(0)); if (FLAG_support_service) { return Service::HandleRootMessage(message); //[见小节3.6] } #endif return Object::null(); } DEFINE_NATIVE_ENTRY(VMService_SendObjectRootServiceMessage, 0, 1) { #ifndef PRODUCT GET_NON_NULL_NATIVE_ARGUMENT(Array, message, arguments->NativeArgAt(0)); if (FLAG_support_service) { return Service::HandleObjectRootMessage(message); } #endif return Object::null(); } 3.6 Service::HandleRootMessage [-> third_party/dart/runtime/vm/service.cc] RawError* Service::HandleRootMessage(const Array& msg_instance) { Isolate* isolate = Isolate::Current(); return InvokeMethod(isolate, msg_instance); //[见小节3.7] } RawError* Service::HandleObjectRootMessage(const Array& msg_instance) { Isolate* isolate = Isolate::Current(); return InvokeMethod(isolate, msg_instance, true); //[见小节3.7] } 3.7 Service::InvokeMethod [-> third_party/dart/runtime/vm/service.cc] RawError* Service::InvokeMethod(Isolate* I, const Array& msg, bool parameters_are_dart_objects) { Thread* T = Thread::Current(); { StackZone zone(T); HANDLESCOPE(T); Instance& reply_port = Instance::Handle(Z); Instance& seq = String::Handle(Z); String& method_name = String::Handle(Z); Array& param_keys = Array::Handle(Z); Array& param_values = Array::Handle(Z); reply_port ^= msg.At(1); seq ^= msg.At(2); method_name ^= msg.At(3); param_keys ^= msg.At(4); param_values ^= msg.At(5); JSONStream js; Dart_Port reply_port_id = (reply_port.IsNull() ? ILLEGAL_PORT : SendPort::Cast(reply_port).Id()); js.Setup(zone.GetZone(), reply_port_id, seq, method_name, param_keys, param_values, parameters_are_dart_objects); ... const char* c_method_name = method_name.ToCString(); //从service_methods_[]找到目标方法 [3.7.1] const ServiceMethodDescriptor* method = FindMethod(c_method_name); if (method != NULL) { if (method->entry(T, &js)) { //执行相应方法 js.PostReply(); } return T->StealStickyError(); } ... } } 3.7.1 FindMethod [-> third_party/dart/runtime/vm/service.cc] const ServiceMethodDescriptor* FindMethod(const char* method_name) { intptr_t num_methods = sizeof(service_methods_) / sizeof(service_methods_[0]); for (intptr_t i = 0; i < num_methods; i++) { const ServiceMethodDescriptor& method = service_methods_[i]; if (strcmp(method_name, method.name) == 0) { return &method; } } return NULL; } 在service.cc中有一个成员变量service_methods_[]记录了所有的定义的方法。比如获取timeline的过程,如下所示。 3.7.2 service_methods_数组 struct ServiceMethodDescriptor { const char* name; const ServiceMethodEntry entry; const MethodParameter* const* parameters; }; static const ServiceMethodDescriptor service_methods_[] = { { "_echo", Echo, NULL }, { "_respondWithMalformedJson", RespondWithMalformedJson, NULL }, { "_respondWithMalformedObject", RespondWithMalformedObject, NULL }, { "_triggerEchoEvent", TriggerEchoEvent, NULL }, { "addBreakpoint", AddBreakpoint, add_breakpoint_params }, { "addBreakpointWithScriptUri", AddBreakpointWithScriptUri, add_breakpoint_with_script_uri_params }, { "addBreakpointAtEntry", AddBreakpointAtEntry, add_breakpoint_at_entry_params }, { "_addBreakpointAtActivation", AddBreakpointAtActivation, add_breakpoint_at_activation_params }, { "_buildExpressionEvaluationScope", BuildExpressionEvaluationScope, build_expression_evaluation_scope_params }, { "_clearCpuProfile", ClearCpuProfile, clear_cpu_profile_params }, { "_clearVMTimeline", ClearVMTimeline, clear_vm_timeline_params, }, { "_compileExpression", CompileExpression, compile_expression_params }, { "_enableProfiler", EnableProfiler, enable_profiler_params, }, { "evaluate", Evaluate, evaluate_params }, { "evaluateInFrame", EvaluateInFrame, evaluate_in_frame_params }, { "_getAllocationProfile", GetAllocationProfile, get_allocation_profile_params }, { "_getAllocationSamples", GetAllocationSamples, get_allocation_samples_params }, { "_getNativeAllocationSamples", GetNativeAllocationSamples, get_native_allocation_samples_params }, { "getClassList", GetClassList, get_class_list_params }, { "_getCpuProfile", GetCpuProfile, get_cpu_profile_params }, { "_getCpuProfileTimeline", GetCpuProfileTimeline, get_cpu_profile_timeline_params }, { "_writeCpuProfileTimeline", WriteCpuProfileTimeline, write_cpu_profile_timeline_params }, { "getFlagList", GetFlagList, get_flag_list_params }, { "_getHeapMap", GetHeapMap, get_heap_map_params }, { "_getInboundReferences", GetInboundReferences, get_inbound_references_params }, { "_getInstances", GetInstances, get_instances_params }, { "getIsolate", GetIsolate, get_isolate_params }, { "getMemoryUsage", GetMemoryUsage, get_memory_usage_params }, { "_getIsolateMetric", GetIsolateMetric, get_isolate_metric_params }, { "_getIsolateMetricList", GetIsolateMetricList, get_isolate_metric_list_params }, { "getObject", GetObject, get_object_params }, { "_getObjectStore", GetObjectStore, get_object_store_params }, { "_getObjectByAddress", GetObjectByAddress, get_object_by_address_params }, { "_getPersistentHandles", GetPersistentHandles, get_persistent_handles_params, }, { "_getPorts", GetPorts, get_ports_params }, { "_getReachableSize", GetReachableSize, get_reachable_size_params }, { "_getRetainedSize", GetRetainedSize, get_retained_size_params }, { "_getRetainingPath", GetRetainingPath, get_retaining_path_params }, { "getScripts", GetScripts, get_scripts_params }, { "getSourceReport", GetSourceReport, get_source_report_params }, { "getStack", GetStack, get_stack_params }, { "_getUnusedChangesInLastReload", GetUnusedChangesInLastReload, get_unused_changes_in_last_reload_params }, { "_getTagProfile", GetTagProfile, get_tag_profile_params }, { "_getTypeArgumentsList", GetTypeArgumentsList, get_type_arguments_list_params }, { "getVersion", GetVersion, get_version_params }, { "getVM", GetVM, get_vm_params }, { "_getVMMetric", GetVMMetric, get_vm_metric_params }, { "_getVMMetricList", GetVMMetricList, get_vm_metric_list_params }, { "_getVMTimeline", GetVMTimeline, get_vm_timeline_params }, { "_getVMTimelineFlags", GetVMTimelineFlags, get_vm_timeline_flags_params }, { "invoke", Invoke, invoke_params }, { "kill", Kill, kill_params }, { "pause", Pause, pause_params }, { "removeBreakpoint", RemoveBreakpoint, remove_breakpoint_params }, { "reloadSources", ReloadSources, reload_sources_params }, { "_reloadSources", ReloadSources, reload_sources_params }, { "resume", Resume, resume_params }, { "_requestHeapSnapshot", RequestHeapSnapshot, request_heap_snapshot_params }, { "_evaluateCompiledExpression", EvaluateCompiledExpression, evaluate_compiled_expression_params }, { "setExceptionPauseMode", SetExceptionPauseMode, set_exception_pause_mode_params }, { "setFlag", SetFlag, set_flags_params }, { "setLibraryDebuggable", SetLibraryDebuggable, set_library_debuggable_params }, { "setName", SetName, set_name_params }, { "_setTraceClassAllocation", SetTraceClassAllocation, set_trace_class_allocation_params }, { "setVMName", SetVMName, set_vm_name_params }, { "_setVMTimelineFlags", SetVMTimelineFlags, set_vm_timeline_flags_params }, { "_collectAllGarbage", CollectAllGarbage, collect_all_garbage_params }, { "_getDefaultClassesAliases", GetDefaultClassesAliases, get_default_classes_aliases_params }, }; 3.8 HttpRequestClient class HttpRequestClient extends Client { static ContentType jsonContentType = new ContentType("application", "json", charset: "utf-8"); final HttpRequest request; void post(Response result) { HttpResponse response = request.response; response.headers.add('Access-Control-Allow-Origin', '*'); response.headers.contentType = jsonContentType; switch (result.kind) { case ResponsePayloadKind.String: response.write(result.payload); break; case ResponsePayloadKind.Utf8String: response.add(result.payload); break; case ResponsePayloadKind.Binary: throw 'Can not handle binary responses'; } response.close(); close(); } 四、小结 ServiceIsolate处理监听状态,根据具体的命令,最终会执行执行到service.cc的成service_methods_数组中所定义的方法。看到这里,你可能还不了解其功能。 这只是为下一篇文章介绍timeline工作原理做铺垫而已。
一、Dart虚拟机 1.1 引言 Dart VM是一种虚拟机,为高级编程语言Dart提供执行环境,但这并意味着Dart在D虚拟机上执行时,总是采用解释执行或者JIT编译。 例如还可以使用Dart虚拟机的AOT管道将Dart代码编译为机器代码,然后运行在Dart虚拟机的精简版环境,称之为预编译运行时(precompiled runtime)环境,该环境不包含任何编译器组件,且无法动态加载Dart源代码。 1.2 虚拟机如何运行Dart代码 Dart VM有多钟方式来执行代码: 源码或者Kernel二进制(JIT) snapshot AOT snapshot AppJIT snapshot 区别主要在于什么时机以及如何将Dart代码转换为可执行的代码。 1.3 Isolate组成 先来看看dart虚拟机中isolate的组成: isolate堆是运该isolate中代码分配的所有对象的GC管理的内存存储; vm isolate是一个伪isolate,里面包含不可变对象,比如null,true,false; isolate堆能引用vm isolate堆中的对象,但vm isolate不能引用isolate堆; isolate彼此之间不能相互引用 每个isolate都有一个执行dart代码的Mutator thread,一个处理虚拟机内部任务(比如GC, JIT等)的helper thread; isolate拥有内存堆和控制线程,虚拟机中可以有很多isolate,但彼此之间不能直接状态,只能通过dart特有的端口;isolate除了拥有一个mutator控制线程,还有一些其他辅助线程: 后台JIT编译线程; GC清理线程; GC并发标记线程; 线程和isolate的关系是什么呢? 同一个线程在同一时间只能进入一个isolate,当需要进入另一个isolate则必须先退出当前的isolate; 一次只能有一个Mutator线程关联对应的isolate,Mutator线程是执行Dart代码并使用虚拟机的公共的C语言API的线程 1.4 ThreadPool组成 虚拟机采用线程池的方式来管理线程,定义在runtime/vm/thread_pool.h ThreadPool的核心成员变量: all_workers_:记录所有的workers; idle_workers:_记录所有空闲的workers; count_started_:记录该线程池的历史累计启动workers个数; count_stopped_:记录该线程池的历史累计关闭workers个数; count_running_:记录该线程池当前正在运行的worker个数; count_idle_:记录该线程池当前处于空闲的worker个数,也就是idle_workers的长度; ThreadPool核心方法: Run(Task*): 执行count_running_加1,并将Task设置到该Worker, 当idle_workers_为空,则创建新的Worker并添加到all_workers_队列头部,count_started_加1; 当idle_workers_不为空,则取走idle_workers_队列头部的Worker,count_idle_减1; Shutdown(): 将all_workers_和idle_workers_队列置为NULL,并将count_running_和count_idle_清零,将关闭的all_workers_个数累加到count_stopped_; SetIdleLocked(Worker*):将该Worker添加到idle_workers_队列头部,count_idle_加1, count_running_减1; ReleaseIdleWorker(Worker*):从all_workers_和idle_workers_队列中移除该Worker,count_idle_减1,count_stopped_加1; 对应关系图: count_started_ count_stopped_ count_running_ count_idle_ Run() +1(无空闲worker) +1 -1(有空闲worker) Shutdown() +all_workers_个数 清零 清零 SetIdleLocked() -1 +1 ReleaseIdleWorker() +1 -1 可见,count_started_ - count_stopped_ = count_running_ + count_idle_; 二、JIT运行模式 2.1 CFE前端编译器 看看dart是如何直接理解并执行dart源码 // gityuan.dart main() => print('Hello Gityuan!'); //dart位于flutter/bin/cache/dart-sdk/bin/dart $ dart gityuan.dart Hello, World! 说明: Dart虚拟机并不能直接从Dart源码执行,而是执行dill二进制文件,该二进制文件包括序列化的Kernel AST(抽象语法树)。 Dart Kernel是一种从Dart中衍生而来的高级语言,设计之初用于程序分析与转换(transformations)的中间产物,可用于代码生成与后端编译器,该kernel语言有一个内存表示,可以序列化为二进制或文本。 将Dart转换为Kernel AST的是CFE(common front-end)通用前端编译器。 生成的Kernel AST可交由Dart VM、dev_compiler以及dart2js等各种Dart工具直接使用。 2.2 kernel service 有一个辅助类isolate叫作kernel service,其核心工作就是CFE,将dart转为Kernel二进制,然后VM可直接使用Kernel二进制运行在主isolate里面运行。 2.3 debug运行 将dart代码转换为kernel二进制和执行kernel二进制,这两个过程也可以分离开来,在两个不同的机器执行,比如host机器执行编译,移动设备执行kernel文件。 图解: 这个编译过程并不是flutter tools自身完成,而是交给另一个进程frontend_server来执行,它包括CFE和一些flutter专有的kernel转换器。 hot reload:热重载机制正是依赖这一点,frontend_server重用上一次编译中的CFE状态,只重新编译实际更改的部分。 2.4 RawClass内部结构 虚拟机内部对象的命名约定:使用C++定义的,其名称在头文件raw_object.h中以Raw开头,比如RawClass是描述Dart类的VM对象,RawField是描述Dart类中的Dart字段的VM对象。 1)将内核二进制文件加载到VM后,将对其进行解析以创建表示各种程序实体的对象。这里采用了懒加载模式,一开始只有库和类的基本信息被加载,内核二进制文件中的每一个实体都会保留指向该二进制文件的指针,以便后续可根据需要加载更多信息。 2)仅在以后需要运行时,才完全反序列化有关类的信息。(例如查找类的成员变量,创建类的实例对象等),便会从内核二进制文件中读取类的成员信息。 但功能完整的主体(FunctionNode)在此阶段并不会反序列化,而只是获取其签名。 到此,已从内核二进制文件加载了足够的信息以供运行时成功解析和调用的方法。 所有函数的主体都具有占位符code_,而不是实际的可执行代码:它们指向LazyCompileStub,该Stub只是简单地要求系统Runtime为当前函数生成可执行代码,然后对这些新生成的代码进行尾部调用。 2.5 查看Kernel文件格式 gen_kernel.dart利用CFE将Dart源码编译为kernel binary文件(也就是dill),可利用dump_kernel.dart能反解kernel binary文件,命令如下所示: //将hello.dart编译成hello.dill $ cd $ dart third_party/dart/pkg/vm/bin/gen_kernel.dart \ --platform out/android_debug/vm_platform_strong.dill \ -o hello.dill \ hello.dart //转储AST的文本表示形式 $ dart third_party/dart/pkg/vm/bin/dump_kernel.dart hello.dill hello.kernel.txt gen_kernel.dart文件,需要平台dill文件,这是一个包括所有核心库(dart:core, dart:async等)的AST的kernel binary文件。如果Dart SDK已经编译过,可直接使用out/ReleaseX64/vm_platform_strong.dill,否则需要使用compile_platform.dart来生成平台dill文件,如下命令: //根据给定的库列表,来生成platform和outline文件 $ cd $ dart third_party/dart/pkg/front_end/tool/_fasta/compile_platform.dart \ dart:core \ third_party/dart/sdk/lib/libraries.json \ vm_outline.dill vm_platform.dill vm_outline.dill 2.6 未优化编译器 首次编译函数时,这是通过未优化编译器来完成的。 未优化的编译器分两步生成机器代码: AST -> CFG: 对函数主体的序列化AST进行遍历,以生成函数主体的控制流程图(CFG),CFG是由填充中间语言(IL)指令的基本块组成。此阶段使用的IL指令类似于基于堆栈的虚拟机的指令:它们从堆栈中获取操作数,执行操作,然后将结果压入同一堆栈 IL -> 机器指令:使用一对多的IL指令,将生成的CFG直接编译为机器代码:每个IL指令扩展为多条机器指令。 在此阶段没有执行优化,未优化编译器的主要目标是快速生成可执行代码。 2.7 内联缓存 未优化编译过程,编译器不会尝试静态解析任何未在Kernel二进制文件中解析的调用,因此(MethodInvocation或PropertyGet AST节点)的调用被编译为完全动态的。虚拟机当前不使用任何形式的基于虚拟表(virtual table)或接口表(interface table)的调度,而是使用内联缓存实现动态调用。 虚拟机的内联缓存的核心思想是缓存方法解析后的站点结果信息,对于内联缓存最初是为了解决函数的本地代码: 站点调用的特定缓存(RawICData对象)将接受者的类映射到方法,缓存中记录着一些辅助信息,比如方法和基本块的调用频次计数器,该计数器记录着被跟踪类的调用频次; 共享的查找存根,用于实现方法调用的快速路径。该存根在给定的高速缓存中进行搜索,以查看其是否包含与接收者的类别匹配的条目。 如果找到该条目,则存根将增加频率计数器和尾部调用缓存的方法。否则,存根将调用系统Runtime来解析方法实现的逻辑,如果方法解析成功,则将更新缓存,并且随后的调用无需进入系统Runtime。 2.8 编译优化 未优化编译器产生的代码执行比较慢,需要自适应优化,通过profile配置文件来驱动优化策略。内联优化,当与某个功能关联的执行计数器达到某个阈值时,该功能将提交给后台优化编译器进行优化。 优化编译的方式与未优化编译的方式相同:通过序列化内核AST来构建未优化的IL。但是,优化编译器不是直接将IL编译为机器码,而是将未优化的IL转换为基于静态单分配(SSA)形式的优化的IL。 对基于SSA的IL通过基于收集到的类型反馈,内联,范围分析,类型传播,表示选择,存储到加载,加载到加载转发,全局值编号,分配接收等一系列经典和Dart特定的优化来进行专业化推测。最后,使用线性扫描寄存器分配器和一个简单的一对多的IL指令。优化编译完成后,后台编译器会请求mutator线程输入安全点,并将优化的代码附加到该函数。下次调用该函数时,它将使用优化的代码。 另外,有些函数包含很长的运行循环,因此在函数仍在运行时将执行从未优化的代码切换到优化的代码是有意义的,此过程之所以称为“堆栈替换”(OSR)。 VM还具有可用于控制JIT并使其转储IL以及用于JIT正在编译的功能的机器代码的标志 $ dart --print-flow-graph-optimized \ --disassemble-optimized \ --print-flow-graph-filter=myFunc \ --no-background-compilation \ hel.dart 2.9 反优化 优化是基于统计的,可能出现违反优化的情况 void printAnimal(obj) { print('Animal {'); print(' ${obj.toString()}'); print('}'); } // 大量调用的情况下,会推测printAnimal假设总是Cat的情况下来优化代码 for (var i = 0; i < 50000; i++) printAnimal(Cat()); // 此处出现的是Dog,优化版本失效,则触发反优化 printAnimal(Dog()); 每当只要优化版本遇到无法解决的情况,它就会将执行转移到未优化功能的匹配点,然后继续执行,这个恢复过程称为去优化:未优化的功能版本不做任何假设,可以处理所有可能的输入。 虚拟机通常会在执行一次反优化后,放弃该功能的优化版本,然后在以后使用优化的类型反馈再次对其进行重新优化。虚拟机保护编译器进行推测性假设的方式有两种: 内联检查(例如CheckSmi,CheckClass IL指令),以验证假设是否在编译器做出此假设的使用场所成立。例如,将动态调用转换为直接调用时,编译器会在直接调用之前添加这些检查。 在此类检查中发生的取消优化称为“急切优化”,因为它在达到检查时就急于发生。 运行时在更改优化代码所依赖的内容时,将会丢弃优化代码。例如,优化编译器可能会发现某些类从未扩展过,并且在类型传播过程中使用了此信息。 但是,随后的动态代码加载或类最终确定可能会引入C的子类,导致假设无效。此时,运行时需要查找并丢弃所有在C没有子类的假设下编译的优化代码。 运行时可能会在执行堆栈上找到一些现在无效的优化代码,在这种情况下,受影响的帧将被标记为不优化,并且当执行返回时将进行不优化。 这种取消优化称为延迟取消优化,因为它会延迟到控制权返回到优化代码为止。 三、Snapshots运行模式 3.1 通过Snapshots运行 1)虚拟机有能力将isolate的堆(驻留在堆上的对象图)序列化成二进制的快照,启动虚拟机isolate的时候可以从快照中重新创建相同的状态。 Snapshot的格式是低级的,并且针对快速启动进行了优化,本质上是要创建的对象列表以及如何将它们连接在一起的说明。那是快照背后的原始思想:代替解析Dart源码并逐步创建虚拟机内部的数据结构,这样虚拟机通过快照中的所有必要数据结构来快速启动isolate。 2)最初,快照不包括机器代码,但是后来在开发AOT编译器时添加了此功能。开发AOT编译器和带代码快照的动机是为了允许虚拟机在由于平台级别限制而无法进行JIT的平台上使用。 带代码的快照的工作方式几乎与普通快照相同,只是有一点点不同:它们包括一个代码部分,该部分与快照的其余部分不同,不需要反序列化。该代码节的放置方式使其可以在映射到内存后直接成为堆的一部分 3.2 通过AppJIT Snapshots运行 引入AppJIT快照可减少大型Dart应用程序(如dartanalyzer或dart2js)的JIT预热时间。当这些工具用于小型项目时,它们花费的实际时间与VM花费的JIT编译这些应用程序的时间一样多。 AppJIT快照可以解决此问题:可以使用一些模拟训练数据在VM上运行应用程序,然后将所有生成的代码和VM内部数据结构序列化为AppJIT快照。然后可以分发此快照,而不是以源(或内核二进制)形式分发应用程序。如果出现实际数据上的执行配置文件与培训期间观察到的执行配置文件不匹配,快照开始的VM仍可以采用JIT模式执行。 3.3 通过AppAOT Snapshots运行 AOT快照最初是为无法进行JIT编译的平台引入的,对于无法进行JIT意味着: AOT快照必须包含应用程序执行期间可能调用的每个功能的可执行代码; 可执行代码不得依赖于执行期间可能违反的任何推测性假设 为了满足这些要求,AOT编译过程会进行全局静态分析(类型流分析, TFA),以确定从已知入口点集中可访问应用程序的哪些部分,分配了哪些类的实例以及类型如何在程序中流动。 所有这些分析都是保守的:这意味着它们会在正确性方面出错,与可以在性能方面出错的JIT形成鲜明对比,因为它始终可以取消优化为未优化的代码以实现正确的行为。 然后,所有可能达到的功能都将编译为本地代码,而无需进行任何推测性优化。但是,类型流信息仍用于专门化代码(例如,取消虚拟化调用),编译完所有函数后,即可获取堆的快照。 最终的快照snapshot可以运行在预编译Runtime,该Runtime是Dart VM的特殊变体,其中不包括诸如JIT和动态代码加载工具之类的组件。 AOT编译工具没有包含进Dart SDK。 //需要构建正常的dart可执行文件和运行AOT代码的runtime $ tool/build.py -m release -a x64 runtime dart_precompiled_runtime // 使用AOT编译器来编译APP $ pkg/vm/tool/precompiler2 hello.dart hello.aot //执行AOT快照 $ out/ReleaseX64/dart_precompiled_runtime hello.aot Hello, World! 3.3.1 Switchable Calls 1)即使进行了全局和局部分析,AOT编译的代码仍可能包含无法静态的去虚拟化的调用站点。为了补偿此AOT编译代码和运行时,采用JIT中使用的内联缓存技术的扩展。此扩展版本称为可切换呼叫 (Switchable Calls)。 JIT部分已经描述过,与调用站点关联的每个内联缓存均由两部分组成:一个缓存对象(由RawICData实例表示)和一个要调用的本机代码块(例如InlineCacheStub)。在JIT模式下,运行时只会更新缓存本身。但在AOT运行时中,可以根据内联缓存的状态选择同时替换缓存和要调用的本机代码。 最初,所有动态呼叫均以未链接状态开始。首次调用此类呼叫站点时,将调用UnlinkedCallStub,它只是调用运行时帮助程序DRT_UnlinkedCall来链接此呼叫站点。 2)如果可能,DRT_UnlinkedCall尝试将呼叫站点转换为单态状态。在这种状态下,呼叫站点变成直接呼叫,该呼叫通过特殊的单态入口点进入方法,该入口点验证接收方是否具有预期的类。 在上面的示例中,假设第一次执行obj.method()时,obj是C的实例,而obj.method则解析为C.method。 下次执行相同的调用站点时,它将直接调用C.method,从而绕过任何类型的方法查找过程。但是,它将通过特殊的入口点(已验证obj仍然是C的实例)进入C.method。如果不是这种情况,将调用DRT_MonomorphicMiss并将尝试选择下一个调用站点状态。 3)C.method可能仍然是调用的有效目标,例如obj是C的扩展类但不覆盖C.method的D类的实例。在这种情况下,检查呼叫站点是否可以转换为由SingleTargetCallStub实现的单个目标状态(见RawSingleTargetCache)。 此存根基于以下事实:对于AOT编译,大多数类都使用继承层次结构的深度优先遍历来分配整数ID。如果C是具有D0,…,Dn子类的基类,并且没有一个覆盖C.method,则C.:cid <= classId(obj)<= max(D0.:cid,…,Dn .:cid)表示obj.method解析为C.method。在这种情况下,我们可以将类ID范围检查(单个目标状态)用于C的所有子类,而不是与单个类(单态)进行比较 否则,呼叫站点将切换为使用线性搜索内联缓存,类似于在JIT模式下使用的缓存。 最后,如果线性数组中的检查数量超过阈值,则呼叫站点将切换为使用类似字典的结构 四、附录 4.1 源码说明 整个过程相关的核心源码,简要说明: runtime/vm/isolate.h: isolate对象 runtime/vm/thread.h:与连接到isolate对象的线程关联的状态 runtime/vm/heap/heap.h: isolate的堆 raw_object.h: 虚拟机内部对象 ast.dart:定义描述内核AST的类 kernel_loader.cc:其中的LoadEntireProgram()方法用于将内核AST反序列化为相应虚拟机对象的入口点 kernel_service.dart:实现了Kernel Service isolate kernel_isolate.cc:将Dart实现粘合到VM的其余部分 pkg/front_end:用于解析Dart源码和构建内核AST pkg/vm: 托管了大多数基于内核的VM特定功能,例如各种内核到内核的转换;由于历史原因,某些转换还位于pkg/kernel; runtime/vm/compiler: 编译器源码 runtime/vm/compiler/jit/compiler.cc:编译管道入口点 runtime/vm/compiler/backend/il.h: IL的定义 runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc: 其中的BuildGraph(), 内核到IL的翻译开始,处理各种人工功能的IL的构建 runtime/vm/stub_code_x64.cc:其中StubCode::GenerateNArgsCheckInlineCacheStub(),为内联缓存存根生成机器代码 runtime/vm/runtime_entry.cc:其中InlineCacheMissHandler()处理IC没有命中的情况 runtime/vm/compiler/compiler_pass.cc: 定义优化编译器的遍历及其顺序 runtime/vm/compiler/jit/jit_call_specializer.h:进行大多数基于类型反馈的专业化 runtime/vm/deopt_instructions.cc: 反优化过程 runtime/vm/clustered_snapshot.cc:处理快照的序列化和反序列化。API函数家族Dart_CreateXyzSnapshot[AsAssembly]负责写出堆的快照,比如 Dart_CreateAppJITSnapshotAsBlobs 和Dart_CreateAppAOTSnapshotAsAssembly。 runtime/vm/dart_api_impl.cc: 其中Dart_CreateIsolate可以选择获取快照数据以开始isolate。 pkg/vm/lib/transformations/type_flow/transformer.dart: TFA(类型流分析)以及基于TFA结果转换的切入点 runtime/vm/compiler/aot/precompiler.cc:其中Precompiler::DoCompileAll()是整个AOT编译的切入点 4.2 参考资料 https://mrale.ph/dartvm/
一、概述 在third_party/dart/runtime/vm/flag_list.h定义了Dart虚拟机中所有标志的列表,标志分为以下几大类别: Product标记:可以在任何部署模式中设置,包括Product模式 Release标志:通常可用的标志,除Product模式以外 Precompile标志:通常可用的标志,除Product模式或已预编译的运行时以外 Debug标志:只能在启用C++断言的VM调试模式中设置 Product、Release、Precompile、Debug这四类可控参数,可使用的范围逐次递减,比如Product flags可用于所有模式,Debug flags只能用于调试模式。Dart虚拟机总共有106个flags参数 二、flags参数 2.1 Product flags 用法:PRODUCT_FLAG_MARCO(名称,类型,默认值,注解) 名称 默认值 注解 collect_dynamic_function_names true 收集所有动态函数名称以标识唯一目标 enable_kernel_expression_compilation true 启用内核前端来编译表达式 enable_mirrors true 允许导入dart:mirrors enable_ffi true 允许导入dart:ffi guess_icdata_cid true 创建算法等操作的类型反馈 lazy_dispatchers true 懒惰地生成调度程序 polymorphic_with_deopt true 反优化的多态调用、巨形调用 reorder_basic_blocks true 对基本块重新排序 use_bare_instructions true 启用裸指令模式 truncating_left_shift true 尽可能优化左移以截断 use_cha_deopt true 使用类层次分析,即使会导致反优化 use_strong_mode_types true 基于强模式类型的优化 enable_slow_path_sharing true 启用共享慢速路径代码 enable_multiple_entrypoints true 启用多个入口点 experimental_unsafe_mode_use_ at_your_own_risk false 省略运行时强模式类型检查并禁用基于类型的优化 abort_on_oom false 如果内存分配失败则中止,仅与–old-gen-heap-size一起使用 collect_code false 尝试GC不常用代码 dwarf_stack_traces false 在dylib快照中发出dwarf行号和内联信息,而不表示堆栈跟踪 fields_may_be_reset false 不要优化静态字段初始化 link_natives_lazily false 懒加载链接本地调用 precompiled_mode false 预编译编译器模式 print_snapshot_sizes false 打印生成snapshot的大小 print_snapshot_sizes_verbose false 打印生成snapshot的详细大小 print_benchmarking_metrics false 打印其他内存和延迟指标以进行基准测试 shared_slow_path_triggers_gc false 测试:慢路径触发GC trace_strong_mode_types false 跟踪基于强模式类型的优化 use_bytecode_compiler false 从字节码编译 use_compactor false 当在旧空间执行GC时则压缩堆 enable_testing_pragmas false 启用神奇的编译指示以进行测试 enable_interpreter false 启用解释内核字节码 verify_entry_points false 通过native API访问无效成员时抛出API错误 background_compilation USING_MULTICORE 根据是否多核来决定是否后台运行优化编译 concurrent_mark USING_MULTICORE 老年代的并发标记 concurrent_sweep USING_MULTICORE 老年代的并发扫描 use_field_guards !USING_DBC 使用字段gurad,跟踪字段类型 interpret_irregexp USING_DBC 使用irregexp字节码解释器 causal_async_stacks !USING_PRODUCT 非product 则开启改进异步堆栈 marker_tasks USING_MULTICORE ? 2 : 0 老生代GC标记的任务数,0代表在主线程执行 idle_timeout_micros 1000 * 1000 长时间后将空闲任务从线程池隔离,单位微秒 idle_duration_micros 500 * 1000 允许空闲任务运行的时长 old_gen_heap_size (kWordSize third_party/dart/runtime/vm/flags.cc] FLAG_LIST(PRODUCT_FLAG_MARCO, RELEASE_FLAG_MARCO, DEBUG_FLAG_MARCO, PRECOMPILE_FLAG_MARCO) FLAG_LIST列举了所有的宏定义,这里有四种不同的宏,接下来逐一展开说明 3.2 flag宏定义 [-> third_party/dart/runtime/vm/flags.cc] // (1) Product标记:可以在任何部署模式中设置 #define PRODUCT_FLAG_MARCO(name, type, default_value, comment) \ type FLAG_##name = Flags::Register_##type(&FLAG_##name, #name, default_value, comment); // (2) Release标志:通常可用的标志,除Product模式以外 #if !defined(PRODUCT) #define RELEASE_FLAG_MARCO(name, product_value, type, default_value, comment) \ type FLAG_##name = Flags::Register_##type(&FLAG_##name, #name, default_value, comment); // (3) Precompile标志:通常可用的标志,除Product模式或已预编译的运行时以外 #if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME) #define PRECOMPILE_FLAG_MARCO(name, pre_value, product_value, type, default_value, comment) \ type FLAG_##name = Flags::Register_##type(&FLAG_##name, #name, default_value, comment); // (4) Debug标志:只能在debug调试模式运行 #if defined(DEBUG) #define DEBUG_FLAG_MARCO(name, type, default_value, comment) \ type FLAG_##name = Flags::Register_##type(&FLAG_##name, #name, default_value, comment); 这里涉及到3个宏定义: PRODUCT:代表Product模式; DART_PRECOMPILED_RUNTIME:代表运行时已预编译模式; DEBUG:代表调试模式; 可见,宏定义最终都是调用Flags::Register_XXX()方法,这里以FLAG_LIST中的其中一条定义来展开说明: P(collect_code, bool, false, "Attempt to GC infrequently used code.") //展开后等价如下 type FLAG_collect_code = Flags::Register_bool(&FLAG_collect_code, collect_code, false, "Attempt to GC infrequently used code."); 3.3 Flags::Register_bool [-> third_party/dart/runtime/vm/flags.cc] bool Flags::Register_bool(bool* addr, const char* name, bool default_value, const char* comment) { Flag* flag = Lookup(name); //[见小节3.4] if (flag != NULL) { return default_value; } flag = new Flag(name, comment, addr, Flag::kBoolean); AddFlag(flag); return default_value; } 3.4 Flags::Lookup [-> third_party/dart/runtime/vm/flags.cc] Flag* Flags::Lookup(const char* name) { //遍历flags_来查找是否已存在 for (intptr_t i = 0; i name_, name) == 0) { return flag; } } return NULL; } Flags类中有3个重要的静态成员变量: static Flag** flags_; //记录所有的flags对象指针 static intptr_t capacity_; //代表数组的容量大小 static intptr_t num_flags_; //代表当前flags对象指针的个数 3.5 Flag初始化 [-> third_party/dart/runtime/vm/flags.cc] class Flag { Flag(const char* name, const char* comment, void* addr, FlagType type) : name_(name), comment_(comment), addr_(addr), type_(type) {} const char* name_; const char* comment_; union { void* addr_; bool* bool_ptr_; int* int_ptr_; uint64_t* uint64_ptr_; charp* charp_ptr_; FlagHandler flag_handler_; OptionHandler option_handler_; }; FlagType type_; } 3.6 Flags::AddFlag [-> third_party/dart/runtime/vm/flags.cc] class Flag { void Flags::AddFlag(Flag* flag) { if (num_flags_ == capacity_) { if (flags_ == NULL) { capacity_ = 256; //初始化大小为256 flags_ = new Flag*[capacity_]; } else { intptr_t new_capacity = capacity_ * 2; //扩容 Flag** new_flags = new Flag*[new_capacity]; for (intptr_t i = 0; i < num_flags_; i++) { new_flags[i] = flags_[i]; } delete[] flags_; flags_ = new_flags; capacity_ = new_capacity; } } //将flag记录到flags_ flags_[num_flags_++] = flag; } } 最终,所有的flag信息都记录在Flags类的静态成员变量flags_中。 四、总结 Product标记:可以在任何部署模式中设置 Release标志:通常可用的标志,除Product模式以外 Precompile标志:通常可用的标志,除Product模式或已预编译的运行时以外 Debug标志:只能在启用C++断言的VM调试模式中设置
一、概述 书接上文源码解读Flutter run机制的第四节 flutter build aot命令将dart源码编译成AOT产物,其主要工作为前端编译器frontend_server和机器码生成,本文再来介绍机器码生成的工作原理。 1.1 GenSnapshot命令 GenSnapshot.run具体命令根据前面的封装,针对Android和iOS平台各有不同: 1.1.1 针对Android平台 flutter/bin/cache/artifacts/engine/android-arm-release/darwin-x64/gen_snapshot \ --causal_async_stacks \ --packages=.packages \ --deterministic \ --snapshot_kind=app-aot-blobs \ --vm_snapshot_data=build/app/intermediates/flutter/release/vm_snapshot_data \ --isolate_snapshot_data=build/app/intermediates/flutter/release/isolate_snapshot_data \ --vm_snapshot_instructions=build/app/intermediates/flutter/release/vm_snapshot_instr \ --isolate_snapshot_instructions=build/app/intermediates/flutter/release/isolate_snapshot_instr \ --no-sim-use-hardfp \ --no-use-integer-division \ build/app/intermediates/flutter/release/app.dill 上述命令用于Android平台将dart kernel转换为机器码。 1.1.2 针对iOS平台 /usr/bin/arch -x86_64 flutter/bin/cache/artifacts/engine/ios-release/gen_snapshot \ --causal_async_stacks \ --deterministic \ --snapshot_kind=app-aot-assembly \ --assembly=build/aot/arm64/snapshot_assembly.S \ build/aot/app.dill 上述命令用于iOS平台将dart kernel转换为机器码。 1.2 机器码生成流程图 点击查看大图 此处gen_snapshot是一个二进制可执行文件,所对应的执行方法源码为third_party/dart/runtime/bin/gen_snapshot.cc,gen_snapshot将dart代码生成AOT二进制机器码,其中重点过程在precompiler.cc中的DoCompileAll()。 1.2.1 小结 先通过Dart_Initialize()来初始化Dart虚拟机环境, 1.2.2 snapshot类型 类型 名称 kCore core kCoreJIT core-jit kApp app kAppJIT app-jit kAppAOTBlobs app-aot-blobs kAppAOTAssembly app-aot-assembly kVMAOTAssembly vm-aot-assembly 二、源码解读GenSnapshot BuildAotCommand.runCommand AOTSnapshotter.build GenSnapshot.run gen_snapshot.main 2.1 gen_snapshot.main [-> third_party/dart/runtime/bin/gen_snapshot.cc] int main(int argc, char** argv) { const int EXTRA_VM_ARGUMENTS = 7; CommandLineOptions vm_options(argc + EXTRA_VM_ARGUMENTS); CommandLineOptions inputs(argc); //从命令行运行时,除非指定其他参数,否则使用更大的新一代半空间大小和更快的新一代生长因子 if (kWordSize mapped_vm_snapshot_data; std::unique_ptr mapped_vm_snapshot_instructions; std::unique_ptr mapped_isolate_snapshot_data; std::unique_ptr mapped_isolate_snapshot_instructions; //将这4个产物文件mmap到内存 if (load_vm_snapshot_data_filename != NULL) { mapped_vm_snapshot_data = MapFile(load_vm_snapshot_data_filename, File::kReadOnly, &init_params.vm_snapshot_data); } if (load_vm_snapshot_instructions_filename != NULL) { mapped_vm_snapshot_instructions = MapFile(load_vm_snapshot_instructions_filename, File::kReadExecute, &init_params.vm_snapshot_instructions); } if (load_isolate_snapshot_data_filename) { mapped_isolate_snapshot_data = MapFile(load_isolate_snapshot_data_filename, File::kReadOnly, &isolate_snapshot_data); } if (load_isolate_snapshot_instructions_filename != NULL) { mapped_isolate_snapshot_instructions = MapFile(load_isolate_snapshot_instructions_filename, File::kReadExecute, &isolate_snapshot_instructions); } // 初始化Dart虚拟机 [见小节2.1.1] error = Dart_Initialize(&init_params); //[见小节2.2] int result = CreateIsolateAndSnapshot(inputs); // 回收Dart虚拟机 error = Dart_Cleanup(); EventHandler::Stop(); return 0; } 该方法主要功能说明: 初始化参数,并将这4个产物文件mmap到内存 执行Dart_Initialize()来初始化Dart虚拟机环境 CreateIsolateAndSnapshot 2.1.1 Dart_Initialize [-> third_party/dart/runtime/vm/dart_api_impl.cc] DART_EXPORT char* Dart_Initialize(Dart_InitializeParams* params) { ... return Dart::Init(params->vm_snapshot_data, params->vm_snapshot_instructions, params->create, params->shutdown, params->cleanup, params->thread_exit, params->file_open, params->file_read, params->file_write, params->file_close, params->entropy_source, params->get_service_assets, params->start_kernel_isolate); } 深入理解Dart虚拟机启动的[小节2.10]记录了Dart虚拟机的初始化过程。 2.2 CreateIsolateAndSnapshot [-> third_party/dart/runtime/bin/gen_snapshot.cc] static int CreateIsolateAndSnapshot(const CommandLineOptions& inputs) { uint8_t* kernel_buffer = NULL; intptr_t kernel_buffer_size = NULL; ReadFile(inputs.GetArgument(0), &kernel_buffer, &kernel_buffer_size); Dart_IsolateFlags isolate_flags; Dart_IsolateFlagsInitialize(&isolate_flags); if (IsSnapshottingForPrecompilation()) { isolate_flags.obfuscate = obfuscate; isolate_flags.entry_points = no_entry_points; } IsolateData* isolate_data = new IsolateData(NULL, NULL, NULL, NULL); Dart_Isolate isolate; char* error = NULL; //创建isolate if (isolate_snapshot_data == NULL) { // 将vmservice库加入到核心snapshot,因此将其加载到main isolate isolate_flags.load_vmservice_library = true; isolate = Dart_CreateIsolateFromKernel(NULL, NULL, kernel_buffer, kernel_buffer_size, &isolate_flags, isolate_data, &error); } else { isolate = Dart_CreateIsolate(NULL, NULL, isolate_snapshot_data, isolate_snapshot_instructions, NULL, NULL, &isolate_flags, isolate_data, &error); } Dart_EnterScope(); Dart_Handle result = Dart_SetEnvironmentCallback(DartUtils::EnvironmentCallback); result = Dart_SetRootLibrary(Dart_LoadLibraryFromKernel(kernel_buffer, kernel_buffer_size)); MaybeLoadExtraInputs(inputs); MaybeLoadCode(); // 根据产物类别 来创建相应产物 switch (snapshot_kind) { case kCore: CreateAndWriteCoreSnapshot(); break; case kCoreJIT: CreateAndWriteCoreJITSnapshot(); break; case kApp: CreateAndWriteAppSnapshot(); break; case kAppJIT: CreateAndWriteAppJITSnapshot(); break; case kAppAOTBlobs: case kAppAOTAssembly: //[见小节2.3] CreateAndWritePrecompiledSnapshot(); break; case kVMAOTAssembly: { File* file = OpenFile(assembly_filename); RefCntReleaseScope rs(file); result = Dart_CreateVMAOTSnapshotAsAssembly(StreamingWriteCallback, file); CHECK_RESULT(result); break; } default: UNREACHABLE(); } Dart_ExitScope(); Dart_ShutdownIsolate(); return 0; } 编译产物类型有7类,见[小节1.2.2]。 根据不同类型调用不同的CreateAndWriteXXXSnapshot()方法: kCore:CreateAndWriteCoreSnapshot kCoreJIT:CreateAndWriteCoreJITSnapshot kApp:CreateAndWriteAppSnapshot kAppJIT:CreateAndWriteAppJITSnapshot kAppAOTBlobs:CreateAndWritePrecompiledSnapshot kAppAOTAssembly:CreateAndWritePrecompiledSnapshot kVMAOTAssembly:Dart_CreateVMAOTSnapshotAsAssembly 此处介绍AOT模式下,接下来执行CreateAndWritePrecompiledSnapshot()过程。 2.3 CreateAndWritePrecompiledSnapshot [-> third_party/dart/runtime/bin/gen_snapshot.cc] static void CreateAndWritePrecompiledSnapshot() { Dart_Handle result; //使用指定的嵌入程序入口点进行预编译 [见小节2.4] result = Dart_Precompile(); //创建一个预编译的snapshot bool as_assembly = assembly_filename != NULL; if (as_assembly) { // kAppAOTAssembly模式 File* file = OpenFile(assembly_filename); RefCntReleaseScope rs(file); //iOS采用该方式 [见小节三] result = Dart_CreateAppAOTSnapshotAsAssembly(StreamingWriteCallback, file); } else { // kAppAOTBlobs模式 const uint8_t* shared_data = NULL; const uint8_t* shared_instructions = NULL; std::unique_ptr mapped_shared_data; std::unique_ptr mapped_shared_instructions; if (shared_blobs_filename != NULL) { AppSnapshot* shared_blobs = NULL; shared_blobs = Snapshot::TryReadAppSnapshot(shared_blobs_filename); const uint8_t* ignored; shared_blobs->SetBuffers(&ignored, &ignored, &shared_data, &shared_instructions); } else { if (shared_data_filename != NULL) { mapped_shared_data = MapFile(shared_data_filename, File::kReadOnly, &shared_data); } if (shared_instructions_filename != NULL) { mapped_shared_instructions = MapFile(shared_instructions_filename, File::kReadOnly, &shared_instructions); } } ... //将snapshot写入buffer缓存 [见小节四] result = Dart_CreateAppAOTSnapshotAsBlobs( &vm_snapshot_data_buffer, &vm_snapshot_data_size, &vm_snapshot_instructions_buffer, &vm_snapshot_instructions_size, &isolate_snapshot_data_buffer, &isolate_snapshot_data_size, &isolate_snapshot_instructions_buffer, &isolate_snapshot_instructions_size, shared_data, shared_instructions); if (blobs_container_filename != NULL) { Snapshot::WriteAppSnapshot( blobs_container_filename, vm_snapshot_data_buffer, vm_snapshot_data_size, vm_snapshot_instructions_buffer, vm_snapshot_instructions_size, isolate_snapshot_data_buffer, isolate_snapshot_data_size, isolate_snapshot_instructions_buffer, isolate_snapshot_instructions_size); } else { // 将内存中的产物数据写入相应的文件 WriteFile(vm_snapshot_data_filename, vm_snapshot_data_buffer, vm_snapshot_data_size); WriteFile(vm_snapshot_instructions_filename, vm_snapshot_instructions_buffer, vm_snapshot_instructions_size); WriteFile(isolate_snapshot_data_filename, isolate_snapshot_data_buffer, isolate_snapshot_data_size); WriteFile(isolate_snapshot_instructions_filename, isolate_snapshot_instructions_buffer, isolate_snapshot_instructions_size); } } // 如果需要,序列化混淆图 if (obfuscation_map_filename != NULL) { uint8_t* buffer = NULL; intptr_t size = 0; result = Dart_GetObfuscationMap(&buffer, &size); WriteFile(obfuscation_map_filename, buffer, size); } } 该方法说明: 调用Dart_Precompile()执行AOT编译 将snapshot代码写入buffer 将buffer写入这四个二进制文件vm_snapshot_data,vm_snapshot_instructions,isolate_snapshot_data,isolate_snapshot_instructions 该方法最终将Dart代码彻底编译为二进制可执行的机器码文件 2.4 Dart_Precompile [-> third_party/dart/runtime/vm/dart_api_impl.cc] DART_EXPORT Dart_Handle Dart_Precompile() { ... #if defined(DART_PRECOMPILER) DARTSCOPE(Thread::Current()); API_TIMELINE_BEGIN_END(T); if (!FLAG_precompiled_mode) { return Api::NewError("Flag --precompilation was not specified."); } Dart_Handle result = Api::CheckAndFinalizePendingClasses(T); if (Api::IsError(result)) { return result; } CHECK_CALLBACK_STATE(T); //[见小节2.4.1] CHECK_ERROR_HANDLE(Precompiler::CompileAll()); return Api::Success(); #endif } 2.4.1 CompileAll [-> third_party/dart/runtime/vm/compiler/aot/precompiler.cc] RawError* Precompiler::CompileAll() { LongJumpScope jump; if (setjmp(*jump.Set()) == 0) { //创建Precompiler对象 Precompiler precompiler(Thread::Current()); //[见小节2.4.2] precompiler.DoCompileAll(); return Error::null(); } else { return Thread::Current()->StealStickyError(); } } 在Dart Runtime中生成FlowGraph对象,接着进行一系列执行流的优化,最后把优化后的FlowGraph对象转换为具体相应系统架构(arm/arm64等)的二进制指令 2.4.2 DoCompileAll [-> third_party/dart/runtime/vm/compiler/aot/precompiler.cc] void Precompiler::DoCompileAll() { { StackZone stack_zone(T); zone_ = stack_zone.GetZone(); if (FLAG_use_bare_instructions) { // 使用zone_来保障全局object对象池的生命周期能伴随整个AOT编译过程 global_object_pool_builder_.InitializeWithZone(zone_); } { HANDLESCOPE(T); // 确保类层次稳定,因此会先支持CHA分析类层次结构 FinalizeAllClasses(); ClassFinalizer::SortClasses(); // 收集类型使用情况信息,使我们可以决定何时/如何优化运行时类型测试 TypeUsageInfo type_usage_info(T); // 一个类的子类的cid范围,用于is/as的类型检查 HierarchyInfo hierarchy_info(T); // 预编译构造函数以计算信息,例如优化的指令数(用于内联启发法) ClassFinalizer::ClearAllCode(FLAG_use_bare_instructions); PrecompileConstructors(); ClassFinalizer::ClearAllCode(FLAG_use_bare_instructions); // 所有存根都已经生成,它们都共享同一个池。 使用该池来初始化全局对象池, // 以确保存根和此处编译的代码都具有相同的池。 if (FLAG_use_bare_instructions) { // 在这里使用任何存根来获取它的对象池(所有存根在裸指令模式下共享相同的对象池) const Code& code = StubCode::InterpretCall(); const ObjectPool& stub_pool = ObjectPool::Handle(code.object_pool()); global_object_pool_builder()->Reset(); stub_pool.CopyInto(global_object_pool_builder()); //我们有两个需要使用新的全局对象池重新生成的全局代码对象,即 // 大型未命中处理程序代码 和 构建方法提取器代码 MegamorphicCacheTable::ReInitMissHandlerCode( isolate_, global_object_pool_builder()); auto& stub_code = Code::Handle(); stub_code = StubCode::GetBuildMethodExtractorStub(global_object_pool_builder()); I->object_store()->set_build_method_extractor_code(stub_code); stub_code = StubCode::BuildIsolateSpecificNullErrorSharedWithFPURegsStub( global_object_pool_builder()); I->object_store()->set_null_error_stub_with_fpu_regs_stub(stub_code); stub_code = StubCode::BuildIsolateSpecificNullErrorSharedWithoutFPURegsStub( global_object_pool_builder()); I->object_store()->set_null_error_stub_without_fpu_regs_stub(stub_code); stub_code = StubCode::BuildIsolateSpecificStackOverflowSharedWithFPURegsStub( global_object_pool_builder()); I->object_store()->set_stack_overflow_stub_with_fpu_regs_stub(stub_code); stub_code = StubCode::BuildIsolateSpecificStackOverflowSharedWithoutFPURegsStub( global_object_pool_builder()); I->object_store()->set_stack_overflow_stub_without_fpu_regs_stub(stub_code); stub_code = StubCode::BuildIsolateSpecificWriteBarrierWrappersStub( global_object_pool_builder()); I->object_store()->set_write_barrier_wrappers_stub(stub_code); stub_code = StubCode::BuildIsolateSpecificArrayWriteBarrierStub( global_object_pool_builder()); I->object_store()->set_array_write_barrier_stub(stub_code); } CollectDynamicFunctionNames(); // 从C++发生的分配和调用的起点添加为根 AddRoots(); // 将所有以@pragma('vm:entry-point')注释的值添加为根 AddAnnotatedRoots(); //编译前面找到的根作为目标,并逐步添加该目标的调用者,直到达到固定点为止 Iterate(); // 用新的[Type]专用存根替换安装在[Type]上的默认类型测试存根 AttachOptimizedTypeTestingStub(); if (FLAG_use_bare_instructions) { // 生成实际的对象池实例,并将其附加到对象存储。AOT运行时将在dart入口代码存根中使用它。 const auto& pool = ObjectPool::Handle( ObjectPool::NewFromBuilder(*global_object_pool_builder())); I->object_store()->set_global_object_pool(pool); global_object_pool_builder()->Reset(); if (FLAG_print_gop) { THR_Print("Global object pool:\n"); pool.DebugPrint(); } } I->set_compilation_allowed(false); TraceForRetainedFunctions(); DropFunctions(); DropFields(); TraceTypesFromRetainedClasses(); DropTypes(); DropTypeArguments(); // 在删除类之前清除这些类的死实例或者未使用的符号 I->object_store()->set_unique_dynamic_targets(Array::null_array()); Class& null_class = Class::Handle(Z); Function& null_function = Function::Handle(Z); Field& null_field = Field::Handle(Z); I->object_store()->set_future_class(null_class); I->object_store()->set_pragma_class(null_class); I->object_store()->set_pragma_name(null_field); I->object_store()->set_pragma_options(null_field); I->object_store()->set_completer_class(null_class); I->object_store()->set_symbol_class(null_class); I->object_store()->set_compiletime_error_class(null_class); I->object_store()->set_growable_list_factory(null_function); I->object_store()->set_simple_instance_of_function(null_function); I->object_store()->set_simple_instance_of_true_function(null_function); I->object_store()->set_simple_instance_of_false_function(null_function); I->object_store()->set_async_set_thread_stack_trace(null_function); I->object_store()->set_async_star_move_next_helper(null_function); I->object_store()->set_complete_on_async_return(null_function); I->object_store()->set_async_star_stream_controller(null_class); DropMetadata(); DropLibraryEntries(); } DropClasses(); DropLibraries(); BindStaticCalls(); SwitchICCalls(); Obfuscate(); ProgramVisitor::Dedup(); zone_ = NULL; } intptr_t symbols_before = -1; intptr_t symbols_after = -1; intptr_t capacity = -1; if (FLAG_trace_precompiler) { //获取symbol表的统计信息 Symbols::GetStats(I, &symbols_before, &capacity); } Symbols::Compact(); if (FLAG_trace_precompiler) { Symbols::GetStats(I, &symbols_after, &capacity); THR_Print("Precompiled %" Pd " functions,", function_count_); THR_Print(" %" Pd " dynamic types,", class_count_); THR_Print(" %" Pd " dynamic selectors.\n", selector_count_); THR_Print("Dropped %" Pd " functions,", dropped_function_count_); THR_Print(" %" Pd " fields,", dropped_field_count_); THR_Print(" %" Pd " symbols,", symbols_before - symbols_after); THR_Print(" %" Pd " types,", dropped_type_count_); THR_Print(" %" Pd " type arguments,", dropped_typearg_count_); THR_Print(" %" Pd " classes,", dropped_class_count_); THR_Print(" %" Pd " libraries.\n", dropped_library_count_); } } 这个过程比较复杂,其主要工作内容如下: FinalizeAllClasses():确保类层次稳定,因此会先支持CHA分析类层次结构; PrecompileConstructors():预编译构造函数以计算信息,例如优化的指令数(用于内联启发法); StubCode:通过StubCode::InterpretCall得到的code来获取它的对象池,再利用StubCode::BuildXXX()系列方法获取的结果保存在object_store; CollectDynamicFunctionNames():收集动态函数的方法名; AddRoots():从C++发生的分配和调用的起点添加为根; AddAnnotatedRoots():将所有以@pragma(’vm:entry-point’)注释的值添加为根; Iterate(): 这是编译最为核心的地方,编译前面找到的根作为目标,并逐步添加该目标的调用者,直到达到固定点为止; DropXXX(): 调用DropFunctions,DropFields,DropTypes等一系列操作 去掉方法、字段、类、库等; BindStaticCalls():绑定静态调用方法,说明tree-shaker后并非所有的函数都会被编译; SwitchICCalls():已编译所有静态函数,则切到实例调用(instance call)队列,迭代所有对象池; Obfuscate():执行代码混淆操作,并保持混淆map表; ProgramVisitor::Dedup():清理各数据段的重复数据,比如CodeSourceMaps、StackMaps等; Symbols::Compact(): 执行完整的垃圾回收,整理后压缩symbols; 到此Dart_Precompile()过程执行完成。 Dart_Precompile()执行完再回到[小节2.3],再来分别看看产物生成的过程。 iOS:执行Dart_CreateAppAOTSnapshotAsAssembly()方法; Android:执行Dart_CreateAppAOTSnapshotAsBlobs()方法。 三、 iOS快照产物生成 3.1 Dart_CreateAppAOTSnapshotAsAssembly [-> third_party/dart/runtime/vm/dart_api_impl.cc] DART_EXPORT Dart_Handle Dart_CreateAppAOTSnapshotAsAssembly(Dart_StreamingWriteCallback callback, void* callback_data) { #if defined(DART_PRECOMPILER) ... //初始化AssemblyImageWriter对象 AssemblyImageWriter image_writer(T, callback, callback_data, NULL, NULL); uint8_t* vm_snapshot_data_buffer = NULL; uint8_t* isolate_snapshot_data_buffer = NULL; FullSnapshotWriter writer(Snapshot::kFullAOT, &vm_snapshot_data_buffer, &isolate_snapshot_data_buffer, ApiReallocate, &image_writer, &image_writer); //[见小节3.2] writer.WriteFullSnapshot(); //[见小节3.7] image_writer.Finalize(); return Api::Success(); #endif } 创建AssemblyImageWriter对象过程,初始化其成员变量StreamingWriteStream类型的assembly_stream_和Dwarf*类型的dwarf_ assembly_stream_初始化:创建大小等于512KB的buffer_,callback_为StreamingWriteCallback,callback_为snapshot_assembly.S dwarf_初始化:其成员变量stream_指向assembly_stream_; 创建FullSnapshotWriter对象过程,初始化其成员变量kind_等于Snapshot::kFullAOT。vm_snapshot_data_buffer_和isolate_snapshot_data_buffer_分别指向vm_snapshot_data_buffer和isolate_snapshot_data_buffer的地址。 3.2 WriteFullSnapshot [-> third_party/dart/runtime/vm/clustered_snapshot.cc] void FullSnapshotWriter::WriteFullSnapshot() { intptr_t num_base_objects; if (vm_snapshot_data_buffer() != NULL) { //[见小节3.3] num_base_objects = WriteVMSnapshot(); } else { num_base_objects = 0; } if (isolate_snapshot_data_buffer() != NULL) { //[见小节3.6] WriteIsolateSnapshot(num_base_objects); } if (FLAG_print_snapshot_sizes) { OS::Print("VMIsolate(CodeSize): %" Pd "\n", clustered_vm_size_); OS::Print("Isolate(CodeSize): %" Pd "\n", clustered_isolate_size_); OS::Print("ReadOnlyData(CodeSize): %" Pd "\n", mapped_data_size_); OS::Print("Instructions(CodeSize): %" Pd "\n", mapped_text_size_); OS::Print("Total(CodeSize): %" Pd "\n", clustered_vm_size_ + clustered_isolate_size_ + mapped_data_size_ + mapped_text_size_); } } 产物大小的分类来自于FullSnapshotWriter的几个成员变量 clustered_vm_size_:是vm的数据段,包含符号表和stub代码 clustered_isolate_size_:是isolate的数据段,包含object store ReadOnlyData:是由vm和isolate的只读数据段组成 Instructions:是由vm和isolate的代码段组成 3.3 WriteVMSnapshot [-> third_party/dart/runtime/vm/clustered_snapshot.cc] intptr_t FullSnapshotWriter::WriteVMSnapshot() { Serializer serializer(thread(), kind_, vm_snapshot_data_buffer_, alloc_, kInitialSize, vm_image_writer_, /*vm=*/true, profile_writer_); serializer.ReserveHeader(); //预留空间来记录快照buffer的大小 serializer.WriteVersionAndFeatures(true); const Array& symbols = Array::Handle(Dart::vm_isolate()->object_store()->symbol_table()); //写入符号表 [见小节3.3.1] intptr_t num_objects = serializer.WriteVMSnapshot(symbols); serializer.FillHeader(serializer.kind()); //填充头部信息 clustered_vm_size_ = serializer.bytes_written(); if (Snapshot::IncludesCode(kind_)) { //kFullAOT模式满足条件 vm_image_writer_->SetProfileWriter(profile_writer_); //[见小节3.4] vm_image_writer_->Write(serializer.stream(), true); mapped_data_size_ += vm_image_writer_->data_size(); //数据段 mapped_text_size_ += vm_image_writer_->text_size(); //代码段 vm_image_writer_->ResetOffsets(); vm_image_writer_->ClearProfileWriter(); } //集群部分+直接映射的数据部分 vm_isolate_snapshot_size_ = serializer.bytes_written(); return num_objects; } 创建Serializer对象过程,初始化其成员变量WriteStream类型的stream_。VM snapshot的根节点是符号表和stub代码(App-AOT、App-JIT、Core-JIT) serializer通过其成员变量stream_写入如下内容: FillHeader:头部内容 WriteVersionAndFeatures:版本信息 WriteVMSnapshot:符号表 3.3.1 Serializer::WriteVMSnapshot [-> third_party/dart/runtime/vm/clustered_snapshot.cc] intptr_t Serializer::WriteVMSnapshot(const Array& symbols) { NoSafepointScope no_safepoint; //添加虚拟机isolate的基本对象 AddVMIsolateBaseObjects(); //VM snapshot的根节点 入栈,也就是是符号表和stub代码 Push(symbols.raw()); if (Snapshot::IncludesCode(kind_)) { for (intptr_t i = 0; i third_party/dart/runtime/vm/image_snapshot.cc] void ImageWriter::Write(WriteStream* clustered_stream, bool vm) { Thread* thread = Thread::Current(); Zone* zone = thread->zone(); Heap* heap = thread->isolate()->heap(); //处理收集的原始指针,构建以下名称将分配在Dart堆 for (intptr_t i = 0; i SetObjectId(data.insns_->raw(), 0); } for (intptr_t i = 0; i third_party/dart/runtime/vm/image_snapshot.cc] void ImageWriter::WriteROData(WriteStream* stream) { stream->Align(OS::kMaxPreferredCodeAlignment); //32位对齐 //堆页面的起点 intptr_t section_start = stream->Position(); stream->WriteWord(next_data_offset_); // Data length. stream->Align(OS::kMaxPreferredCodeAlignment); //堆页面中对象的起点 for (intptr_t i = 0; i (obj.raw()) - kHeapObjectTag; uword end = start + obj.raw()->HeapSize(); //写有标记和只读位的对象标头 uword marked_tags = obj.raw()->ptr()->tags_; marked_tags = RawObject::OldBit::update(true, marked_tags); marked_tags = RawObject::OldAndNotMarkedBit::update(false, marked_tags); marked_tags = RawObject::OldAndNotRememberedBit::update(true, marked_tags); marked_tags = RawObject::NewBit::update(false, marked_tags); stream->WriteWord(marked_tags); start += sizeof(uword); for (uword* cursor = reinterpret_cast(start); cursor (end); cursor++) { stream->WriteWord(*cursor); } } } 3.5 AssemblyImageWriter::WriteText [-> ]third_party/dart/runtime/vm/image_snapshot.cc] void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) { Zone* zone = Thread::Current()->zone(); //写入头部 const char* instructions_symbol = vm ? "_kDartVmSnapshotInstructions" : "_kDartIsolateSnapshotInstructions"; assembly_stream_.Print(".text\n"); assembly_stream_.Print(".globl %s\n", instructions_symbol); assembly_stream_.Print(".balign %" Pd ", 0\n", VirtualMemory::PageSize()); assembly_stream_.Print("%s:\n", instructions_symbol); //写入头部空白字符,使得指令快照看起来像堆页 intptr_t instructions_length = next_text_offset_; WriteWordLiteralText(instructions_length); intptr_t header_words = Image::kHeaderSize / sizeof(uword); for (intptr_t i = 1; i object_store(); TypeTestingStubNamer tts; intptr_t text_offset = 0; for (intptr_t i = 0; i (data.trampoline_bytes); const auto end = start + data.trampline_length; //写入.quad xxx字符串 text_offset += WriteByteSequence(start, end); delete[] data.trampoline_bytes; data.trampoline_bytes = nullptr; continue; } const intptr_t instr_start = text_offset; const Instructions& insns = *data.insns_; const Code& code = *data.code_; // 1. 写入 头部到入口点 { NoSafepointScope no_safepoint; uword beginning = reinterpret_cast(insns.raw_ptr()); uword entry = beginning + Instructions::HeaderSize(); //ARM64 32位对齐 //指令的只读标记 uword marked_tags = insns.raw_ptr()->tags_; marked_tags = RawObject::OldBit::update(true, marked_tags); marked_tags = RawObject::OldAndNotMarkedBit::update(false, marked_tags); marked_tags = RawObject::OldAndNotRememberedBit::update(true, marked_tags); marked_tags = RawObject::NewBit::update(false, marked_tags); //写入标记 WriteWordLiteralText(marked_tags); beginning += sizeof(uword); text_offset += sizeof(uword); text_offset += WriteByteSequence(beginning, entry); } // 2. 在入口点写入标签 owner = code.owner(); if (owner.IsNull()) { // owner为空,说明是一个常规的stub,其中stub列表定义在stub_code_list.h中的VM_STUB_CODE_LIST const char* name = StubCode::NameOfStub(insns.EntryPoint()); if (name != nullptr) { assembly_stream_.Print("Precompiled_Stub_%s:\n", name); } else { if (name == nullptr) { // isolate专有的stub代码[见小节3.5.1] name = NameOfStubIsolateSpecificStub(object_store, code); } assembly_stream_.Print("Precompiled__%s:\n", name); } } else if (owner.IsClass()) { //owner为Class,说明是该类分配的stub,其中class列表定义在class_id.h中的CLASS_LIST_NO_OBJECT_NOR_STRING_NOR_ARRAY str = Class::Cast(owner).Name(); const char* name = str.ToCString(); EnsureAssemblerIdentifier(const_cast(name)); assembly_stream_.Print("Precompiled_AllocationStub_%s_%" Pd ":\n", name, i); } else if (owner.IsAbstractType()) { const char* name = tts.StubNameForType(AbstractType::Cast(owner)); assembly_stream_.Print("Precompiled_%s:\n", name); } else if (owner.IsFunction()) { //owner为Function,说明是一个常规的dart函数 const char* name = Function::Cast(owner).ToQualifiedCString(); EnsureAssemblerIdentifier(const_cast(name)); assembly_stream_.Print("Precompiled_%s_%" Pd ":\n", name, i); } else { UNREACHABLE(); } #ifdef DART_PRECOMPILER // 创建一个标签用于DWARF if (!code.IsNull()) { const intptr_t dwarf_index = dwarf_->AddCode(code); assembly_stream_.Print(".Lcode%" Pd ":\n", dwarf_index); } #endif { // 3. 写入 入口点到结束 NoSafepointScope no_safepoint; uword beginning = reinterpret_cast(insns.raw_ptr()); uword entry = beginning + Instructions::HeaderSize(); uword payload_size = insns.raw()->HeapSize() - insns.HeaderSize(); uword end = entry + payload_size; text_offset += WriteByteSequence(entry, end); } } FrameUnwindEpilogue(); #if defined(TARGET_OS_LINUX) || defined(TARGET_OS_ANDROID) || \ defined(TARGET_OS_FUCHSIA) assembly_stream_.Print(".section .rodata\n"); #elif defined(TARGET_OS_MACOS) || defined(TARGET_OS_MACOS_IOS) assembly_stream_.Print(".const\n"); #else UNIMPLEMENTED(); #endif //写入数据段 const char* data_symbol = vm ? "_kDartVmSnapshotData" : "_kDartIsolateSnapshotData"; assembly_stream_.Print(".globl %s\n", data_symbol); assembly_stream_.Print(".balign %" Pd ", 0\n", OS::kMaxPreferredCodeAlignment); assembly_stream_.Print("%s:\n", data_symbol); uword buffer = reinterpret_cast(clustered_stream->buffer()); intptr_t length = clustered_stream->bytes_written(); WriteByteSequence(buffer, buffer + length); } 3.5.1 NameOfStubIsolateSpecificStub [[-> ]third_party/dart/runtime/vm/image_snapshot.cc] const char* NameOfStubIsolateSpecificStub(ObjectStore* object_store, const Code& code) { if (code.raw() == object_store->build_method_extractor_code()) { return "_iso_stub_BuildMethodExtractorStub"; } else if (code.raw() == object_store->null_error_stub_with_fpu_regs_stub()) { return "_iso_stub_NullErrorSharedWithFPURegsStub"; } else if (code.raw() == object_store->null_error_stub_without_fpu_regs_stub()) { return "_iso_stub_NullErrorSharedWithoutFPURegsStub"; } else if (code.raw() == object_store->stack_overflow_stub_with_fpu_regs_stub()) { return "_iso_stub_StackOverflowStubWithFPURegsStub"; } else if (code.raw() == object_store->stack_overflow_stub_without_fpu_regs_stub()) { return "_iso_stub_StackOverflowStubWithoutFPURegsStub"; } else if (code.raw() == object_store->write_barrier_wrappers_stub()) { return "_iso_stub_WriteBarrierWrappersStub"; } else if (code.raw() == object_store->array_write_barrier_stub()) { return "_iso_stub_ArrayWriteBarrierStub"; } return nullptr; } 再回到[小节3.1],执行完WriteVMSnapshot()方法,然后执行WriteIsolateSnapshot()方法。 3.6 WriteIsolateSnapshot [-> third_party/dart/runtime/vm/clustered_snapshot.cc] void FullSnapshotWriter::WriteIsolateSnapshot(intptr_t num_base_objects) { Serializer serializer(thread(), kind_, isolate_snapshot_data_buffer_, alloc_, kInitialSize, isolate_image_writer_, /*vm=*/false, profile_writer_); ObjectStore* object_store = isolate()->object_store(); serializer.ReserveHeader(); serializer.WriteVersionAndFeatures(false); // Isolate快照的根为object store serializer.WriteIsolateSnapshot(num_base_objects, object_store); serializer.FillHeader(serializer.kind()); clustered_isolate_size_ = serializer.bytes_written(); if (Snapshot::IncludesCode(kind_)) { isolate_image_writer_->SetProfileWriter(profile_writer_); //[见小节3.4] isolate_image_writer_->Write(serializer.stream(), false); #if defined(DART_PRECOMPILER) isolate_image_writer_->DumpStatistics(); #endif mapped_data_size_ += isolate_image_writer_->data_size(); mapped_text_size_ += isolate_image_writer_->text_size(); isolate_image_writer_->ResetOffsets(); isolate_image_writer_->ClearProfileWriter(); } // 集群部分 + 直接映射的数据部分 isolate_snapshot_size_ = serializer.bytes_written(); } 3.7 AssemblyImageWriter::Finalize [-> third_party/dart/runtime/vm/image_snapshot.cc] void AssemblyImageWriter::Finalize() { #ifdef DART_PRECOMPILER dwarf_->Write(); #endif } 3.7.1 Dwarf.Write [-> third_party/dart/runtime/vm/dwarf.h] class Dwarf : public ZoneAllocated { void Write() { WriteAbbreviations(); WriteCompilationUnit(); WriteLines(); } } Dwarf数据采用数的形式,其节点称为DIE,每个DIE均以缩写代码开头,并且该缩写描述了该DIE的属性及其表示形式。 四、 Android快照产物生成 4.1 Dart_CreateAppAOTSnapshotAsBlobs [-> third_party/dart/runtime/vm/dart_api_impl.cc] DART_EXPORT Dart_Handle Dart_CreateAppAOTSnapshotAsBlobs(uint8_t** vm_snapshot_data_buffer, intptr_t* vm_snapshot_data_size, uint8_t** vm_snapshot_instructions_buffer, intptr_t* vm_snapshot_instructions_size, uint8_t** isolate_snapshot_data_buffer, intptr_t* isolate_snapshot_data_size, uint8_t** isolate_snapshot_instructions_buffer, intptr_t* isolate_snapshot_instructions_size, const uint8_t* shared_data, const uint8_t* shared_instructions) { #if defined(DART_PRECOMPILER) DARTSCOPE(Thread::Current()); API_TIMELINE_DURATION(T); Isolate* I = T->isolate(); CHECK_NULL(vm_snapshot_data_buffer); CHECK_NULL(vm_snapshot_data_size); CHECK_NULL(vm_snapshot_instructions_buffer); CHECK_NULL(vm_snapshot_instructions_size); CHECK_NULL(isolate_snapshot_data_buffer); CHECK_NULL(isolate_snapshot_data_size); CHECK_NULL(isolate_snapshot_instructions_buffer); CHECK_NULL(isolate_snapshot_instructions_size); const void* shared_data_image = NULL; if (shared_data != NULL) { shared_data_image = Snapshot::SetupFromBuffer(shared_data)->DataImage(); } const void* shared_instructions_image = shared_instructions; TIMELINE_DURATION(T, Isolate, "WriteAppAOTSnapshot"); BlobImageWriter vm_image_writer(T, vm_snapshot_instructions_buffer, ApiReallocate, 2 * MB, nullptr, nullptr, nullptr); BlobImageWriter isolate_image_writer(T, isolate_snapshot_instructions_buffer, ApiReallocate, 2 * MB , shared_data_image, shared_instructions_image, nullptr); FullSnapshotWriter writer(Snapshot::kFullAOT, vm_snapshot_data_buffer, isolate_snapshot_data_buffer, ApiReallocate, &vm_image_writer, &isolate_image_writer); //[见小节3.1] writer.WriteFullSnapshot(); *vm_snapshot_data_size = writer.VmIsolateSnapshotSize(); *vm_snapshot_instructions_size = vm_image_writer.InstructionsBlobSize(); *isolate_snapshot_data_size = writer.IsolateSnapshotSize(); *isolate_snapshot_instructions_size = isolate_image_writer.InstructionsBlobSize(); return Api::Success(); #endif } 该方法主要功能是将snapshot写入buffer缓存: vm_snapshot_data_buffer vm_snapshot_instructions_buffer isolate_snapshot_data_buffer isolate_snapshot_instructions_buffer 再下一步将这些数据写入文件。 附录 third_party/dart/runtime/ - bin/gen_snapshot.cc - vm/dart_api_impl.cc - vm/compiler/aot/precompiler.cc
一、概述 书接上文源码解读Flutter run机制的第四节 flutter build aot命令将dart源码编译成AOT产物,其主要工作为前端编译器frontend_server和机器码生成,本文先介绍前端编译器frontend_server的工作原理。 1.1 frontend_server命令 KernelCompiler.compile()过程等价于如下命令: // 该frontend_server命令 同时适用于Android和iOS flutter/bin/cache/dart-sdk/bin/dart \ flutter/bin/cache/artifacts/engine/darwin-x64/frontend_server.dart.snapshot \ --sdk-root flutter/bin/cache/artifacts/engine/common/flutter_patched_sdk/ \ --strong \ --target=flutter \ --aot --tfa \ -Ddart.vm.product=true \ --packages .packages \ --output-dill /build/app/intermediates/flutter/release/app.dill \ --depfile /build/app/intermediates/flutter/release/kernel_compile.d \ --"package" /lib/main.dart 可见,通过dart虚拟机启动frontend_server.dart.snapshot,将dart代码转换成app.dill形式的kernel文件。frontend_server.dart.snapshot入口位于Flutter引擎中的 flutter/frontend_server/bin/starter.dart。 1.2 frontend参数表 前端编译器的可选参数: 参数 说明 默认值 aot 在AOT模式下运行编译器(启用整个程序转换) false tfa 在AOT模式下启用全局类型流分析和相关转换 false train 通过示例命令行运行以生成快照 false incremental 以增量模式运行编译器 flase link-platform 批处理模式,平台kernel文件链接到结果的内核文件 true embed-source-text 源码加入到生成的dill文件,便于得到用于调试的堆栈信息 true track-widget-creation 运行内核转换器来跟踪widgets创建的位置 false strong 已过时flags true import-dill 从已存在的dill文件中引入库 null output-dill 将生成的dill文件输出路径 null output-incremental-dill 将生成的增量dill文件输出路径 null depfile 仅用于批量,输出Ninja的depfile packages 用于编译的.packages文件 null sdk-root SDK根目录的路径 ../../out/android_debug/flutter_patched_sdk target 确定哪些核心库可用,可取值vm、flutter、flutter_runner、dart_runner vm 增量模式运行编译器应该能加快编译速度 track-widget-creation、aot、tfa参数的使用场景 1.3 frontend_server执行流程图 (1)点击查看大图 frontend_server前端编译器将dart代码转换为AST,并生成app.dill文件,其中bytecode生成过程默认是关闭的。 (2)点击查看大图 Component的成员变量: uriToSource的类型为Map ,用于从源文件URI映射到行开始表和源代码。给定一个源文件URI和该文件中的偏移量,就可以转换为该文件中line:column的位置。 二、 源码解读frontend_server BuildAotCommand.runCommand AOTSnapshotter.compileKernel KernelCompiler.compile frontend_server命令 2.1 starter.main [-> flutter/frontend_server/bin/starter.dart] void main(List args) async { final int exitCode = await starter(args); ... } 2.2 server.starter [-> flutter/frontend_server/lib/server.dart] Future starter( List args, { frontend.CompilerInterface compiler, Stream> input, StringSink output, }) async { ... //解析参数 [见小节2.2.1] ArgResults options = frontend.argParser.parse(args); //创建前端编译器实例对象 compiler ??= new _FlutterFrontendCompiler(output, trackWidgetCreation: options['track-widget-creation'], unsafePackageSerialization: options['unsafe-package-serialization']); if (options.rest.isNotEmpty) { //解析命令行的剩余参数 [见小节2.3] return await compiler.compile(options.rest[0], options) ? 0 : 254; } ... } 该方法主要工作: 解析KernelCompiler.compile()方法中传递过来的参数,参数表小节[1.2] 创建前端编译器实例对象_FlutterFrontendCompiler; 执行编译操作; 2.3 _FlutterFrontendCompiler.compile [-> flutter/frontend_server/lib/server.dart] class _FlutterFrontendCompiler implements frontend.CompilerInterface{ final frontend.CompilerInterface _compiler; _FlutterFrontendCompiler(StringSink output, {bool trackWidgetCreation: false, bool unsafePackageSerialization}) : //创建编译器对象 _compiler = new frontend.FrontendCompiler(output, transformer: trackWidgetCreation ? new WidgetCreatorTracker() : null, unsafePackageSerialization: unsafePackageSerialization); Future compile(String filename, ArgResults options, {IncrementalCompiler generator}) async { // filename是入口文件名 [见小节2.4] return _compiler.compile(filename, options, generator: generator); } } 创建前端编译器实例对象_FlutterFrontendCompiler,其内部有一个重要的成员变量frontend.FrontendCompiler,该对象主要是在FrontendCompile功能的基础之上编译中添加了一个widgetCreatorTracker的内核转换器,所以核心工作都是交由FrontendCompiler来执行。 2.4 FrontendCompiler.compile [-> third_party/dart/pkg/vm/lib/frontend_server.dart] class FrontendCompiler implements CompilerInterface { Future compile(String entryPoint, ArgResults options, {IncrementalCompiler generator,}) async { _options = options; _fileSystem = createFrontEndFileSystem(options['filesystem-scheme'], options['filesystem-root']); //源码入口函数名,也就是lib/main.dart _mainSource = _getFileOrUri(entryPoint); _kernelBinaryFilenameFull = _options['output-dill'] ?? '$entryPoint.dill'; _kernelBinaryFilenameIncremental = _options['output-incremental-dill'] ?? (_options['output-dill'] != null ? '${_options['output-dill']}.incremental.dill' : '$entryPoint.incremental.dill'); _kernelBinaryFilename = _kernelBinaryFilenameFull; _initializeFromDill = _options['initialize-from-dill'] ?? _kernelBinaryFilenameFull; final String boundaryKey = new Uuid().generateV4(); _outputStream.writeln('result $boundaryKey'); final Uri sdkRoot = _ensureFolderPath(options['sdk-root']); final String platformKernelDill = options['platform'] ?? 'platform_strong.dill'; ... Component component; if (options['incremental']) { _compilerOptions = compilerOptions; setVMEnvironmentDefines(environmentDefines, _compilerOptions); _compilerOptions.omitPlatform = false; _generator = generator ?? _createGenerator(new Uri.file(_initializeFromDill)); await invalidateIfInitializingFromDill(); component = await _runWithPrintRedirection(() => _generator.compile()); } else { ... // [见小节2.5] component = await _runWithPrintRedirection(() => compileToKernel( _mainSource, compilerOptions, aot: options['aot'], useGlobalTypeFlowAnalysis: options['tfa'], environmentDefines: environmentDefines)); } if (component != null) { if (transformer != null) { transformer.transform(component); } //[见小节2.10] 写入dill文件 await writeDillFile(component, _kernelBinaryFilename, filterExternal: importDill != null); await _outputDependenciesDelta(component); final String depfile = options['depfile']; if (depfile != null) { await writeDepfile(compilerOptions.fileSystem, component, _kernelBinaryFilename, depfile); } _kernelBinaryFilename = _kernelBinaryFilenameIncremental; } return errors.isEmpty; } } 该方法主要功能: 执行compileToKernel,将dart转换为kernel文件,也就是中间语言文件; 再将中间数据写入app.dill文件 2.5 compileToKernel [-> third_party/dart/pkg/vm/lib/kernel_front_end.dart] Future compileToKernel(Uri source, CompilerOptions options, {bool aot: false, bool useGlobalTypeFlowAnalysis: false, Map environmentDefines, bool genBytecode: false, bool emitBytecodeSourcePositions: false, bool emitBytecodeAnnotations: false, bool dropAST: false, bool useFutureBytecodeFormat: false, bool enableAsserts: false, bool enableConstantEvaluation: true, bool useProtobufTreeShaker: false}) async { //替代错误处理程序以检测是否存在编译错误 final errorDetector = new ErrorDetector(previousErrorHandler: options.onDiagnostic); options.onDiagnostic = errorDetector; setVMEnvironmentDefines(environmentDefines, options); //将dart代码转换为component对象 [见小节2.6] final component = await kernelForProgram(source, options); if (aot && component != null) { // 执行全局转换器 [见小节2.7] await _runGlobalTransformations( source, options, component, useGlobalTypeFlowAnalysis, environmentDefines, enableAsserts, enableConstantEvaluation, useProtobufTreeShaker, errorDetector); } if (genBytecode && !errorDetector.hasCompilationErrors && component != null) { //生成字节码,genBytecode默认为false,不执行该操作 [见小节2.8] await runWithFrontEndCompilerContext(source, options, component, () { generateBytecode(component, emitSourcePositions: emitBytecodeSourcePositions, emitAnnotations: emitBytecodeAnnotations, useFutureBytecodeFormat: useFutureBytecodeFormat, environmentDefines: environmentDefines); }); if (dropAST) { new ASTRemover(component).visitComponent(component); } } //恢复错误处理程序 options.onDiagnostic = errorDetector.previousErrorHandler; return component; } 该方法主要功能: kernelForProgram:将dart代码转换为component对象; _runGlobalTransformations:执行全局转换器; generateBytecode:默认genBytecode为false,AST不生成kernel字节码 2.6 kernelForProgram [-> third_party/dart/pkg/front_end/lib/src/api_prototype/kernel_generator.dart] Future kernelForProgram( Uri source, CompilerOptions options) async { return (await kernelForProgramInternal(source, options)); } Future kernelForProgramInternal( Uri source, CompilerOptions options, {bool retainDataForTesting: false}) async { var pOptions = new ProcessedOptions(options: options, inputs: [source]); return await CompilerContext.runWithOptions(pOptions, (context) async { //生成component [见小节2.6.1] var component = (await generateKernelInternal())?.component; if (component == null) return null; // 输入source应该是包含main方法的脚步,否则将报告错误 if (component.mainMethod == null) { context.options.report( messageMissingMain.withLocation(source, -1, noLength), Severity.error); return null; } return component; }); } 该方法的主要功能是将整个dart程序代码生成component对象。编译整个程序,生成程序的内核表示,该程序的主库位于给定的源码。 给定包含main方法的文件的Uri,通过该函数的import, export, part声明来发现整个程序,并将结果转换为Dart Kernel格式。 需要注意的是,当[options]中的compileSdk=true,则生成的组件将包含SDK代码。 Component的成员变量libraries,记录所有的lib库,包括app源文件、package以及三方库。每个Library对象会有Class、Field、procedure等组成。 2.6.1 generateKernelInternal [-> third_party/dart/pkg/front_end/lib/src/kernel_generator_impl.dart] Future generateKernelInternal( {bool buildSummary: false, bool buildComponent: true, bool truncateSummary: false}) async { var options = CompilerContext.current.options; var fs = options.fileSystem; Loader sourceLoader; return withCrashReporting(() async { UriTranslator uriTranslator = await options.getUriTranslator(); var dillTarget = new DillTarget(options.ticker, uriTranslator, options.target); ... await dillTarget.buildOutlines(); //创建KernelTarget var kernelTarget = new KernelTarget(fs, false, dillTarget, uriTranslator); sourceLoader = kernelTarget.loader; kernelTarget.setEntryPoints(options.inputs); Component summaryComponent = await kernelTarget.buildOutlines(nameRoot: nameRoot); if (buildSummary) { ... } Component component; if (buildComponent) { //[见小节2.6.2] component = await kernelTarget.buildComponent(verify: options.verify); } ... return new InternalCompilerResult( summary: summary, component: component, classHierarchy: includeHierarchyAndCoreTypes ? kernelTarget.loader.hierarchy : null, coreTypes: includeHierarchyAndCoreTypes ? kernelTarget.loader.coreTypes : null, deps: new List.from(CompilerContext.current.dependencies), kernelTargetForTesting: retainDataForTesting ? kernelTarget : null); }, () => sourceLoader?.currentUriForCrashReporting ?? options.inputs.first); } 2.6.2 buildComponent [-> third_party/dart/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart] class KernelTarget extends TargetImplementation { Component component; //成员变量--组件 Future buildComponent({bool verify: false}) async { if (loader.first == null) return null; return withCrashReporting(() async { //[见小节2.6.3] await loader.buildBodies(); finishClonedParameters(); loader.finishDeferredLoadTearoffs(); loader.finishNoSuchMethodForwarders(); List myClasses = collectMyClasses(); loader.finishNativeMethods(); loader.finishPatchMethods(); finishAllConstructors(myClasses); runBuildTransformations(); if (verify) this.verify(); installAllComponentProblems(loader.allComponentProblems); return component; }, () => loader?.currentUriForCrashReporting); } } KernelTarget的component记录整个dart代码的各种信息。 2.6.3 buildBodies [-> third_party/dart/pkg/front_end/lib/src/fasta/loader.dart] Future buildBodies() async { for (LibraryBuilder library in builders.values) { if (library.loader == this) { currentUriForCrashReporting = library.uri; //[见小节2.6.4] await buildBody(library); } } currentUriForCrashReporting = null; logSummary(templateSourceBodySummary); } 此处的loader为SourceLoader,是在KernelTarget对象创建过程初始化的。 2.6.4 buildBody [-> third_party/dart/pkg/front_end/lib/src/fasta/source/source_loader.dart] class SourceLoader extends Loader { Future buildBody(LibraryBuilder library) async { if (library is SourceLibraryBuilder) { //词法分析 Token tokens = await tokenize(library, suppressLexicalErrors: true); DietListener listener = createDietListener(library); DietParser parser = new DietParser(listener); //语法分析 parser.parseUnit(tokens); for (SourceLibraryBuilder part in library.parts) { if (part.partOfLibrary != library) { // part部分包含在多个库中,此处跳过 continue; } Token tokens = await tokenize(part); if (tokens != null) { listener.uri = part.fileUri; listener.partDirectiveIndex = 0; parser.parseUnit(tokens); } } } } } 该方法主要工作: 词法分析tokenize:对库中dart源码,根据一定的词法规则解析成词法单元tokens; 语法分析parser:对tokens根据Dart语法规则解析成抽象语法树; 说明,这个过程采用两次标记源文件,以保持较低的内存使用率。 这是第二次,第一次是在上面的[buildOutline]中,所以这抑制词法错误。 2.7 _runGlobalTransformations [-> third_party/dart/pkg/vm/lib/kernel_front_end.dart] Future _runGlobalTransformations( Uri source, CompilerOptions compilerOptions, Component component, bool useGlobalTypeFlowAnalysis, Map environmentDefines, bool enableAsserts, bool enableConstantEvaluation, bool useProtobufTreeShaker, ErrorDetector errorDetector) async { if (errorDetector.hasCompilationErrors) return; final coreTypes = new CoreTypes(component); _patchVmConstants(coreTypes); //mixin应用在前端创建mixin应用时,所有后端(以及从一开始就进行的所有转换)能都受益于mixin重复数据删除。 //AOT除外, JIT构建情况下,都需要运行此转换 mixin_deduplication.transformComponent(component); if (enableConstantEvaluation) { await _performConstantEvaluation(source, compilerOptions, component, coreTypes, environmentDefines, enableAsserts); if (errorDetector.hasCompilationErrors) return; } if (useGlobalTypeFlowAnalysis) { globalTypeFlow.transformComponent( compilerOptions.target, coreTypes, component); } else { devirtualization.transformComponent(coreTypes, component); no_dynamic_invocations_annotator.transformComponent(component); } if (useProtobufTreeShaker) { if (!useGlobalTypeFlowAnalysis) { throw 'Protobuf tree shaker requires type flow analysis (--tfa)'; } protobuf_tree_shaker.removeUnusedProtoReferences( component, coreTypes, null); globalTypeFlow.transformComponent( compilerOptions.target, coreTypes, component); } // 避免通过从平台文件读取重新计算CSA void ignoreAmbiguousSupertypes(cls, a, b) {} final hierarchy = new ClassHierarchy(component, onAmbiguousSupertypes: ignoreAmbiguousSupertypes); call_site_annotator.transformLibraries( component, component.libraries, coreTypes, hierarchy); // 不确定gen_snapshot是否要进行混淆处理,但是如果这样做,则需要混淆处理禁止。 obfuscationProhibitions.transformComponent(component, coreTypes); } 执行混淆等转换工作 2.8 runWithFrontEndCompilerContext [-> third_party/dart/pkg/vm/lib/kernel_front_end.dart] Future runWithFrontEndCompilerContext(Uri source, CompilerOptions compilerOptions, Component component, T action()) async { final processedOptions = new ProcessedOptions(options: compilerOptions, inputs: [source]); //在上下文中运行,则可以获取uri源的tokens return await CompilerContext.runWithOptions(processedOptions, (CompilerContext context) async { // 为了使fileUri / fileOffset->行/列映射,则需要预填充映射。 context.uriToSource.addAll(component.uriToSource); //此处action对应的是generateBytecode()方法 [见小节2.8.1] return action(); }); } generateBytecode BytecodeGenerator.visitLibrary(Library node) visitList(node.procedures, BytecodeGenerator); Procedure.accept(BytecodeGenerator); BytecodeGenerator.visitProcedure(Procedure); BytecodeGenerator.defaultMember(Procedure) _genxxx asm.emitPush third_party/dart/pkg/vm/lib/bytecode/dbc.dart 中定义很多指令 2.8.1 generateBytecode [-> third_party/dart/pkg/vm/lib/bytecode/gen_bytecode.dart] void generateBytecode( ast.Component component, { bool emitSourcePositions: false, bool emitAnnotations: false, bool omitAssertSourcePositions: false, bool useFutureBytecodeFormat: false, Map environmentDefines: const {}, ErrorReporter errorReporter, List libraries, }) { final coreTypes = new CoreTypes(component); void ignoreAmbiguousSupertypes(Class cls, Supertype a, Supertype b) {} final hierarchy = new ClassHierarchy(component, onAmbiguousSupertypes: ignoreAmbiguousSupertypes); final typeEnvironment = new TypeEnvironment(coreTypes, hierarchy); final constantsBackend = new VmConstantsBackend(coreTypes); final errorReporter = new ForwardConstantEvaluationErrors(); //从component获取libraries libraries ??= component.libraries; //创建字节码生成器对象 final bytecodeGenerator = new BytecodeGenerator( component, coreTypes, hierarchy, typeEnvironment, constantsBackend, environmentDefines, emitSourcePositions, emitAnnotations, omitAssertSourcePositions, useFutureBytecodeFormat, errorReporter); for (var library in libraries) { //[见小节2.8.2] bytecodeGenerator.visitLibrary(library); } } 遍历component中的所有libraries。 2.8.2 visitLibrary [-> third_party/dart/pkg/vm/lib/bytecode/gen_bytecode.dart] class BytecodeGenerator extends RecursiveVisitor { visitLibrary(Library node) { if (node.isExternal) { return; } //对于class的visit会调用到下方的visitClass visitList(node.classes, this); //初始化fieldDeclarations和functionDeclarations来记录类的字段和方法 startMembers(); // [见小节2.8.3] visitList(node.procedures, this); visitList(node.fields, this); endMembers(node); } visitClass(Class node) { startMembers(); visitList(node.constructors, this); visitList(node.procedures, this); visitList(node.fields, this); endMembers(node); } } 该方法主要功能: 通过visitList来访问库中的classes,procedures,fields。 先访问类中的构造函数constructors、方法procedures以及字段fields; 再访问库中不属于任何类的一些方法和字段; fieldDeclarations和functionDeclarations来记录类的字段和方法,最终保存在bytecodeComponent的成员变量members; 2.8.3 visitList [-> third_party/dart/pkg/kernel/lib/ast.dart] void visitList(List nodes, Visitor visitor) { for (int i = 0; i third_party/dart/pkg/kernel/lib/ast.dart] class Procedure extends Member { accept(MemberVisitor v) => v.visitProcedure(this); } class Field extends Member { R accept(MemberVisitor v) => v.visitField(this); } class Constructor extends Member { R accept(MemberVisitor v) => v.visitConstructor(this); } 此处的v是BytecodeGenerator,而BytecodeGenerator间接继承于TreeVisitor,在TreeVisitor由大量的visitXXX()方法,最终都是调用到defaultMember(),如下所示。 class TreeVisitor { // [见小节2.8.5] R visitConstructor(Constructor node) => defaultMember(node); R visitProcedure(Procedure node) => defaultMember(node); R visitField(Field node) => defaultMember(node); } 2.8.5 defaultMember [-> third_party/dart/pkg/vm/lib/bytecode/gen_bytecode.dart] defaultMember(Member node) { // 当该方法表示重定向工厂构造函数,并且没有可运行的主体,则直接返回 if (node is Procedure && node.isRedirectingFactoryConstructor) { return; } try { bool hasCode = false; start(node); //字段类型 if (node is Field) { if (hasInitializerCode(node)) { hasCode = true; if (node.isConst) { _genPushConstExpr(node.initializer); } else { _generateNode(node.initializer); } _genReturnTOS(); } //方法类型 } else if ((node is Procedure && !node.isRedirectingFactoryConstructor) || (node is Constructor)) { if (!node.isAbstract) { hasCode = true; if (node is Constructor) { _genConstructorInitializers(node); } if (node.isExternal) { final String nativeName = getExternalName(node); if (nativeName != null) { _genNativeCall(nativeName); } else { asm.emitPushNull(); } } else { _generateNode(node.function?.body); // 如果无法访问此字节码,则BytecodeAssembler会将其消除。 asm.emitPushNull(); } _genReturnTOS(); } } else { throw 'Unexpected member ${node.runtimeType} $node'; } end(node, hasCode); } on BytecodeLimitExceededException { // 不生成字节码,回滚到内核语法树AST hasErrors = true; end(node, false); } } 该方法主要功能是 根据node类型:字段、方法或者构造方法,则生成相应的汇编指令。 这里会有很多_genXXX()方法,最终是调用asm.emitXXX()方法, 此处的asm的数据类型为BytecodeAssembler。 接下来以emitPushNull为例子,继续往下说。 2.8.6 emitPushNull [-> third_party/dart/pkg/vm/lib/bytecode/assembler.dart] class BytecodeAssembler { final List bytecode = new List(); final Uint32List _encodeBufferIn; final Uint8List _encodeBufferOut; void emitPushNull() { emitWord(_encode0(Opcode.kPushNull)); } void emitWord(int word) { if (isUnreachable) { return; } _encodeBufferIn[0] = word; //opcode写入_encodeBufferIn bytecode.addAll(_encodeBufferOut); } //将操作码转换整型 int _encode0(Opcode opcode) => _uint8(opcode.index); ... } 可见,所有的字节码信息最终都写入到BytecodeAssembler的bytecode列表。另外,Opcode操作码位于dbc.dart,里面定义了各种操作码。 2.9 writeDillFile [-> third_party/dart/pkg/vm/lib/frontend_server.dart] writeDillFile(Component component, String filename, {bool filterExternal: false}) async { final IOSink sink = new File(filename).openWrite(); final BinaryPrinter printer = filterExternal ? new LimitedBinaryPrinter( sink, (lib) => !lib.isExternal, true /* excludeUriToSource */) : printerFactory.newBinaryPrinter(sink); component.libraries.sort((Library l1, Library l2) { return "${l1.fileUri}".compareTo("${l2.fileUri}"); }); component.computeCanonicalNames(); for (Library library in component.libraries) { library.additionalExports.sort((Reference r1, Reference r2) { return "${r1.canonicalName}".compareTo("${r2.canonicalName}"); }); } if (unsafePackageSerialization == true) { writePackagesToSinkAndTrimComponent(component, sink); } //[见小节2.9.1] printer.writeComponentFile(component); await sink.close(); } 再回到[小节2.4],执行完compileToKernel()后开始执行writeDillFile,该方法主要功能便是将component内容写入app.dill文件。 component:是指compileToKernel()方法执行后得到的,记录dart代码中类、方法、字段等所有相关信息 filename:是指前面传递–output-dill参数值,也就是app.dill 2.9.1 writeComponentFile [-> third_party/dart/pkg/kernel/lib/binary/ast_to_binary.dart] void writeComponentFile(Component component) { computeCanonicalNames(component); final componentOffset = getBufferOffset(); writeUInt32(Tag.ComponentFile); writeUInt32(Tag.BinaryFormatVersion); writeListOfStrings(component.problemsAsJson); indexLinkTable(component); _collectMetadata(component); if (_metadataSubsections != null) { // 将asm.bytecode写入文件 _writeNodeMetadataImpl(component, componentOffset); } libraryOffsets = []; CanonicalName main = getCanonicalNameOfMember(component.mainMethod); if (main != null) { checkCanonicalName(main); } writeLibraries(component); writeUriToSource(component.uriToSource); writeLinkTable(component); _writeMetadataSection(component); writeStringTable(stringIndexer); writeConstantTable(_constantIndexer); writeComponentIndex(component, component.libraries); _flush(); } 这便完成的kernel编译以及文件生成过程。 附录 本文相关源码flutter engine flutter/frontend_server/ - bin/starter.dart - lib/server.dart third_party/dart/pkg/ - vm/lib/ - frontend_server.dart - kernel_front_end.dart - bytecode/gen_bytecode.dart - bytecode/assembler.dart - front_end/lib/ - src/api_prototype/kernel_generator.dart - src/kernel_generator_impl.dart - src/fasta/kernel/kernel_target.dart - src/fasta/loader.dart - src/fasta/source/source_loader.dart - kernel/lib/ - ast.dart - binary/ast_to_binary.dart
一、解读flutter run命令 1.1 初识flutter run 1.1.1 IDE运行 编写完flutter代码后,一定离不开运行flutter应用。比如Android Studio可点击如下按钮来执行 该命令默认是采用debug模式,如果需要运行release模式,可以在IDE选择中的Run->Configurations的Additional arguments里面加上–release参数 1.1.2 命令行运行 既然运行应用是通过调用flutter run命令该命令对Android或者iOS设备是通用的,那么下面直接用命令方式来运行。 1)flutter run命令用于编译打包生成APP,然后安装到已连接设备上,并启动运行该APP的过程。 以Android为例,利用gradle来编译打包,最终apk产物位于/build/app/outputs/apk/debug/app-debug.apk。当flutter run命令后面不带任何参数默认采用的是debug模式,从上图可以看到APP右上角会带有DEBUG标识,对于非DEBUG模式则右上角不会有任何标识。当需要运行release模式,可运行命令:flutter run –release。 2)当调试性能(需要用到timeline),且修改本地Flutter引擎代码,则采用profile模式,运行命令: flutter run --profile --disable-service-auth-codes --local-engine-src-path=/engine/src --local-engine android_profile 从上图可以看出这是运行在Android设备上的profile模式,利用Gradle来构建APK,位于工程根目录下/build/app/outputs/apk/profile/app-profile.apk,安装到手机后并通过am start来启动该应用。对于Profile模式,启动Observatory调试器,可通过127.0.0.1:xxx地址,打开网页版性能分析工具Observatory,其中包含有timeline工具,类似于Android的systrace。 1.2 解读flutter run参数 1.2.1 参数表 通过前面会发现,flutter run后面可以跟不同的参数[arguments],具体有哪些参数如下所示: arguments 说明 –debug 调试版本,这是默认模式 –profile profile版本 –release 发布版本 –target-platform 指定app运行的目标平台,比如android-arm/android-arm64,iOS平台不可用 –target= 主入口,默认值lib/main.dart –observatory-port 指定observatory端口,默认为0(随机生成可用端口) –disable-service-auth-codes 关闭observatory服务鉴权 –trace-startup 跟踪应用启动/退出,并保存trace到文件 –trace-skia 跟踪skia,用于调试GPU线程 –trace-systrace 转为systrace,适用于Android/Fuchsia –dump-skp-on-shader-compilation 转储触发着色器编译的skp,默认关闭 –verbose-system-logs 包括来自flutter引擎的详细日志记录 –enable-software-rendering 开启软件渲染,默认采用OpenGL或者Vulkan –skia-deterministic-rendering 确定性采用skia渲染 –no-hot 可关闭热重载,默认是开启 –start-paused 应用启动后暂停 –local-engine-src-path 指定本地引擎源码路径,比如xxx/engine/src –local-engine 指定本地引擎类型,比如android_profile 对于flutter 1.5及以上的版本,抓取timeline报错的情况下,可采用以下两个方案之一: //方案1:关闭鉴权 flutter run --disable-service-auth-codes //方案2:对于已安装应用,直接运行 adb shell am start -a android.intent.action.RUN -f 0x20000000 --ez enable-background-compilation true --ez enable-dart-profiling true --ez disable-service-auth-codes true --ez trace-skia true com.gityuan.flutterdemo/.MainActivity 如果不确定该应用的activity名,可以通过以下命令获取: adb shell dumpsys SurfaceFlinger --list //方式一 adb shell dumpsys activity a -p io.flutter.demo.gallery //方式二 1.2.2 gradle参数说明 flutter run构建应用的过程,对于Android用到了gradle,下面列举gradle的参数。 参数 说明 PlocalEngineOut 引擎产物 Ptarget 取值lib/main.dart Ptrack-widget-creation 默认为false Pcompilation-trace-file Ppatch Pextra-front-end-options Pextra-gen-snapshot-options Pfilesystem-roots Pfilesystem-scheme Pbuild-shared-library 是否采取共享库 Ptarget-platform 目标平台 = 1.2.3 build aot参数说明 gradle参数说明会传递到build aot过程,其对应参数说明: -output-dir:指定aot产物输出路径,缺省默认等于“build/aot”; -target:指定应用的主函数,缺省默认等于“lib/main.dart”; -target-platform:指定目标平台,可取值有android-arm,android-arm64,android-x64, android-x86,ios, darwin-linux_x64, linux-x64,web; -ios-arch:指定ios架构类型,可取值有arm64,armv7,仅用于iOS; -build-shared-library:指定是否构建共享库,仅用于Android;iOS强制为false; -release:指定编译模式,可取值有debug, profile, release, dynamicProfile, dynamicRelease; -extra-front-end-options:指定用于编译kernel的可选参数 –extra-gen-snapshot-options:指定用于构建AOT快照的可选参数 也就是说执行flutter build aot必须指定的参数是target-platform和release参数。 1.3 AOT产物命令 产物生成分为Android和iOS产物 Android AOT产物/build/app/intermediates/flutter/release/目录,最终安装到Android手机的是/build/app/outputs/release/app-release.apk iOS AOT产物位于build/aot目录,最终安装到iOS手机是build/ios/iphoneos/Runner.app 1.3.1 Android AOT产物生成命令 // build aot命令 flutter build aot \ --suppress-analytics \ --quiet \ --target=lib/main.dart \ --output-dir=build/app/intermediates/flutter/release \ --target-platform=android-arm \ --release \ --extra-gen-snapshot-options="--print-snapshot-sizes" 1.3.2 iOS AOT产物生成命令 // build aot命令 flutter build aot \ --suppress-analytics \ --target=lib/main.dart \ --output-dir=build/aot \ --target-platform=ios \ --ios-arch=arm64 \ --release \ --extra-gen-snapshot-options="--print-snapshot-sizes" 如果需要同时编译32位和64位,则可以设置参数–ios-arch=armv7,arm64。 1.4 flutter run原理说明 flutter run过程涉及多个flutter相关命令,其包含关系如下所示: 图解: flutter命令的整个过程位于目录flutter/packages/flutter_tools/,对于flutter run命令核心功能包括以下几部分: flutter build apk:通过gradle来构建APK,由以下两部分组成: flutter build aot,分为如下两个核心过程,该过程详情见下一篇文章 frontend_server前端编译器生成kernel文件 gen_snapshot来编译成AOT产物 - flutter build bundle,将相关文件放入flutter_assets目录 通过adb install来安装APK 通过adb am start来启动应用 整个flutter run的执行流程图,点击查看大图 二、源码解读flutter run命令 相信有不少人会好奇flutter命令背后的原理,根据文章Flutter tools可知,对于flutter run命令,那么对应执行的便是RunCommand.runCommand()。这里就以[小节二]中flutter run命令为起点展开,flutter run 命令对应 RunCommand,该命令执行过程中包括以下4个部分组成: [小节三] flutter build apk 命令对应 BuildApkCommand [小节四] flutter build aot 命令对应 BuildAotCommand [小节五] flutter build bundle 命令对应 BuildBundleCommand [小节六] flutter install 命令对应 InstallCommand 说明以下过程都位于工程flutter/packages/flutter_tools/目录。 2.1 RunCommand.runCommand [-> lib/src/commands/run.dart] Future runCommand() async { // debug模式会默认开启热加载模式,如果不需要则添加参数--no-hot final bool hotMode = shouldUseHotMode(); ... //遍历所有已连接设备,runCommand的validateCommand过程会发现所有已连接设备 for (Device device in devices) { final FlutterDevice flutterDevice = await FlutterDevice.create( device, trackWidgetCreation: argResults['track-widget-creation'], dillOutputPath: argResults['output-dill'], fileSystemRoots: argResults['filesystem-root'], fileSystemScheme: argResults['filesystem-scheme'], viewFilter: argResults['isolate-filter'], experimentalFlags: expFlags, target: argResults['target'], buildMode: getBuildMode(), ); flutterDevices.add(flutterDevice); } ResidentRunner runner; final String applicationBinaryPath = argResults['use-application-binary']; if (hotMode) { runner = HotRunner( flutterDevices, target: targetFile, //创建调试flag的开关 debuggingOptions: _createDebuggingOptions(), benchmarkMode: argResults['benchmark'], applicationBinary: applicationBinaryPath == null ? null : fs.file(applicationBinaryPath), projectRootPath: argResults['project-root'], packagesFilePath: globalResults['packages'], dillOutputPath: argResults['output-dill'], saveCompilationTrace: argResults['train'], stayResident: stayResident, ipv6: ipv6, ); } else { runner = ColdRunner( flutterDevices, target: targetFile, debuggingOptions: _createDebuggingOptions(), traceStartup: traceStartup, awaitFirstFrameWhenTracing: awaitFirstFrameWhenTracing, applicationBinary: applicationBinaryPath == null ? null : fs.file(applicationBinaryPath), saveCompilationTrace: argResults['train'], stayResident: stayResident, ipv6: ipv6, ); } ... // [见小节2.2] final int result = await runner.run( appStartedCompleter: appStartedTimeRecorder, route: route, shouldBuild: !runningWithPrebuiltApplication && argResults['build'], ); ... } 该方法主要功能说明: debug模式会默认开启热加载模式,如果不需要则添加参数–no-hot 遍历所有已连接设备,发现所有已连接设备 通过_createDebuggingOptions来解析flutter run方法传递过来的命令参数 根据启动方式是否为热重载来调用相应ResidentRunner的run()来执行,接下来以hot reload为例展开说明。 2.2 HotRunner.run [-> lib/src/run_hot.dart] class HotRunner extends ResidentRunner { Future run({ Completer connectionInfoCompleter, Completer appStartedCompleter, String route, bool shouldBuild = true, }) async { ... firstBuildTime = DateTime.now(); for (FlutterDevice device in flutterDevices) { //[见小节2.3] final int result = await device.runHot( hotRunner: this, route: route, shouldBuild: shouldBuild, ); } //与设备建立连接 return attach( connectionInfoCompleter: connectionInfoCompleter, appStartedCompleter: appStartedCompleter, ); } } 2.3 FlutterDevice.runHot [-> lib/src/resident_runner.dart] class FlutterDevice { Future runHot({HotRunner hotRunner, String route, bool shouldBuild,}) async { final bool prebuiltMode = hotRunner.applicationBinary != null; final String modeName = hotRunner.debuggingOptions.buildInfo.friendlyModeName; final TargetPlatform targetPlatform = await device.targetPlatform; package = await ApplicationPackageFactory.instance.getPackageForPlatform( targetPlatform, applicationBinary: hotRunner.applicationBinary, ); ... //[见小节2.4/2.5] 启动应用 final Future futureResult = device.startApp( package, mainPath: hotRunner.mainPath, debuggingOptions: hotRunner.debuggingOptions, platformArgs: platformArgs, route: route, prebuiltApplication: prebuiltMode, usesTerminalUi: hotRunner.usesTerminalUI, ipv6: hotRunner.ipv6, ); final LaunchResult result = await futureResult; ... return 0; } } 应用启动过程,这里小节2.4介绍Android,小节2.5是介绍iOS的启动过程。 2.4 AndroidDevice.startApp [-> lib/src/android/android_device.dart] class AndroidDevice extends Device { Future startApp( ApplicationPackage package, { String mainPath, String route, DebuggingOptions debuggingOptions, Map platformArgs, bool prebuiltApplication = false, bool usesTerminalUi = true, bool ipv6 = false, }) async { ... //获取平台信息arm64/arm/x64/x86 final TargetPlatform devicePlatform = await targetPlatform; if (!prebuiltApplication || androidSdk.licensesAvailable && androidSdk.latestVersion == null) { final FlutterProject project = await FlutterProject.current(); //通过gradle来构建APK [小节3.2] await buildApk(project: project, target: mainPath, buildInfo: buildInfo,); //APK已构建,则从中获取应用id(包名)和activity名 package = await AndroidApk.fromAndroidProject(project.android); } //通过adb am force-stop来强杀该应用 await stopApp(package); //该方法会installApp()安装APK [小节6.2] if (!await _installLatestApp(package)) return LaunchResult.failed(); ... if (debuggingOptions.debuggingEnabled) { //调试模式,开启observatory observatoryDiscovery = ProtocolDiscovery.observatory( getLogReader(), portForwarder: portForwarder, hostPort: debuggingOptions.observatoryPort, ipv6: ipv6, ); } List cmd; // 通过adb am start来启动应用 cmd = adbCommandForDevice([ 'shell', 'am', 'start', '-a', 'android.intent.action.RUN', '-f', '0x20000000', // FLAG_ACTIVITY_SINGLE_TOP '--ez', 'enable-background-compilation', 'true', '--ez', 'enable-dart-profiling', 'true', ]); if (traceStartup) cmd.addAll(['--ez', 'trace-startup', 'true']); if (route != null) cmd.addAll(['--es', 'route', route]); if (debuggingOptions.enableSoftwareRendering) cmd.addAll(['--ez', 'enable-software-rendering', 'true']); if (debuggingOptions.skiaDeterministicRendering) cmd.addAll(['--ez', 'skia-deterministic-rendering', 'true']); if (debuggingOptions.traceSkia) cmd.addAll(['--ez', 'trace-skia', 'true']); if (debuggingOptions.traceSystrace) cmd.addAll(['--ez', 'trace-systrace', 'true']); if (debuggingOptions.dumpSkpOnShaderCompilation) cmd.addAll(['--ez', 'dump-skp-on-shader-compilation', 'true']); if (debuggingOptions.debuggingEnabled) { if (debuggingOptions.buildInfo.isDebug) { cmd.addAll(['--ez', 'enable-checked-mode', 'true']); cmd.addAll(['--ez', 'verify-entry-points', 'true']); } if (debuggingOptions.startPaused) cmd.addAll(['--ez', 'start-paused', 'true']); if (debuggingOptions.disableServiceAuthCodes) cmd.addAll(['--ez', 'disable-service-auth-codes', 'true']); if (debuggingOptions.useTestFonts) cmd.addAll(['--ez', 'use-test-fonts', 'true']); if (debuggingOptions.verboseSystemLogs) { cmd.addAll(['--ez', 'verbose-logging', 'true']); } } cmd.add(apk.launchActivity); final String result = (await runCheckedAsync(cmd)).stdout; ... if (!debuggingOptions.debuggingEnabled) return LaunchResult.succeeded(); try { Uri observatoryUri; //debug或者profile模式,开启observatory服务来跟设备交互 if (debuggingOptions.buildInfo.isDebug || debuggingOptions.buildInfo.isProfile) { observatoryUri = await observatoryDiscovery.uri; } return LaunchResult.succeeded(observatoryUri: observatoryUri); } catch (error) { ... } finally { await observatoryDiscovery.cancel(); } } } 关于TargetPlatform,是通过adb shell getprop获取属性值来查看ro.product.cpu.abi的值,来获取平台信息arm64/arm/x64/x86。 该方法的主要功能是以下完成如下几件事: 通过gradle来构建APK 通过adb am force-stop来强杀旧的应用 通过adb install来安装APK 通过adb am start来启动应用 对于debug或者profile模式,等待开启observatory服务 2.5 IOSDevice.startApp [-> lib/src/ios/devices.dart] class IOSDevice extends Device { Future startApp( ApplicationPackage package, { String mainPath, String route, DebuggingOptions debuggingOptions, Map platformArgs, bool prebuiltApplication = false, bool usesTerminalUi = true, bool ipv6 = false, }) async { if (!prebuiltApplication) { //ideviceinfo中获取CPUArchitecture,从而判断是armv7还是arm64 final String cpuArchitecture = await iMobileDevice.getInfoForDevice(id, 'CPUArchitecture'); final IOSArch iosArch = getIOSArchForName(cpuArchitecture); // Step 1: 构建预编译/DBC应用 final XcodeBuildResult buildResult = await buildXcodeProject( app: package, buildInfo: debuggingOptions.buildInfo, targetOverride: mainPath, buildForDevice: true, usesTerminalUi: usesTerminalUi, activeArch: iosArch, ); } else { if (!await installApp(package)) return LaunchResult.failed(); } // Step 2: 检查应用程序是否存在于指定路径 final IOSApp iosApp = package; final Directory bundle = fs.directory(iosApp.deviceBundlePath); // Step 3: 在设备上尝试安装应用 final List launchArguments = ['--enable-dart-profiling']; if (debuggingOptions.startPaused) launchArguments.add('--start-paused'); if (debuggingOptions.disableServiceAuthCodes) launchArguments.add('--disable-service-auth-codes'); if (debuggingOptions.useTestFonts) launchArguments.add('--use-test-fonts'); if (debuggingOptions.debuggingEnabled) { launchArguments.add('--enable-checked-mode'); launchArguments.add('--verify-entry-points'); } if (debuggingOptions.enableSoftwareRendering) launchArguments.add('--enable-software-rendering'); if (debuggingOptions.skiaDeterministicRendering) launchArguments.add('--skia-deterministic-rendering'); if (debuggingOptions.traceSkia) launchArguments.add('--trace-skia'); if (debuggingOptions.dumpSkpOnShaderCompilation) launchArguments.add('--dump-skp-on-shader-compilation'); if (debuggingOptions.verboseSystemLogs) { launchArguments.add('--verbose-logging'); } if (platformArgs['trace-startup'] ?? false) launchArguments.add('--trace-startup'); int installationResult = -1; Uri localObservatoryUri; if (!debuggingOptions.debuggingEnabled) { ... } else { //调试模式,则打开observatory服务 final ProtocolDiscovery observatoryDiscovery = ProtocolDiscovery.observatory( getLogReader(app: package), portForwarder: portForwarder, hostPort: debuggingOptions.observatoryPort, ipv6: ipv6, ); final Future forwardObservatoryUri = observatoryDiscovery.uri; //启动应用 final Future launch = const IOSDeploy().runApp( deviceId: id, bundlePath: bundle.path, launchArguments: launchArguments, ); localObservatoryUri = await launch.then((int result) async { installationResult = result; //等待observatory服务启动完成 return await forwardObservatoryUri; }).whenComplete(() { observatoryDiscovery.cancel(); }); } ... return LaunchResult.succeeded(observatoryUri: localObservatoryUri); } } 该方法主要功能: 构建预编译/DBC应用 检查应用程序是否存在于指定路径 通过ios-deploy命令来安装并运行应用 对于debug或者profile模式,等待开启observatory服务 关于运行时参数跟Android基本一致。 2.6 flutter run参数小结 flutter run最核心的功能是: 通过gradle来构建APK 通过adb install来安装APK 通过adb am start来启动应用 对于am start过程有很多debuggingOptions可选的调试参数,如下所示: flags 含义 trace-startup 跟踪启动 route enable-software-rendering 开启软件渲染 skia-deterministic-rendering trace-skia 跟踪skia trace-systrace 跟进systrace dump-skp-on-shader-compilation enable-checked-mode verify-entry-points start-paused 应用启动后暂停 disable-service-auth-codes 关闭observatory服务鉴权 use-test-fonts 使用测试字体 verbose-logging 输出verbose日志 由此可见,如果你希望运行某个已经安装过的flutter应用,可以跳过安装等环节,可以直接执行应用启动,如下命令: adb shell am start -a android.intent.action.RUN -f 0x20000000 --ez enable-background-compilation true --ez enable-dart-profiling true --ez disable-service-auth-codes true com.gityuan.flutterdemo/.MainActivity 三、flutter build apk命令 对于flutter build apk命令,那么对应执行的便是BuildApkCommand类,那么接下来便是执行BuildApkCommand.runCommand()。 3.1 BuildApkCommand.runCommand [-> lib/src/commands/build_apk.dart] class BuildApkCommand extends BuildSubCommand { Future runCommand() async { // [见小节3.2] await buildApk( project: await FlutterProject.current(), target: targetFile, buildInfo: getBuildInfo(), ); return null; } } 3.2 buildApk [-> lib/src/android/apk.dart] Future buildApk({ @required FlutterProject project, @required String target, BuildInfo buildInfo = BuildInfo.debug, }) async { // [见小节3.3] await buildGradleProject( project: project, buildInfo: buildInfo, target: target, isBuildingBundle: false, ); androidSdk.reinitialize(); } 3.3 buildGradleProject [-> lib/src/android/gradle.dart] Future buildGradleProject({ @required FlutterProject project, @required BuildInfo buildInfo, @required String target, @required bool isBuildingBundle, }) async { updateLocalProperties(project: project, buildInfo: buildInfo); // [见小节3.3.1] 获取gradle命令 final String gradle = await _ensureGradle(project); switch (getFlutterPluginVersion(project.android)) { case FlutterPluginVersion.none: case FlutterPluginVersion.v1: return _buildGradleProjectV1(project, gradle); case FlutterPluginVersion.managed: case FlutterPluginVersion.v2: // [见小节3.4] return _buildGradleProjectV2(project, gradle, buildInfo, target, isBuildingBundle); } } 更新local.properties文件的构建模式、版本名和版本号。 FlutterPlugin v1读取local.properties以确定构建模式, 插件v2使用标准的Android方法来确定要构建的内容。版本名称和版本号由pubspec.yaml文件提供并可以用flutter build命令覆盖。默认的Gradle脚本读取版本名称和编号从local.properties文件中。 3.3.1 _ensureGradle [-> lib/src/android/gradle.dart] Future _ensureGradle(FlutterProject project) async { _cachedGradleExecutable ??= await _initializeGradle(project); return _cachedGradleExecutable; } Future _initializeGradle(FlutterProject project) async { final Directory android = project.android.hostAppGradleRoot; final Status status = logger.startProgress('Initializing gradle...', timeout: timeoutConfiguration.slowOperation); // [见小节3.3.2] String gradle = _locateGradlewExecutable(android); if (gradle == null) { injectGradleWrapper(android); gradle = _locateGradlewExecutable(android); } // 通过检查版本来验证Gradle可执行文件。如果需要,请下载并安装Gradle发行版。 await runCheckedAsync([gradle, '-v'], environment: _gradleEnv); status.stop(); return gradle; } 3.3.2 _locateGradlewExecutable [-> lib/src/android/gradle.dart] String _locateGradlewExecutable(Directory directory) { final File gradle = directory.childFile( platform.isWindows ? 'gradlew.bat' : 'gradlew', ); if (gradle.existsSync()) { os.makeExecutable(gradle); return gradle.absolute.path; } else { return null; } } 该方法说明: 对于window环境,则是gradlew.bat; 其他环境,则是gradlew; 3.4 _buildGradleProjectV2 [-> lib/src/android/gradle.dart] Future _buildGradleProjectV2( FlutterProject flutterProject, String gradle, BuildInfo buildInfo, String target, bool isBuildingBundle, ) async { final GradleProject project = await _gradleProject(); String assembleTask; // 前面传递过来isBuildingBundle为false if (isBuildingBundle) { assembleTask = project.bundleTaskFor(buildInfo); } else { assembleTask = project.assembleTaskFor(buildInfo); } //获取gradle路径 final String gradlePath = fs.file(gradle).absolute.path; final List command = [gradlePath]; if (artifacts is LocalEngineArtifacts) { final LocalEngineArtifacts localEngineArtifacts = artifacts; command.add('-PlocalEngineOut=${localEngineArtifacts.engineOutPath}'); } if (target != null) { command.add('-Ptarget=$target'); } command.add('-Ptrack-widget-creation=${buildInfo.trackWidgetCreation}'); if (buildInfo.compilationTraceFilePath != null) command.add('-Pcompilation-trace-file=${buildInfo.compilationTraceFilePath}'); if (buildInfo.createPatch) command.add('-Ppatch=true'); if (buildInfo.extraFrontEndOptions != null) command.add('-Pextra-front-end-options=${buildInfo.extraFrontEndOptions}'); if (buildInfo.extraGenSnapshotOptions != null) command.add('-Pextra-gen-snapshot-options=${buildInfo.extraGenSnapshotOptions}'); if (buildInfo.fileSystemRoots != null && buildInfo.fileSystemRoots.isNotEmpty) command.add('-Pfilesystem-roots=${buildInfo.fileSystemRoots.join('|')}'); if (buildInfo.fileSystemScheme != null) command.add('-Pfilesystem-scheme=${buildInfo.fileSystemScheme}'); if (buildInfo.buildSharedLibrary && androidSdk.ndk != null) { command.add('-Pbuild-shared-library=true'); } if (buildInfo.targetPlatform != null) command.add('-Ptarget-platform=${getNameForTargetPlatform(buildInfo.targetPlatform)}'); command.add(assembleTask); bool potentialAndroidXFailure = false; //运行组装了一串参数的gradle命令 final int exitCode = await runCommandAndStreamOutput( command, workingDirectory: flutterProject.android.hostAppGradleRoot.path, allowReentrantFlutter: true, environment: _gradleEnv, ... ); status.stop(); if (!isBuildingBundle) { //获取apk文件 final File apkFile = _findApkFile(project, buildInfo); //将APK复制到app.apk,以便`flutter run`, `flutter install`这些命令能找到 apkFile.copySync(project.apkDirectory.childFile('app.apk').path); final File apkShaFile = project.apkDirectory.childFile('app.apk.sha1'); apkShaFile.writeAsStringSync(calculateSha(apkFile)); ... } else { ... } } 构建过程主要是调用gradle命令,如下所示 3.4.1 gradle命令与参数说明 gradlew命令: gradlew -Ptarget=lib/main.dart -Ptrack-widget-creation=false -Ptarget-platform=android-arm assembleRelease 参数 说明 PlocalEngineOut 引擎产物 Ptarget 取值lib/main.dart Ptrack-widget-creation 默认为false Pcompilation-trace-file Ppatch Pextra-front-end-options Pextra-gen-snapshot-options Pfilesystem-roots Pfilesystem-scheme Pbuild-shared-library 是否采取共享库 Ptarget-platform 目标平台 3.5 flutter的gradle构建 gradlew assembleRelease这便是Anroid平台比较常见的编译命令。 会执行build.gradle文件,里面有一行重要的语句,如下所示。 apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 3.5.1 flutter.gradle [-> gradle/flutter.gradle] CopySpec getAssets() { return project.copySpec { from "${intermediateDir}" include "flutter_assets/**" // the working dir and its files if (buildMode == 'release' || buildMode == 'profile') { if (buildSharedLibrary) { include "app.so" } else { include "vm_snapshot_data" include "vm_snapshot_instr" include "isolate_snapshot_data" include "isolate_snapshot_instr" } } } } 可知flutter产物可以是app.so或者是xxx_snapshot_xxx。 3.5.2 buildBundle [-> gradle/flutter.gradle] void buildBundle() { intermediateDir.mkdirs() if (buildMode == "profile" || buildMode == "release") { //执行flutter build aot project.exec { executable flutterExecutable.absolutePath workingDir sourceDir if (localEngine != null) { args "--local-engine", localEngine args "--local-engine-src-path", localEngineSrcPath } args "build", "aot" args "--suppress-analytics" args "--quiet" args "--target", targetPath args "--target-platform", "android-arm" args "--output-dir", "${intermediateDir}" if (trackWidgetCreation) { args "--track-widget-creation" } if (extraFrontEndOptions != null) { args "--extra-front-end-options", "${extraFrontEndOptions}" } if (extraGenSnapshotOptions != null) { args "--extra-gen-snapshot-options", "${extraGenSnapshotOptions}" } if (buildSharedLibrary) { args "--build-shared-library" } if (targetPlatform != null) { args "--target-platform", "${targetPlatform}" } args "--${buildMode}" } } //flutter build bundle project.exec { executable flutterExecutable.absolutePath workingDir sourceDir if (localEngine != null) { args "--local-engine", localEngine args "--local-engine-src-path", localEngineSrcPath } args "build", "bundle" args "--suppress-analytics" args "--target", targetPath if (verbose) { args "--verbose" } if (fileSystemRoots != null) { for (root in fileSystemRoots) { args "--filesystem-root", root } } if (fileSystemScheme != null) { args "--filesystem-scheme", fileSystemScheme } if (trackWidgetCreation) { args "--track-widget-creation" } if (compilationTraceFilePath != null) { args "--compilation-trace-file", compilationTraceFilePath } if (createPatch) { args "--patch" args "--build-number", project.android.defaultConfig.versionCode if (buildNumber != null) { assert buildNumber == project.android.defaultConfig.versionCode } } if (baselineDir != null) { args "--baseline-dir", baselineDir } if (extraFrontEndOptions != null) { args "--extra-front-end-options", "${extraFrontEndOptions}" } if (extraGenSnapshotOptions != null) { args "--extra-gen-snapshot-options", "${extraGenSnapshotOptions}" } if (targetPlatform != null) { args "--target-platform", "${targetPlatform}" } if (buildMode == "release" || buildMode == "profile") { args "--precompiled" } else { args "--depfile", "${intermediateDir}/snapshot_blob.bin.d" } args "--asset-dir", "${intermediateDir}/flutter_assets" if (buildMode == "debug") { args "--debug" } if (buildMode == "profile" || buildMode == "dynamicProfile") { args "--profile" } if (buildMode == "release" || buildMode == "dynamicRelease") { args "--release" } if (buildMode == "dynamicProfile" || buildMode == "dynamicRelease") { args "--dynamic" } } } 该方法核心功能是两部分: flutter build aot:针对profile或者release模式 flutter build bundle 3.6 build apk等价命令 build apk的过程主要分为以下两个过程,也就是[小节3.4.2]的buildBundle中过程展开后的如下两个命令: flutter build aot --suppress-analytics --quiet --target lib/main.dart --output-dir /build/app/intermediates/flutter/release/ --target-platform android-arm --extra-front-end-options --extra-gen-snapshot-options --release flutter build bundle --suppress-analytics --verbose --target lib/main.dart --target-platform android-arm --extra-front-end-options --extra-gen-snapshot-options --asset-dir /build/app/intermediates/flutter/release/flutter_assets --precompiled --release 四、 flutter build aot命令 4.1 BuildAotCommand.runCommand [-> lib/src/commands/build_aot.dart] class BuildAotCommand extends BuildSubCommand with TargetPlatformBasedDevelopmentArtifacts { Future runCommand() async { //解析目标平台 final String targetPlatform = argResults['target-platform']; final TargetPlatform platform = getTargetPlatformForName(targetPlatform); //解析编译模式 final BuildMode buildMode = getBuildMode(); Status status; //解析aot产物路径 final String outputPath = argResults['output-dir'] ?? getAotBuildDirectory(); final bool reportTimings = argResults['report-timings']; try { //解析dart主函数路径 String mainPath = findMainDartFile(targetFile); final AOTSnapshotter snapshotter = AOTSnapshotter(reportTimings: reportTimings); //编译到内核 [见小节4.2] mainPath = await snapshotter.compileKernel( platform: platform, buildMode: buildMode, mainPath: mainPath, packagesPath: PackageMap.globalPackagesPath, trackWidgetCreation: false, outputPath: outputPath, extraFrontEndOptions: argResults[FlutterOptions.kExtraFrontEndOptions], ); //构建AOT快照 if (platform == TargetPlatform.ios) { // iOS架构分为armv7和arm64 final Iterable buildArchs = argResults['ios-arch'].map(getIOSArchForName); final Map iosBuilds = {}; for (IOSArch arch in buildArchs) iosBuilds[arch] = fs.path.join(outputPath, getNameForIOSArch(arch)); final Map> exitCodes = >{}; iosBuilds.forEach((IOSArch iosArch, String outputPath) { //生成AOT快照 并编译为特定架构的App.framework [见小节4.4] exitCodes[iosArch] = snapshotter.build( platform: platform, iosArch: iosArch, buildMode: buildMode, mainPath: mainPath, packagesPath: PackageMap.globalPackagesPath, outputPath: outputPath, buildSharedLibrary: false, extraGenSnapshotOptions: argResults[FlutterOptions.kExtraGenSnapshotOptions], ).then((int buildExitCode) { return buildExitCode; }); }); //将特定于架构的App.frameworks合并到一个多架构的App.framework中 if ((await Future.wait(exitCodes.values)).every((int buildExitCode) => buildExitCode == 0)) { final Iterable dylibs = iosBuilds.values.map((String outputDir) => fs.path.join(outputDir, 'App.framework', 'App')); fs.directory(fs.path.join(outputPath, 'App.framework'))..createSync(); await runCheckedAsync(['lipo'] ..addAll(dylibs) ..addAll(['-create', '-output', fs.path.join(outputPath, 'App.framework', 'App')]), ); } else { status?.cancel(); exitCodes.forEach((IOSArch iosArch, Future exitCodeFuture) async { final int buildExitCode = await exitCodeFuture; printError('Snapshotting ($iosArch) exited with non-zero exit code: $buildExitCode'); }); } } else { // Android AOT快照 [见小节4.4] final int snapshotExitCode = await snapshotter.build( platform: platform, buildMode: buildMode, mainPath: mainPath, packagesPath: PackageMap.globalPackagesPath, outputPath: outputPath, buildSharedLibrary: argResults['build-shared-library'], extraGenSnapshotOptions: argResults[FlutterOptions.kExtraGenSnapshotOptions], ); } } on String catch (error) { ... } ... return null; } } 该方法主要功能: build aot的参数解读,见小节[1.2.3]; 生成kernel文件, 这是dart定义的一种特殊数据格式,由dart虚拟机解释模式执行; 生成AOT可执行文件,根据kernel来生成的一种二进制机器码,执行速度更快;release模式打进apk的便是机器码; 4.2 compileKernel [-> lib/src/base/build.dart] class AOTSnapshotter { Future compileKernel({ @required TargetPlatform platform, @required BuildMode buildMode, @required String mainPath, @required String packagesPath, @required String outputPath, @required bool trackWidgetCreation, List extraFrontEndOptions = const [], }) async { final FlutterProject flutterProject = await FlutterProject.current(); final Directory outputDir = fs.directory(outputPath); outputDir.createSync(recursive: true); //路径为 build/aot/kernel_compile.d final String depfilePath = fs.path.join(outputPath, 'kernel_compile.d'); final KernelCompiler kernelCompiler = await kernelCompilerFactory.create(flutterProject); final CompilerOutput compilerOutput = await _timedStep('frontend', //[见小节4.3] () => kernelCompiler.compile( sdkRoot: artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath, mode: buildMode), mainPath: mainPath, packagesPath: packagesPath, outputFilePath: getKernelPathForTransformerOptions( fs.path.join(outputPath, 'app.dill'), trackWidgetCreation: trackWidgetCreation, ), depFilePath: depfilePath, extraFrontEndOptions: extraFrontEndOptions, linkPlatformKernelIn: true, aot: true, trackWidgetCreation: trackWidgetCreation, targetProductVm: buildMode == BuildMode.release, )); //将路径写入frontend_server,因为当更改时需要重新生成 final String frontendPath = artifacts.getArtifactPath(Artifact.frontendServerSnapshotForEngineDartSdk); await fs.directory(outputPath).childFile('frontend_server.d').writeAsString('frontend_server.d: $frontendPath\n'); return compilerOutput?.outputFilename; } } 4.3 KernelCompiler.compile [-> lib/src/compile.dart] class KernelCompiler { Future compile({ String sdkRoot, String mainPath, String outputFilePath, String depFilePath, TargetModel targetModel = TargetModel.flutter, bool linkPlatformKernelIn = false, bool aot = false, @required bool trackWidgetCreation, List extraFrontEndOptions, String incrementalCompilerByteStorePath, String packagesPath, List fileSystemRoots, String fileSystemScheme, bool targetProductVm = false, String initializeFromDill, }) async { final String frontendServer = artifacts.getArtifactPath( Artifact.frontendServerSnapshotForEngineDartSdk ); FlutterProject flutterProject; if (fs.file('pubspec.yaml').existsSync()) { flutterProject = await FlutterProject.current(); } Fingerprinter fingerprinter; if (depFilePath != null) { fingerprinter = Fingerprinter( fingerprintPath: '$depFilePath.fingerprint', paths: [mainPath], properties: { 'entryPoint': mainPath, 'trackWidgetCreation': trackWidgetCreation.toString(), 'linkPlatformKernelIn': linkPlatformKernelIn.toString(), 'engineHash': Cache.instance.engineRevision, 'buildersUsed': '${flutterProject != null ? flutterProject.hasBuilders : false}', }, depfilePaths: [depFilePath], pathFilter: (String path) => !path.startsWith('/b/build/slave/'), ); } //获取dart命令路径 final String engineDartPath = artifacts.getArtifactPath(Artifact.engineDartBinary); } final List command = [ engineDartPath, frontendServer, '--sdk-root', sdkRoot, '--strong', '--target=$targetModel', ]; if (trackWidgetCreation) command.add('--track-widget-creation'); if (!linkPlatformKernelIn) command.add('--no-link-platform'); if (aot) { command.add('--aot'); command.add('--tfa'); } if (targetProductVm) { command.add('-Ddart.vm.product=true'); } if (incrementalCompilerByteStorePath != null) { command.add('--incremental'); } Uri mainUri; if (packagesPath != null) { command.addAll(['--packages', packagesPath]); mainUri = PackageUriMapper.findUri(mainPath, packagesPath, fileSystemScheme, fileSystemRoots); } if (outputFilePath != null) { command.addAll(['--output-dill', outputFilePath]); } if (depFilePath != null && (fileSystemRoots == null || fileSystemRoots.isEmpty)) { command.addAll(['--depfile', depFilePath]); } if (fileSystemRoots != null) { for (String root in fileSystemRoots) { command.addAll(['--filesystem-root', root]); } } if (fileSystemScheme != null) { command.addAll(['--filesystem-scheme', fileSystemScheme]); } if (initializeFromDill != null) { command.addAll(['--initialize-from-dill', initializeFromDill]); } if (extraFrontEndOptions != null) command.addAll(extraFrontEndOptions); command.add(mainUri?.toString() ?? mainPath); ... //执行命令 [见小节4.3.1] await processManager.start(command); await fingerprinter.writeFingerprint(); ... } } 4.3.1 frontend_server命令 KernelCompiler.compile()过程等价于如下命令: flutter/bin/cache/dart-sdk/bin/dart flutter/bin/cache/artifacts/engine/darwin-x64/frontend_server.dart.snapshot --sdk-root flutter/bin/cache/artifacts/engine/common/flutter_patched_sdk_product/ --strong --target=flutter --aot --tfa -Ddart.vm.product=true --packages .packages --output-dill build/app/intermediates/flutter/release/app.dill --depfile build/app/intermediates/flutter/release/kernel_compile.d package:flutter_app/main.dart 可见,通过dart虚拟机启动frontend_server.dart.snapshot,将dart代码编程成app.dill形式的kernel文件。frontend_server.dart.snapshot的入口位于Flutter引擎中的 flutter/frontend_server/bin/starter.dart。 关于这个过程的kernel编译以及文件的生成过程,将在下一篇文章将进一步展开说明。 再回到[小节4.1],接下来执行AOTSnapshotter.build()方法。 4.4 AOTSnapshotter.build [-> lib/src/base/build.dart] class AOTSnapshotter { Future build({ @required TargetPlatform platform, @required BuildMode buildMode, @required String mainPath, @required String packagesPath, @required String outputPath, @required bool buildSharedLibrary, IOSArch iosArch, List extraGenSnapshotOptions = const [], }) async { FlutterProject flutterProject; if (fs.file('pubspec.yaml').existsSync()) { flutterProject = await FlutterProject.current(); } //非debug模式下的android arm/arm64或者ios才支持aot if (!_isValidAotPlatform(platform, buildMode)) { return 1; } //iOS忽略共享库 if (platform == TargetPlatform.ios) buildSharedLibrary = false; final PackageMap packageMap = PackageMap(packagesPath); final Directory outputDir = fs.directory(outputPath); outputDir.createSync(recursive: true); final String skyEnginePkg = _getPackagePath(packageMap, 'sky_engine'); final String uiPath = fs.path.join(skyEnginePkg, 'lib', 'ui', 'ui.dart'); final String vmServicePath = fs.path.join(skyEnginePkg, 'sdk_ext', 'vmservice_io.dart'); final List inputPaths = [uiPath, vmServicePath, mainPath]; final Set outputPaths = {}; final String depfilePath = fs.path.join(outputDir.path, 'snapshot.d'); final List genSnapshotArgs = ['--deterministic',]; if (extraGenSnapshotOptions != null && extraGenSnapshotOptions.isNotEmpty) { genSnapshotArgs.addAll(extraGenSnapshotOptions); } final String assembly = fs.path.join(outputDir.path, 'snapshot_assembly.S'); if (buildSharedLibrary || platform == TargetPlatform.ios) { // Assembly AOT snapshot. outputPaths.add(assembly); genSnapshotArgs.add('--snapshot_kind=app-aot-assembly'); genSnapshotArgs.add('--assembly=$assembly'); } else { // Blob AOT snapshot. final String vmSnapshotData = fs.path.join(outputDir.path, 'vm_snapshot_data'); final String isolateSnapshotData = fs.path.join(outputDir.path, 'isolate_snapshot_data'); final String vmSnapshotInstructions = fs.path.join(outputDir.path, 'vm_snapshot_instr'); final String isolateSnapshotInstructions = fs.path.join(outputDir.path, 'isolate_snapshot_instr'); outputPaths.addAll([vmSnapshotData, isolateSnapshotData, vmSnapshotInstructions, isolateSnapshotInstructions]); genSnapshotArgs.addAll([ '--snapshot_kind=app-aot-blobs', '--vm_snapshot_data=$vmSnapshotData', '--isolate_snapshot_data=$isolateSnapshotData', '--vm_snapshot_instructions=$vmSnapshotInstructions', '--isolate_snapshot_instructions=$isolateSnapshotInstructions', ]); } if (platform == TargetPlatform.android_arm || iosArch == IOSArch.armv7) { //将softfp用于Android armv7设备。这是armv7 iOS构建的默认设置 genSnapshotArgs.add('--no-sim-use-hardfp'); // Pixel不支持32位模式 genSnapshotArgs.add('--no-use-integer-division'); } genSnapshotArgs.add(mainPath); final Fingerprinter fingerprinter = Fingerprinter( fingerprintPath: '$depfilePath.fingerprint', paths: [mainPath]..addAll(inputPaths)..addAll(outputPaths), properties: { 'buildMode': buildMode.toString(), 'targetPlatform': platform.toString(), 'entryPoint': mainPath, 'sharedLib': buildSharedLibrary.toString(), 'extraGenSnapshotOptions': extraGenSnapshotOptions.join(' '), 'engineHash': Cache.instance.engineRevision, 'buildersUsed': '${flutterProject != null ? flutterProject.hasBuilders : false}', }, depfilePaths: [], ); //自从上次运行以来,输入和输出都没有更改,则跳过该构建流程 if (await fingerprinter.doesFingerprintMatch()) { return 0; } final SnapshotType snapshotType = SnapshotType(platform, buildMode); //[见小节4.5] final int genSnapshotExitCode = await _timedStep('gen_snapshot', () => genSnapshot.run( snapshotType: snapshotType, additionalArgs: genSnapshotArgs, iosArch: iosArch, )); // 将路径写入gen_snapshot,因为在滚动Dart SDK时必须重新生成快照 final String genSnapshotPath = GenSnapshot.getSnapshotterPath(snapshotType); await outputDir.childFile('gen_snapshot.d').writeAsString('gen_snapshot.d: $genSnapshotPath\n'); //在iOS上,使用Xcode将snapshot编译到动态库中,最终可见将其链接到应用程序。 if (platform == TargetPlatform.ios) { final RunResult result = await _buildIosFramework(iosArch: iosArch, assemblyPath: assembly, outputPath: outputDir.path); } else if (buildSharedLibrary) { final RunResult result = await _buildAndroidSharedLibrary(assemblyPath: assembly, outputPath: outputDir.path); } //计算和记录构建指纹 await fingerprinter.writeFingerprint(); return 0; } } 该方法说明: 对于iOS或者采用共享库方式的Android,则产物类型snapshot_kind为app-aot-assembly 对于Android,则生成app.so 对于非共享库方式的Android,则产物类型snapshot_kind为app-aot-blobs 生成vmSnapshotData,isolateSnapshotData,vmSnapshotInstructions,isolateSnapshotInstructions这四个产物 4.5 GenSnapshot.run [-> lib/src/base/build.dart] class GenSnapshot { Future run({ @required SnapshotType snapshotType, IOSArch iosArch, Iterable additionalArgs = const [], }) { final List args = [ '--causal_async_stacks', ]..addAll(additionalArgs); //获取gen_snapshot命令的路径 final String snapshotterPath = getSnapshotterPath(snapshotType); //iOS gen_snapshot是一个多体系结构二进制文件。 作为i386二进制文件运行将生成armv7代码。 作为x86_64二进制文件运行将生成arm64代码。 // /usr/bin/arch可用于运行具有指定体系结构的二进制文件 if (snapshotType.platform == TargetPlatform.ios) { final String hostArch = iosArch == IOSArch.armv7 ? '-i386' : '-x86_64'; return runCommandAndStreamOutput(['/usr/bin/arch', hostArch, snapshotterPath]..addAll(args)); } return runCommandAndStreamOutput([snapshotterPath]..addAll(args)); } } runCommandAndStreamOutput便会执行如下这一串命令: 4.5.1 GenSnapshot命令 GenSnapshot.run具体命令根据前面的封装,最终等价于: // 这是针对Android的genSnapshot命令 flutter/bin/cache/artifacts/engine/android-arm-release/darwin-x64/gen_snapshot --causal_async_stacks --deterministic --snapshot_kind=app-aot-blobs --vm_snapshot_data=build/app/intermediates/flutter/release/vm_snapshot_data --isolate_snapshot_data=build/app/intermediates/flutter/release/isolate_snapshot_data --vm_snapshot_instructions=build/app/intermediates/flutter/release/vm_snapshot_instr --isolate_snapshot_instructions=build/app/intermediates/flutter/release/isolate_snapshot_instr --no-sim-use-hardfp --no-use-integer-division build/aot/app.dill //这是针对iOS的genSnapshot命令 /usr/bin/arch -x86_64 flutter/bin/cache/artifacts/engine/ios-release/gen_snapshot --causal_async_stacks --deterministic --snapshot_kind=app-aot-assembly --assembly=build/aot/arm64/snapshot_assembly.S build/aot/app.dill 此处gen_snapshot是一个二进制可执行文件,所对应的执行方法源码为third_party/dart/runtime/bin/gen_snapshot.cc,将在下一篇文章将进一步展开说明。 五、flutter build bundle命令 5.1 BuildBundleCommand.runCommand [-> lib/src/commands/build_bundle.dart] class BuildBundleCommand extends BuildSubCommand { Future runCommand() async { final String targetPlatform = argResults['target-platform']; final TargetPlatform platform = getTargetPlatformForName(targetPlatform); final BuildMode buildMode = getBuildMode(); final String buildNumber = argResults['build-number'] != null ? argResults['build-number'] : null; //[见小节5.2] await build( platform: platform, buildMode: buildMode, mainPath: targetFile, manifestPath: argResults['manifest'], depfilePath: argResults['depfile'], privateKeyPath: argResults['private-key'], assetDirPath: argResults['asset-dir'], precompiledSnapshot: argResults['precompiled'], reportLicensedPackages: argResults['report-licensed-packages'], trackWidgetCreation: argResults['track-widget-creation'], compilationTraceFilePath: argResults['compilation-trace-file'], createPatch: argResults['patch'], buildNumber: buildNumber, baselineDir: argResults['baseline-dir'], extraFrontEndOptions: argResults[FlutterOptions.kExtraFrontEndOptions], extraGenSnapshotOptions: argResults[FlutterOptions.kExtraGenSnapshotOptions], fileSystemScheme: argResults['filesystem-scheme'], fileSystemRoots: argResults['filesystem-root'], ); return null; } } 5.2 build [-> lib/src/bundle.dart] Future build(...) async { ... final AssetBundle assets = await buildAssets( manifestPath: manifestPath, assetDirPath: assetDirPath, packagesPath: packagesPath, reportLicensedPackages: reportLicensedPackages, ); if (!precompiledSnapshot) { ... //relase模式,参数中会带上--precompiled,则不会编译kernel文件 } //[见小节5.3] await assemble( buildMode: buildMode, assetBundle: assets, kernelContent: kernelContent, privateKeyPath: privateKeyPath, assetDirPath: assetDirPath, compilationTraceFilePath: compilationTraceFilePath, ); } 5.3 assemble [-> lib/src/bundle.dart] Future assemble({ BuildMode buildMode, AssetBundle assetBundle, DevFSContent kernelContent, String privateKeyPath = defaultPrivateKeyPath, String assetDirPath, String compilationTraceFilePath, }) async { // 目录 build/flutter_assets/ assetDirPath ??= getAssetBuildDirectory(); final Map assetEntries = Map.from(assetBundle.entries); if (kernelContent != null) { if (compilationTraceFilePath != null) { final String vmSnapshotData = artifacts.getArtifactPath(Artifact.vmSnapshotData, mode: buildMode); final String isolateSnapshotData = fs.path.join(getBuildDirectory(), _kIsolateSnapshotData); final String isolateSnapshotInstr = fs.path.join(getBuildDirectory(), _kIsolateSnapshotInstr); assetEntries[_kVMSnapshotData] = DevFSFileContent(fs.file(vmSnapshotData)); assetEntries[_kIsolateSnapshotData] = DevFSFileContent(fs.file(isolateSnapshotData)); assetEntries[_kIsolateSnapshotInstr] = DevFSFileContent(fs.file(isolateSnapshotInstr)); } else { final String vmSnapshotData = artifacts.getArtifactPath(Artifact.vmSnapshotData, mode: buildMode); final String isolateSnapshotData = artifacts.getArtifactPath(Artifact.isolateSnapshotData, mode: buildMode); assetEntries[_kKernelKey] = kernelContent; assetEntries[_kVMSnapshotData] = DevFSFileContent(fs.file(vmSnapshotData)); assetEntries[_kIsolateSnapshotData] = DevFSFileContent(fs.file(isolateSnapshotData)); } } ensureDirectoryExists(assetDirPath); //[见小节5.4] await writeBundle(fs.directory(assetDirPath), assetEntries); } 5.4 writeBundle [-> lib/src/bundle.dart] Future writeBundle( Directory bundleDir, Map assetEntries, ) async { if (bundleDir.existsSync()) bundleDir.deleteSync(recursive: true); bundleDir.createSync(recursive: true); await Future.wait( assetEntries.entries.map>((MapEntry entry) async { final File file = fs.file(fs.path.join(bundleDir.path, entry.key)); file.parent.createSync(recursive: true); await file.writeAsBytes(await entry.value.contentsAsBytes()); })); } 将一些文件放进了build/app/intermediates/flutter/release/flutter_assets目录下。 AssetManifest.json FontManifest.json LICENSE fonts/MaterialIcons-Regular.ttf packages/cupertino_icons/assets/CupertinoIcons.ttf 六、flutter install命令 6.1 InstallCommand.runCommand [-> lib/src/commands/install.dart] class InstallCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts { Future runCommand() async { final ApplicationPackage package = await applicationPackages.getPackageForPlatform(await device.targetPlatform); Cache.releaseLockEarly(); //[见小节6.2] if (!await installApp(device, package)) throwToolExit('Install failed'); return null; } } 6.2 installApp [-> lib/src/commands/install.dart] Future installApp(Device device, ApplicationPackage package, { bool uninstall = true }) async { //当app已存在,则先卸载老的apk,再安装新的apk if (uninstall && await device.isAppInstalled(package)) { if (!await device.uninstallApp(package)) printError('Warning: uninstalling old version failed'); } return device.installApp(package); } 6.3 AndroidDevice.installApp [-> lib/src/android/android_device.dart] Future installApp(ApplicationPackage app) async { final AndroidApk apk = app; ... //执行的命令是adb install -t -r [apk_path]来安装APK final RunResult installResult = await runAsync(adbCommandForDevice(['install', '-t', '-r', apk.file.path])); status.stop(); //执行完安装命令,会再通过检查日志来判断是非安装成功 ... return true; } 执行的命令是adb install -t -r [apk_path]来安装APK 附录 flutter/packages/flutter_tools/ lib/src/commands/run.dart lib/src/commands/build_apk.dart lib/src/commands/build_aot.dart lib/src/commands/build_bundle.dart lib/src/commands/install.dart lib/src/ios/devices.dart lib/src/android/android_device.dart lib/src/android/apk.dart lib/src/android/gradle.dart lib/src/base/build.dart lib/src/bundle.dart lib/src/compile.dart lib/src/run_hot.dart lib/src/resident_runner.dart
一、Flutter tools命令 1.1 概述 开发Flutter应用过程,经常会用过Flutter命令,比如flutter run可用于安装并运行Flutter应用,flutter build可用于构建产物,相信有不少人会好奇flutter命令背后的原理。 对于flutter命令的起点位于flutter sdk中路径/flutter/bin/目录中的flutter命令,该命令最终会调用到flutter/packages/flutter_tools工程。 1.2 flutter命令参数表 列举Flutter命令、对应类以及说明,实现见下文[小节2.3]。 名称 对应类 说明 create CreateCommand 创建新的Flutter项目 build BuildCommand Flutter构建命令 install InstallCommand 安装Flutter应用到已连接设备 run RunCommand 运行Flutter应用于已连接设备 packages PackagesCommand 管理Flutter包的命令 devices DevicesCommand 列出所有已连接的设备 emulators EmulatorsCommand 列出,启动,创建模拟器 attach AttachCommand 附加到正在运行的应用程序 trace TraceCommand 开始和停止跟踪正在运行的Flutter应用程序 logs LogsCommand 显示Flutter应用运行中的log doctor DoctorCommand 显示关于已安装工具的信息 upgrade UpgradeCommand 升级Flutter clean CleanCommand 删除build/和.dart_tool/ 目录 analyze AnalyzeCommand 分析项目Dart代码 format FormatCommand 格式化一个或多个dart文件 config ConfigCommand 配置Flutter settings drive DriveCommand 为当前项目运行Flutter Driver测试 test TestCommand 为当前项目运行Flutter 单元测试 另外,对于flutter build有子命令,其子命令的对应类及说明如下: 命令 对应类 说明 build aot BuildAotCommand 构建AOT编译产物 build apk BuildApkCommand 构建Android APK build ios BuildIOSCommand 构建iOS应用bundle build appbundle BuildAppBundleCommand 构建Android应用bundle build bundle BuildBundleCommand 构建Flutter assets 比如flutter run则执行RunCommand.runCommand(),flutter install则执行InstallCommand.runCommand()。 二、深入源码flutter命令 2.1 flutter命令起点 [-> /flutter/bin/flutter] ... FLUTTER_TOOLS_DIR="$FLUTTER_ROOT/packages/flutter_tools" SNAPSHOT_PATH="$FLUTTER_ROOT/bin/cache/flutter_tools.snapshot" STAMP_PATH="$FLUTTER_ROOT/bin/cache/flutter_tools.stamp" SCRIPT_PATH="$FLUTTER_TOOLS_DIR/bin/flutter_tools.dart" DART_SDK_PATH="$FLUTTER_ROOT/bin/cache/dart-sdk" DART="$DART_SDK_PATH/bin/dart" PUB="$DART_SDK_PATH/bin/pub" //真正的执行逻辑 "$DART" $FLUTTER_TOOL_ARGS "$SNAPSHOT_PATH" "$@" 该方法功能: $DART:是指$FLUTTER_ROOT/bin/cache/dart-sdk/bin/dart; $SNAPSHOT_PATH:是指$FLUTTER_ROOT/bin/cache/flutter_tools.snapshot,这是由packages/flutter_tools项目编译所生成的产物文件。 那么flutter命令等价于如下: /bin/cache/dart-sdk/bin/dart $FLUTTER_TOOL_ARGS "bin/cache/flutter_tools.snapshot" "$@" dart执行flutter_tools.snapshot,其实也就是执行flutter_tools.dart的main()方法,也就是说将上述命令改为如下语句,则运行flutter命令可以执行本地flutter_tools的项目代码,可用于本地调试分析。 /bin/cache/dart-sdk/bin/dart $FLUTTER_TOOL_ARGS "$FLUTTER_ROOT/packages/flutter_tools/bin/flutter_tools.dart" "$@" 接下来,执行流程进入flutter/packages/flutter_tools/目录。 2.2 flutter_tools.main [-> flutter/packages/flutter_tools/bin/flutter_tools.dart] import 'package:flutter_tools/executable.dart' as executable; void main(List args) { executable.main(args); //[见小节2.3] } 2.3 executable.main [-> lib/executable.dart] import 'runner.dart' as runner; Future main(List args) async { ... //[见小节2.4] await runner.run(args, [ AnalyzeCommand(verboseHelp: verboseHelp), AttachCommand(verboseHelp: verboseHelp), BuildCommand(verboseHelp: verboseHelp), ChannelCommand(verboseHelp: verboseHelp), CleanCommand(), ConfigCommand(verboseHelp: verboseHelp), CreateCommand(), DaemonCommand(hidden: !verboseHelp), DevicesCommand(), DoctorCommand(verbose: verbose), DriveCommand(), EmulatorsCommand(), FormatCommand(), GenerateCommand(), IdeConfigCommand(hidden: !verboseHelp), InjectPluginsCommand(hidden: !verboseHelp), InstallCommand(), LogsCommand(), MakeHostAppEditableCommand(), PackagesCommand(), PrecacheCommand(), RunCommand(verboseHelp: verboseHelp), ScreenshotCommand(), ShellCompletionCommand(), StopCommand(), TestCommand(verboseHelp: verboseHelp), TraceCommand(), TrainingCommand(), UpdatePackagesCommand(hidden: !verboseHelp), UpgradeCommand(), VersionCommand(), ], verbose: verbose, muteCommandLogging: muteCommandLogging, verboseHelp: verboseHelp, overrides: { CodeGenerator: () => const BuildRunner(), }); } 2.4 runner.run [-> lib/runner.dart] Future run( List args, List commands, { bool muteCommandLogging = false, bool verbose = false, bool verboseHelp = false, bool reportCrashes, String flutterVersion, Map overrides, }) { ... //创建FlutterCommandRunner对象 final FlutterCommandRunner runner = FlutterCommandRunner(verboseHelp: verboseHelp); //[见小节2.4.1] 将创建的命令对象都加入到_commands commands.forEach(runner.addCommand); return runInContext(() async { ... // [见小节2.5] await runner.run(args); ... }, overrides: overrides); } 2.4.1 addCommand [-> package:args/command_runner.dart] void addCommand(Command command) { var names = [command.name]..addAll(command.aliases); for (var name in names) { _commands[name] = command; argParser.addCommand(name, command.argParser); } command._runner = this; } 所有命令都加入到_commands。比如flutter run对应的命令对象为RunCommand,flutter build对应的命令对象为buildCommand。 2.5 FlutterCommandRunner.run [-> lib/src/runner/flutter_command_runner.dart] class FlutterCommandRunner extends CommandRunner { Future run(Iterable args) { return super.run(args); // [见小节2.6] } } 2.6 CommandRunner.run [-> package:args/command_runner.dart] class CommandRunner { Future run(Iterable args) => new Future.sync(() => runCommand(parse(args))); //见下文 Future runCommand(ArgResults topLevelResults) async { var argResults = topLevelResults; var commands = _commands; Command command; var commandString = executableName; while (commands.isNotEmpty) { ... argResults = argResults.command; //根据命令名从命令列表中找到相应的命令 command = commands[argResults.name]; command._globalResults = topLevelResults; command._argResults = argResults; commands = command._subcommands; //查找到子命令 commandString += " ${argResults.name}"; } // 执行真正对应命令的run()方法 [见小节2.7] return (await command.run()) as T; } } 该方法会根据命令后通过循环遍历查找子命令,直到找到最后的命令为止。但这些命令都直接或者间接继承于FlutterCommand命令 2.7 FlutterCommand.run [-> lib/src/runner/flutter_command.dart] abstract class FlutterCommand extends Command { Future run() { final DateTime startTime = systemClock.now(); return context.run( name: 'command', overrides: {FlutterCommand: () => this}, body: () async { ... try { // [见小节2.8] commandResult = await verifyThenRunCommand(commandPath); } on ToolExit { commandResult = const FlutterCommandResult(ExitStatus.fail); rethrow; } finally { ... } }, ); } } 2.8 FlutterCommand.verifyThenRunCommand [-> lib/src/runner/flutter_command.dart] abstract class FlutterCommand extends Command { Future verifyThenRunCommand(String commandPath) async { await validateCommand(); if (shouldUpdateCache) { await cache.updateAll(await requiredArtifacts); } if (shouldRunPub) { //获取pub await pubGet(context: PubContext.getVerifyContext(name)); final FlutterProject project = await FlutterProject.current(); await project.ensureReadyForPlatformSpecificTooling(); } setupApplicationPackages(); ... // 执行真正对应的命令类 return await runCommand(); } } 该方法先执行pubGet()用于下载pubspec.yaml里配置的依赖,该pub对应执行命令为: $flutterRoot/bin/cache/dart-sdk/bin/pub --verbosity=warning get --no-precompile 最终执行真正对应的命令类的runCommand方法。如果RunCommand.runCommand()过程,见下一篇文章。 附录 /flutter/bin/flutter /flutter/packages/flutter_tools/ - bin/flutter_tools.dart - lib/executable.dart - lib/runner.dart - lib/src/runner/flutter_command_runner.dart - lib/src/runner/flutter_command.dart (FlutterCommand是各种Command的父类) package:args/command_runner.dart
基于Flutter 1.5,从源码视角来深入剖析flutter的channel,相关源码目录见文末附录 一、概述 Flutter 官方提供了一种 Platform Channel 的方案,用于 Dart 和平台之间相互通信。 核心原理: Flutter应用通过Platform Channel将传递的数据编码成消息的形式,跨线程发送到该应用所在的宿主(Android或iOS); 宿主接收到Platform Channel的消息后,调用相应平台的API,也就是原生编程语言来执行相应方法; 执行完成后将结果数据通过同样方式原路返回给应用程序的Flutter部分。 整个过程的消息和响应是异步的,所以不会直接阻塞用户界面。 1.1 流程图 MethodChannel调用流程 FlutterViewHandlePlatformMessage()方法会调用到Java层的FlutterJNI.handlePlatformMessage()方法。 MethodChannel返回流程 1.2 Channel类说明 1) Flutter提供了三种不同的Channel: BasicMessageChannel:传递字符串和半结构化数据 MethodChannel:方法调用 EventChannel:数据流的通信 2) 方法编解码MethodCodec有两个子类: StandardMethodCodec JSONMethodCodec 3) 消息编解码MessageCodec有4个子类: StandardMessageCodec StringCodec JSONMessageCodec BinaryCodec 4) BinaryMessages _handlers的数据类型为map,其中以MethodChannel的name为key,以返回值为Future的Function为value。 //待完善 1.3 实例 以官方提供的Android平台获取电池电量的实例,有Flutter端和Android端两部分代码。 Flutter端代码: class _HomePageState extends State { //创建MethodChannel [见小节2.1] static const platform = const MethodChannel('samples.flutter.io/battery'); Future _getBatteryLevel() async { try { //调用相应通道的方法 [见小节2.2] int batteryLevel = await platform.invokeMethod('getBatteryLevel'); } on PlatformException catch (e) { ... } } } Android端代码: public class MainActivity extends FlutterActivity { private static final String CHANNEL = "samples.flutter.io/battery"; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //创建方法通道 [见小节4.1] new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler( new MethodCallHandler() { public void onMethodCall(MethodCall call, Result result) { if (call.method.equals("getBatteryLevel")) { //调用android端的BatteryManager来获取电池电量信息 int batteryLevel = getBatteryLevel(); if (batteryLevel != -1) { //将函数执行的成功结果回传到Flutter端 result.success(batteryLevel); } else { //将函数执行的失败结果回传到Flutter端 result.error("UNAVAILABLE", "Battery level not available.", null); } } else { result.notImplemented(); } } }); } } 二、Dart层 2.1 MethodChannel初始化 [-> lib/src/services/platform_channel.dart] class MethodChannel { //[见小节2.1.1] const MethodChannel(this.name, [this.codec = const StandardMethodCodec()]); final String name; final MethodCodec codec; } 默认用的是标准方法编解码器StandardMethodCodec 2.1.1 StandardMethodCodec初始化 [-> lib/src/services/message_codecs.dart] class StandardMethodCodec implements MethodCodec { //[见小节2.1.2] const StandardMethodCodec([this.messageCodec = const StandardMessageCodec()]); final StandardMessageCodec messageCodec; } 2.1.2 StandardMessageCodec初始化 [-> lib/src/services/message_codecs.dart] class StandardMessageCodec implements MessageCodec { const StandardMessageCodec(); } 2.2 MethodChannel.invokeMethod [-> lib/src/services/platform_channel.dart] class MethodChannel { Future invokeMethod(String method, [ dynamic arguments ]) async { //[见小节2.3] final ByteData result = await BinaryMessages.send(name, codec.encodeMethodCall(MethodCall(method, arguments)), ); ... final T typedResult = codec.decodeEnvelope(result); return typedResult; } } 该方法主要功能: 创建MethodCall对象[小节2.2.1]; 通过StandardMethodCodec的encodeMethodCall将MethodCall转换为ByteData数据类型[小节2.2.2]; 然后调用BinaryMessages的send来发送消息[小节2.3] 最后,decodeEnvelope来解码结果 2.2.1 MethodCall初始化 [-> lib/src/services/message_codec.dart] class MethodCall { const MethodCall(this.method, [this.arguments]); final String method; //方法名,非空 final dynamic arguments; } 2.2.2 encodeMethodCall [-> lib/src/services/message_codecs.dart] class StandardMethodCodec implements MethodCodec { ByteData encodeMethodCall(MethodCall call) { //创建一个用于写的buffer [见小节2.2.3] final WriteBuffer buffer = WriteBuffer(); //调用StandardMessageCodec将数据写入buffer messageCodec.writeValue(buffer, call.method); messageCodec.writeValue(buffer, call.arguments); return buffer.done(); } } 2.2.3 WriteBuffer初始化 [-> lib/src/foundation/serialization.dart] class WriteBuffer { WriteBuffer() { _buffer = Uint8Buffer(); _eightBytes = ByteData(8); _eightBytesAsList = _eightBytes.buffer.asUint8List(); } Uint8Buffer _buffer; ByteData _eightBytes; Uint8List _eightBytesAsList; ByteData done() { final ByteData result = _buffer.buffer.asByteData(0, _buffer.lengthInBytes); _buffer = null; return result; } ... } 2.3 BinaryMessages.send [-> lib/src/services/platform_messages.dart] class BinaryMessages { static Future send(String channel, ByteData message) { final _MessageHandler handler = _mockHandlers[channel]; if (handler != null) return handler(message); //[见小节2.4] return _sendPlatformMessage(channel, message); } } _mockHandlers是用于调试的。 2.4 BinaryMessages._sendPlatformMessage [-> lib/src/services/platform_messages.dart] static Future _sendPlatformMessage(String channel, ByteData message) { //[见小节2.4.1] final Completer completer = Completer(); //[见小节2.5] ui.window.sendPlatformMessage(channel, message, (ByteData reply) { try { //[见小节6.6] completer.complete(reply); } catch (exception, stack) { ... } }); return completer.future; } 2.4.1 Completer初始化 [-> third_party/dart/sdk/lib/async/future.dart] factory Completer() => new _AsyncCompleter(); 2.4.2 _AsyncCompleter初始化 [-> third_party/dart/sdk/lib/async/future_impl.dart] class _AsyncCompleter extends _Completer { void complete([FutureOr value]) { future._asyncComplete(value); } } abstract class _Completer implements Completer { final _Future future = new _Future(); void complete([FutureOr value]); } 2.5 window.sendPlatformMessage [-> flutter/lib/ui/window.dart] class Window { void sendPlatformMessage(String name, ByteData data, PlatformMessageResponseCallback callback) { final String error = _sendPlatformMessage(name, _zonedPlatformMessageResponseCallback(callback), data); if (error != null) throw new Exception(error); } //[见小节3.1] String _sendPlatformMessage(String name, PlatformMessageResponseCallback callback, ByteData data) native 'Window_sendPlatformMessage'; } 2.5.1 window._zonedPlatformMessageResponseCallback [-> flutter/lib/ui/window.dart] static PlatformMessageResponseCallback _zonedPlatformMessageResponseCallback( PlatformMessageResponseCallback callback) { //储存在注册回调所在的zone区域 final Zone registrationZone = Zone.current; return (ByteData data) { registrationZone.runUnaryGuarded(callback, data); }; } 接下来执行_sendPlatformMessages,这是一个native方法,会调用到Flutter引擎层。 三、引擎层 3.1 _SendPlatformMessage [-> flutter/lib/ui/window/window.cc] void _SendPlatformMessage(Dart_NativeArguments args) { tonic::DartCallStatic(&SendPlatformMessage, args); } void Window::RegisterNatives(tonic::DartLibraryNatives* natives) { natives->Register({ {"Window_defaultRouteName", DefaultRouteName, 1, true}, {"Window_scheduleFrame", ScheduleFrame, 1, true}, {"Window_sendPlatformMessage", _SendPlatformMessage, 4, true}, ... }); } Window.dart中的_sendPlatformMessage()最终对应于引擎层中window.cc的_SendPlatformMessage()方法,为了更好理解引擎中的调用关系,见如下Enggine核心类图 3.2 SendPlatformMessage [-> flutter/lib/ui/window/window.cc] Dart_Handle SendPlatformMessage(Dart_Handle window, const std::string& name, Dart_Handle callback, Dart_Handle data_handle) { UIDartState* dart_state = UIDartState::Current(); if (!dart_state->window()) { return tonic::ToDart("Platform messages can only be sent from the main isolate"); } fml::RefPtr response; if (!Dart_IsNull(callback)) { //PlatformMessageResponseDart对象中采用的是UITaskRunner response = fml::MakeRefCounted( tonic::DartPersistentValue(dart_state, callback), dart_state->GetTaskRunners().GetUITaskRunner()); } if (Dart_IsNull(data_handle)) { dart_state->window()->client()->HandlePlatformMessage( fml::MakeRefCounted(name, response)); } else { tonic::DartByteData data(data_handle); const uint8_t* buffer = static_cast(data.data()); //[见小节3.3] dart_state->window()->client()->HandlePlatformMessage( fml::MakeRefCounted( name, std::vector(buffer, buffer + data.length_in_bytes()), response)); } return Dart_Null(); } 该方法主要功能: 该方法是发送平台消息,则只允许从主isolate中发出,否则会跑出异常 该SendPlatformMessage方法的参数name代表是channel名,data_handle是记录待执行的方法名和参数,callback是执行后回调反馈结果数据的方法 创建PlatformMessageResponseDart对象,保存callback方法 调用RuntimeController的HandlePlatformMessage来处理平台消息 3.3 RuntimeController::HandlePlatformMessage [-> flutter/runtime/runtime_controller.cc] void RuntimeController::HandlePlatformMessage( fml::RefPtr message) { //[见小节3.4] client_.HandlePlatformMessage(std::move(message)); } 3.4 Engine::HandlePlatformMessage [-> flutter/shell/common/engine.cc] static constexpr char kAssetChannel[] = "flutter/assets"; void Engine::HandlePlatformMessage(fml::RefPtr message) { if (message->channel() == kAssetChannel) { HandleAssetPlatformMessage(std::move(message)); } else { //[见小节3.5] delegate_.OnEngineHandlePlatformMessage(std::move(message)); } } 3.5 Shell::OnEngineHandlePlatformMessage [-> flutter/shell/common/shell.cc] constexpr char kSkiaChannel[] = "flutter/skia"; void Shell::OnEngineHandlePlatformMessage( fml::RefPtr message) { if (message->channel() == kSkiaChannel) { HandleEngineSkiaMessage(std::move(message)); return; } //[见小节3.6] task_runners_.GetPlatformTaskRunner()->PostTask( [view = platform_view_->GetWeakPtr(), message = std::move(message)]() { if (view) { view->HandlePlatformMessage(std::move(message)); } }); } 接下来将HandlePlatformMessage的工作交给主线程的PlatformTaskRunner来处理,对于PlatformView在Android平台的实例为PlatformViewAndroid。 3.6 PlatformViewAndroid::HandlePlatformMessage [-> flutter/shell/platform/android/platform_view_android.cc] void PlatformViewAndroid::HandlePlatformMessage( fml::RefPtr message) { JNIEnv* env = fml::jni::AttachCurrentThread(); fml::jni::ScopedJavaLocalRef view = java_object_.get(env); int response_id = 0; if (auto response = message->response()) { response_id = next_response_id_++; pending_responses_[response_id] = response; //保存response } auto java_channel = fml::jni::StringToJavaString(env, message->channel()); if (message->hasData()) { fml::jni::ScopedJavaLocalRef message_array( env, env->NewByteArray(message->data().size())); env->SetByteArrayRegion( message_array.obj(), 0, message->data().size(), reinterpret_cast(message->data().data())); message = nullptr; //[见小节3.7] FlutterViewHandlePlatformMessage(env, view.obj(), java_channel.obj(), message_array.obj(), response_id); } else { message = nullptr; FlutterViewHandlePlatformMessage(env, view.obj(), java_channel.obj(), nullptr, response_id); } } PlatformViewAndroid对象的pending_responses_是一个map数据类型,里面记录着所有的待响应的PlatformMessageResponse数据。 3.7 FlutterViewHandlePlatformMessage [-> flutter/shell/platform/android/platform_view_android_jni.cc] void FlutterViewHandlePlatformMessage(JNIEnv* env, jobject obj, jstring channel, jobject message, jint responseId) { env->CallVoidMethod(obj, g_handle_platform_message_method, channel, message, responseId); } g_handle_platform_message_method方法所对应的便是Java层的FlutterJNI.java中的handlePlatformMessage()方法。 四、宿主层 4.1 MethodChannel初始化 [-> io/flutter/plugin/common/MethodChannel.java] public final class MethodChannel { private final BinaryMessenger messenger; private final String name; private final MethodCodec codec; public MethodChannel(BinaryMessenger messenger, String name) { //创建MethodChannel this(messenger, name, StandardMethodCodec.INSTANCE); } public MethodChannel(BinaryMessenger messenger, String name, MethodCodec codec) { this.messenger = messenger; this.name = name; this.codec = codec; } } 再来看看MethodChannel的成员变量messenger,是一个BinaryMessenger类型的接口,由前面[1.3]是通过getFlutterView()方法所获取的。 4.1.1 FlutterActivity.getFlutterView [-> io/flutter/app/FlutterActivity.java] public class FlutterActivity extends Activity implements FlutterView.Provider, PluginRegistry, ViewFactory { private final FlutterActivityDelegate delegate = new FlutterActivityDelegate(this, this); private final FlutterView.Provider viewProvider = delegate; public FlutterView getFlutterView() { return viewProvider.getFlutterView(); //[见小节4.1.2] } } 4.1.2 FlutterActivityDelegate.getFlutterView [-> io/flutter/app/FlutterActivityDelegate.java] public final class FlutterActivityDelegate implements FlutterActivityEvents, FlutterView.Provider, PluginRegistry { public FlutterView getFlutterView() { return flutterView; } } 此处的flutterView的赋值过程是在FlutterActivityDelegate的onCreate()过程,如下所示。 public void onCreate(Bundle savedInstanceState) { ... FlutterNativeView nativeView = viewFactory.createFlutterNativeView(); flutterView = new FlutterView(activity, null, nativeView); } 4.2 MethodChannel.setMethodCallHandler [-> io/flutter/plugin/common/MethodChannel.java] public final class MethodChannel { public void setMethodCallHandler(final @Nullable MethodCallHandler handler) { //[见小节4.2.1] messenger.setMessageHandler(name, handler == null ? null : new IncomingMethodCallHandler(handler)); } 此处的messenger是指FlutterView,此处的handler为IncomingMethodCallHandler。 4.2.1 FlutterView.setMessageHandler [-> io/flutter/view/FlutterView.java] public void setMessageHandler(String channel, BinaryMessageHandler handler) { //[见小节4.2.2] mNativeView.setMessageHandler(channel, handler); } 4.2.2 FlutterNativeView.setMessageHandler [-> FlutterNativeView.java] public void setMessageHandler(String channel, BinaryMessageHandler handler) { //[见小节4.2.3] dartExecutor.setMessageHandler(channel, handler); } 4.2.3 DartExecutor.setMessageHandler [-> io/flutter/embedding/engine/dart/DartExecutor.java] public void setMessageHandler(@NonNull String channel, @Nullable BinaryMessenger.BinaryMessageHandler handler) { //[见小节4.2.4] messenger.setMessageHandler(channel, handler); } 4.2.4 DartMessenger.setMessageHandler [-> io/flutter/embedding/engine/dart/DartMessenger.java] class DartMessenger implements BinaryMessenger, PlatformMessageHandler { private final Map messageHandlers; public void setMessageHandler(@NonNull String channel, @Nullable BinaryMessenger.BinaryMessageHandler handler) { if (handler == null) { messageHandlers.remove(channel); } else { //将channel和handler放入到messageHandlers messageHandlers.put(channel, handler); } } } messageHandlers记录着每一个channel所对应的handler方法。 再回到[小节4.2],可知此处handler为IncomingMethodCallHandler,初始化过程见[小节4.2.5]。 4.2.5 IncomingMethodCallHandler初始化 [-> io/flutter/plugin/common/MethodChannel.java] public final class MethodChannel { private final class IncomingMethodCallHandler implements BinaryMessageHandler { private final MethodCallHandler handler; IncomingMethodCallHandler(MethodCallHandler handler) { this.handler = handler; } } } 五、Java层 再回到小节[3.7]FlutterViewHandlePlatformMessage方法,经过JNI将调用FlutterJNI.handlePlatformMessage()方法。 5.1 FlutterJNI.handlePlatformMessage [-> flutter/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java] private void handlePlatformMessage(final String channel, byte[] message, final int replyId) { if (platformMessageHandler != null) { platformMessageHandler.handleMessageFromDart(channel, message, replyId); } } FlutterNativeView初始化过程,attach中会执行DartExecutor.onAttachedToJNI()来设置platformMessageHandler,其值等于DartMessenger,如下所示。 5.1.1 DartExecutor.onAttachedToJNI [-> io/flutter/embedding/engine/dart/DartExecutor.java] public class DartExecutor implements BinaryMessenger { private final FlutterJNI flutterJNI; private final DartMessenger messenger; public DartExecutor(@NonNull FlutterJNI flutterJNI) { this.flutterJNI = flutterJNI; //创建DartMessenger对象 this.messenger = new DartMessenger(flutterJNI); } public void onAttachedToJNI() { //[见小节5.1.2] flutterJNI.setPlatformMessageHandler(messenger); } 5.1.2 FlutterJNI.setPlatformMessageHandler [-> flutter/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java] public void setPlatformMessageHandler(@Nullable PlatformMessageHandler platformMessageHandler) { this.platformMessageHandler = platformMessageHandler; } 5.2 DartMessenger.handleMessageFromDart [-> io/flutter/embedding/engine/dart/DartMessenger.java] public void handleMessageFromDart(final String channel, byte[] message, final int replyId) { //从messageHandlers中获取handler BinaryMessenger.BinaryMessageHandler handler = messageHandlers.get(channel); if (handler != null) { try { final ByteBuffer buffer = (message == null ? null : ByteBuffer.wrap(message)); //[见小节5.3] [见小节5.2.1] handler.onMessage(buffer, new Reply(flutterJNI, replyId)); } catch (Exception ex) { ... } } else { ... } } 由[小节4.2.4]可知,此处的handler为IncomingMethodCallHandler,先来看看其成员变量Reply的初始化过程。 5.2.1 Reply初始化 [-> io/flutter/embedding/engine/dart/DartMessenger.java] class DartMessenger implements BinaryMessenger, PlatformMessageHandler { private static class Reply implements BinaryMessenger.BinaryReply { private final FlutterJNI flutterJNI; private final int replyId; private final AtomicBoolean done = new AtomicBoolean(false); Reply(@NonNull FlutterJNI flutterJNI, int replyId) { this.flutterJNI = flutterJNI; this.replyId = replyId; } } } 5.3 IncomingMethodCallHandler.onMessage [-> io/flutter/plugin/common/MethodChannel.java] private final class IncomingMethodCallHandler implements BinaryMessageHandler { public void onMessage(ByteBuffer message, final BinaryReply reply) { //从消息中解码出MethodCall final MethodCall call = codec.decodeMethodCall(message); try { //[见小节5.4] handler.onMethodCall(call, new Result() { @Override public void success(Object result) { //[见小节6.1] reply.reply(codec.encodeSuccessEnvelope(result)); } @Override public void error(String errorCode, String errorMessage, Object errorDetails) { reply.reply(codec.encodeErrorEnvelope(errorCode, errorMessage, errorDetails)); } @Override public void notImplemented() { reply.reply(null); } }); } catch (RuntimeException e) { ... } } } 5.4 MethodCallHandler.onMethodCall new MethodCallHandler() { public void onMethodCall(MethodCall call, Result result) { if (call.method.equals("getBatteryLevel")) { //调用android端的BatteryManager来获取电池电量信息 int batteryLevel = getBatteryLevel(); if (batteryLevel != -1) { //将结果返回 result.success(batteryLevel); } else { result.error("UNAVAILABLE", "Battery level not available.", null); } } else { result.notImplemented(); } } } 当方法执行成功后,会调用result.success()方法,再回到[小节5.3],可知会执行相对应BinaryReply.reply()方法。 六、回传结果 6.1 Reply.reply [-> io/flutter/embedding/engine/dart/DartMessenger.java] class DartMessenger implements BinaryMessenger, PlatformMessageHandler { private static class Reply implements BinaryMessenger.BinaryReply { public void reply(ByteBuffer reply) { if (reply == null) { flutterJNI.invokePlatformMessageEmptyResponseCallback(replyId); } else { //[见小节6.2] flutterJNI.invokePlatformMessageResponseCallback(replyId, reply, reply.position()); } } } } 6.2 invokePlatformMessageResponseCallback [-> io/flutter/embedding/engine/FlutterJNI.java] public void invokePlatformMessageResponseCallback(int responseId, ByteBuffer message, int position) { if (isAttached()) { //[见小节6.3] nativeInvokePlatformMessageResponseCallback( nativePlatformViewId, responseId, message, position); } } 6.3 InvokePlatformMessageResponseCallback [-> platform_view_android_jni.cc] static void InvokePlatformMessageResponseCallback(JNIEnv* env, jobject jcaller, jlong shell_holder, jint responseId, jobject message, jint position) { ANDROID_SHELL_HOLDER->GetPlatformView() ->InvokePlatformMessageResponseCallback(env, // responseId, // message, // position // ); } 6.4 InvokePlatformMessageResponseCallback [-> flutter/shell/platform/android/platform_view_android.cc] void PlatformViewAndroid::InvokePlatformMessageResponseCallback( JNIEnv* env, jint response_id, jobject java_response_data, jint java_response_position) { //从pending_responses_根据response_id来查找PlatformMessageResponse auto it = pending_responses_.find(response_id); uint8_t* response_data = static_cast(env->GetDirectBufferAddress(java_response_data)); //返回结果数据 std::vector response = std::vector(response_data, response_data + java_response_position); auto message_response = std::move(it->second); pending_responses_.erase(it); //[见小节6.5] message_response->Complete(std::make_unique(std::move(response))); } message_responsed所对应的真实类型为PlatformMessageResponseDart,赋值过程[见小节3.2]。 6.5 Complete [-> flutter/lib/ui/window/platform_message_response_dart.cc] void PlatformMessageResponseDart::Complete(std::unique_ptr data) { is_complete_ = true; //post到UI线程来执行 ui_task_runner_->PostTask(fml::MakeCopyable( [callback = std::move(callback_), data = std::move(data)]() mutable { std::shared_ptr dart_state = callback.dart_state().lock(); tonic::DartState::Scope scope(dart_state); Dart_Handle byte_buffer = WrapByteData(std::move(data)); //[见小节6.6] tonic::DartInvoke(callback.Release(), {byte_buffer}); })); } 到此就发生了线程切换操作,将任务post到UI线程的UITaskRunner来执行。 6.6 DartInvoke [-> third_party/tonic/logging/dart_invoke.cc] Dart_Handle DartInvoke(Dart_Handle closure, std::initializer_list args) { int argc = args.size(); Dart_Handle* argv = const_cast(args.begin()); Dart_Handle handle = Dart_InvokeClosure(closure, argc, argv); return handle; } 该方法参数closure,也就是PlatformMessageResponseDart中的callback_,不断回溯可知所对应方法便是小节[2.4]sendPlatformMessage()的第3个参数,如下所示。 (ByteData reply) { try { completer.complete(reply); //[见小节6.7] } catch (exception, stack) { ... } } 6.7 _AsyncCompleter.complete [-> third_party/dart/sdk/lib/async/future_impl.dart] class _AsyncCompleter extends _Completer { void complete([FutureOr value]) { future._asyncComplete(value); //[见小节6.8] } } 6.8 _Future._asyncComplete [-> third_party/dart/sdk/lib/async/future_impl.dart] class _Future implements Future { void _asyncComplete(FutureOr value) { if (value is Future) { _chainFuture(value); return; } _setPendingComplete(); //设置状态为_statePendingComplete //[见小节6.9] _zone.scheduleMicrotask(() { _completeWithValue(value); }); } } 通过scheduleMicrotask()将任务封装成微任务交给UI线程 6.9 _Future._completeWithValue [-> third_party/dart/sdk/lib/async/future_impl.dart] void _completeWithValue(T value) { _FutureListener listeners = _removeListeners(); _setValue(value); _propagateToListeners(this, listeners); //[见小节6.10] } 6.10 _Future._propagateToListeners [-> third_party/dart/sdk/lib/async/future_impl.dart] static void _propagateToListeners(_Future source, _FutureListener listeners) { while (true) { ... //一般情况下futures只有一个监听器 while (listeners._nextListener != null) { _FutureListener listener = listeners; listeners = listener._nextListener; listener._nextListener = null; _propagateToListeners(source, listener); } _FutureListener listener = listeners; //待传回的返回结果数据 final sourceResult = source._resultOrListeners; if (hasError || listener.handlesValue || listener.handlesComplete) { Zone zone = listener._zone; ... Zone oldZone; if (!identical(Zone.current, zone)) { //当current不是该llistener所在的zone,则切换current oldZone = Zone._enter(zone); } ... void handleValueCallback() { //【见小节6.11】 listenerValueOrError = listener.handleValue(sourceResult); } if (listener.handlesComplete) { handleWhenCompleteCallback(); } else if (!hasError) { if (listener.handlesValue) { handleValueCallback(); } } else { ... } if (oldZone != null) Zone._leave(oldZone); //回到原来的zone } _Future result = listener.result; listeners = result._removeListeners(); ... source = result; } } 6.11 _FutureListener.handleValue [-> third_party/dart/sdk/lib/async/future_impl.dart] class _FutureListener { FutureOr handleValue(S sourceResult) { return _zone.runUnary, S>(_onValue, sourceResult); } } 七、总结 MethodChannel的执行流程涉及到主线程和UI线程的交互,代码从Dart到C++再到Java层,执行完相应逻辑后原路返回,从Java层到C++层再到Dart层。 [小节3.5] Shell::OnEngineHandlePlatformMessage 将任务发送给主线程 [小节6.5] PlatformMessageResponseDart::Complete 将任务发送给UI线程