本文会从SurfaceFlinger
启动和画面显示流程2个方面简单分析理解。
init进程启动SurfaceFlinger的大致流程如下:
一、SurfaceFlinger
启动
1.SurfaceFlinger
编译。
首先来看frameworks/native/services/surfaceflinger/Android.bp
文件
// https://android-opengrok.bangnimang.net/android-12.0.0_r3/xref/frameworks/native/services/surfaceflinger/Android.bp?r=f824b538
cc_binary {
name: "surfaceflinger",
defaults: ["libsurfaceflinger_binary"],
init_rc: ["surfaceflinger.rc"],
srcs: [
":surfaceflinger_binary_sources",
// Note: SurfaceFlingerFactory is not in the filegroup so that it
// can be easily replaced.
"SurfaceFlingerFactory.cpp",
],
shared_libs: [
"libSurfaceFlingerProp",
],
logtags: ["EventLog/EventLogTags.logtags"],
}
cc_binary
表示编译成可执行的二进制文件surfaceflinger
。
可执行的二进制文件在Linux中,shell中,我们手动执行方式为输入./xxx
,在Linux中要如何调用呢?实际用到的是Linux
中的execv函数
。
Android.bp
中的init_rc
对应的是早期(android8及以前的版本)的Android.mk
文件中定义的LOCAL_INIT_RC
。
build/make/core/base_rules.mk
中会使用该宏,
//https://android-opengrok.bangnimang.net/android-12.0.0_r3/xref/build/make/core/base_rules.mk?r=9bbb60e1
ifndef LOCAL_IS_HOST_MODULE
# Rule to install the module's companion init.rc.
ifneq ($(strip $(LOCAL_FULL_INIT_RC)),)
my_init_rc := $(LOCAL_FULL_INIT_RC)
else
my_init_rc := $(foreach rc,$(LOCAL_INIT_RC_$(my_32_64_bit_suffix)) $(LOCAL_INIT_RC),$(LOCAL_PATH)/$(rc))
endif
ifneq ($(strip $(my_init_rc)),)
# Make doesn't support recovery as an output partition, but some Soong modules installed in recovery
# have init.rc files that need to be installed alongside them. Manually handle the case where the
# output file is in the recovery partition.
my_init_rc_path := $(if $(filter $(TARGET_RECOVERY_ROOT_OUT)/%,$(my_module_path)),$(TARGET_RECOVERY_ROOT_OUT)/system/etc,$(TARGET_OUT$(partition_tag)_ETC))
my_init_rc_pairs := $(foreach rc,$(my_init_rc),$(rc):$(my_init_rc_path)/init/$(notdir $(rc)))
my_init_rc_installed := $(foreach rc,$(my_init_rc_pairs),$(call word-colon,2,$(rc)))
# Make sure we only set up the copy rules once, even if another arch variant
# shares a common LOCAL_INIT_RC.
my_init_rc_new_pairs := $(filter-out $(ALL_INIT_RC_INSTALLED_PAIRS),$(my_init_rc_pairs))
my_init_rc_new_installed := $(call copy-many-init-script-files-checked,$(my_init_rc_new_pairs))
ALL_INIT_RC_INSTALLED_PAIRS += $(my_init_rc_new_pairs)
rc文件目录规范:
/system/etc/init/ 用于核心系统功能,例如SurfaceFlinger、MediaService和logd等。
/vendor/etc/init/ 用于芯片供应商的一些核心操作或者守护进程功能。
/odm/etc/init/ 用于设备制造厂商的功能,比如传感器和其他外围设备所需的操作或者守护进程。
可参考https://android-opengrok.bangnimang.net/android-12.0.0_r3/xref/system/core/init/ 中的README
Android编译完成surfaceflinger
这个模块后,会把surfaceflinger.rc
放到编译生成的out目录中的/system/etc/init/
目录下。
2.解析对应的rc文件,启动surfaceflinger
系统启动的时候,system/core/init/init.cpp
里面的LoadBootScripts函数会解析rc文件。
//https://android-opengrok.bangnimang.net/android-12.0.0_r3/xref/system/core/init/init.cpp?r=cedb057e
static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
Parser parser = CreateParser(action_manager, service_list);
std::string bootscript = GetProperty("ro.boot.init_rc", "");
if (bootscript.empty()) {
parser.ParseConfig("/system/etc/init/hw/init.rc");
if (!parser.ParseConfig("/system/etc/init")) {
late_import_paths.emplace_back("/system/etc/init");
}
// late_import is available only in Q and earlier release. As we don't
// have system_ext in those versions, skip late_import for system_ext.
parser.ParseConfig("/system_ext/etc/init");
if (!parser.ParseConfig("/vendor/etc/init")) {
late_import_paths.emplace_back("/vendor/etc/init");
}
if (!parser.ParseConfig("/odm/etc/init")) {
late_import_paths.emplace_back("/odm/etc/init");
}
if (!parser.ParseConfig("/product/etc/init")) {
late_import_paths.emplace_back("/product/etc/init");
}
} else {
parser.ParseConfig(bootscript);
}
}
frameworks/native/services/surfaceflinger/surfaceflinger.rc
定义如下。
//https://android-opengrok.bangnimang.net/android-12.0.0_r3/xref/frameworks/native/services/surfaceflinger/surfaceflinger.rc?r=60f3ab27
service surfaceflinger /system/bin/surfaceflinger
class core animation
user system
group graphics drmrpc readproc
capabilities SYS_NICE
onrestart restart zygote
task_profiles HighPerformance
socket pdx/system/vr/display/client stream 0666 system graphics u:object_r:pdx_display_client_endpoint_socket:s0
socket pdx/system/vr/display/manager stream 0666 system graphics u:object_r:pdx_display_manager_endpoint_socket:s0
socket pdx/system/vr/display/vsync stream 0666 system graphics u:object_r:pdx_display_vsync_endpoint_socket:s0
service
表示以服务的形式来启动进程,surfaceflinger
是进程名字,/system/bin/surfaceflinger
是可执行程序的路径。
class core
,表示 surfaceflinger属于core服务,后面加个animation表示surfaceflinger服务将bootanim启动(surfaceflinger最后会启动StartPropertySetThread从而启动bootanim)。
init.rc中有一句
//https://android-opengrok.bangnimang.net/android-12.0.0_r3/xref/system/core/rootdir/init.rc?r=03067a21
class_start core
class_start core
这样一条命令被执行,就会启动类型为core的所有service。
inti.rc被init_parser.cpp 解析后,init进程的main()函数中会通过调用action_for_each_trigger()函数来把需要执行的"action"加入到执行列表的action_queue中,进入while()循环依次取出执行队列action_queue中的command执行。
走到action_manager.cpp
中。
//https://android-opengrok.bangnimang.net/android-12.0.0_r3/raw/system/core/init/action_manager.cpp?r=52c8422e
void ActionManager::ExecuteOneCommand() {
{
auto lock = std::lock_guard{event_queue_lock_};
// Loop through the event queue until we have an action to execute
while (current_executing_actions_.empty() && !event_queue_.empty()) {
for (const auto& action : actions_) {
if (std::visit([&action](const auto& event) { return action->CheckEvent(event); },
event_queue_.front())) {
current_executing_actions_.emplace(action.get());
}
}
event_queue_.pop();
}
}
if (current_executing_actions_.empty()) {
return;
}
auto action = current_executing_actions_.front();
if (current_command_ == 0) {
std::string trigger_name = action->BuildTriggersString();
LOG(INFO) << "processing action (" << trigger_name << ") from (" << action->filename()
<< ":" << action->line() << ")";
}
action->ExecuteOneCommand(current_command_);
// If this was the last command in the current action, then remove
// the action from the executing list.
// If this action was oneshot, then also remove it from actions_.
++current_command_;
if (current_command_ == action->NumCommands()) {
current_executing_actions_.pop();
current_command_ = 0;
if (action->oneshot()) {
auto eraser = [&action](std::unique_ptr<Action>& a) { return a.get() == action; };
actions_.erase(std::remove_if(actions_.begin(), actions_.end(), eraser),
actions_.end());
}
}
}
然后走到action.cpp
中
//https://android-opengrok.bangnimang.net/android-12.0.0_r3/raw/system/core/init/action.cpp?r=ce44c8ac
void Action::ExecuteOneCommand(std::size_t command) const {
// We need a copy here since some Command execution may result in
// changing commands_ vector by importing .rc files through parser
Command cmd = commands_[command];
ExecuteCommand(cmd);
}
void Action::ExecuteAllCommands() const {
for (const auto& c : commands_) {
ExecuteCommand(c);
}
}
void Action::ExecuteCommand(const Command& command) const {
android::base::Timer t;
auto result = command.InvokeFunc(subcontext_);
auto duration = t.duration();
// Any action longer than 50ms will be warned to user as slow operation
if (!result.has_value() || duration > 50ms ||
android::base::GetMinimumLogSeverity() <= android::base::DEBUG) {
std::string trigger_name = BuildTriggersString();
std::string cmd_str = command.BuildCommandString();
LOG(INFO) << "Command '" << cmd_str << "' action=" << trigger_name << " (" << filename_
<< ":" << command.line() << ") took " << duration.count() << "ms and "
<< (result.ok() ? "succeeded" : "failed: " + result.error().message());
}
}
Result<void> Command::InvokeFunc(Subcontext* subcontext) const {
if (subcontext) {
if (execute_in_subcontext_) {
return subcontext->Execute(args_);
}
auto expanded_args = subcontext->ExpandArgs(args_);
if (!expanded_args.ok()) {
return expanded_args.error();
}
return RunBuiltinFunction(func_, *expanded_args, subcontext->context());
}
return RunBuiltinFunction(func_, args_, kInitContext);
}
Result<void> RunBuiltinFunction(const BuiltinFunction& function,
const std::vector<std::string>& args, const std::string& context) {
auto builtin_arguments = BuiltinArguments(context);
builtin_arguments.args.resize(args.size());
builtin_arguments.args[0] = args[0];
for (std::size_t i = 1; i < args.size(); ++i) {
auto expanded_arg = ExpandProps(args[i]);
if (!expanded_arg.ok()) {
return expanded_arg.error();
}
builtin_arguments.args[i] = std::move(*expanded_arg);
}
return function(builtin_arguments);
}
这里从ExecuteOneCommand->InvokeFunc->RunBuiltinFunction->BuiltinFunction
builtins.h
中定义了BuiltinFunction
。
//https://android-opengrok.bangnimang.net/android-12.0.0_r3/raw/system/core/init/builtins.h?r=ce44c8ac
namespace android {
namespace init {
using BuiltinFunction = std::function<Result<void>(const BuiltinArguments&)>;
struct BuiltinFunctionMapValue {
bool run_in_subcontext;
BuiltinFunction function;
};
using BuiltinFunctionMap = KeywordMap<BuiltinFunctionMapValue>;
const BuiltinFunctionMap& GetBuiltinFunctionMap();
extern std::vector<std::string> late_import_paths;
} // namespace init
} // namespace android
这里使用了using
,指定别名。
using BuiltinFunction = std::function<Result<void>(const BuiltinArguments&)>;
using的写法把别名的名字强制分离到了左边,而把别名指向的放在了右边,比较清晰。
C++11
以后在标准库里引入了std::function
模板类,这个模板概括了函数指针的概念。函数指针只能指向一个函数,而std::function
对象可以代表任何可以调用的对象,比如说任何可以被当作函数一样调用的对象。std::function
的实例可以存储、复制和调用任何可调用对象。
也就是,这个函数的作用就是把builtin_arguments
对象存储后返回。
Linux
中的builtin
:运行一个builtin shell
,向它传递参数,并获取它的退出状态。
builtin
命令用于执行指定的bash内建命令,builtin
命令调用的bash
内建命令优先于同名的外部命令及同名的shell
函数。 返回该内建命令执行的返回值,除非传递的不是bash
内建命令或该内建命令被禁用。
Action
中的function
,只是返回了需要执行的命令对象,不是真正执行的地方。
builtins.cpp
中的do_start
会调用service.cpp
中的Start
函数
https://android-opengrok.bangnimang.net/android-12.0.0_r3/raw/system/core/init/builtins.cpp?r=cedb057e
static Result<void> do_start(const BuiltinArguments& args) {
Service* svc = ServiceList::GetInstance().FindService(args[1]);
if (!svc) return Error() << "service " << args[1] << " not found";
if (auto result = svc->Start(); !result.ok()) {
return ErrorIgnoreEnoent() << "Could not start service: " << result.error();
}
return {};
}
system/core/init/service.cpp
中的ExpandArgsAndExecv
。
//https://android-opengrok.bangnimang.net/android-12.0.0_r3/raw/system/core/init/service.cpp?r=f3fea377
Result<void> Service::Start() {
....
if (!ExpandArgsAndExecv(args_, sigstop_)) {
PLOG(ERROR) << "cannot execv('" << args_[0]
<< "'). See the 'Debugging init' section of init's README.md for tips";
}
....
}
static bool ExpandArgsAndExecv(const std::vector<std::string>& args, bool sigstop) {
std::vector<std::string> expanded_args;
std::vector<char*> c_strings;
expanded_args.resize(args.size());
c_strings.push_back(const_cast<char*>(args[0].data()));
for (std::size_t i = 1; i < args.size(); ++i) {
auto expanded_arg = ExpandProps(args[i]);
if (!expanded_arg.ok()) {
LOG(FATAL) << args[0] << ": cannot expand arguments': " << expanded_arg.error();
}
expanded_args[i] = *expanded_arg;
c_strings.push_back(expanded_args[i].data());
}
c_strings.push_back(nullptr);
if (sigstop) {
kill(getpid(), SIGSTOP);
}
return execv(c_strings[0], c_strings.data()) == 0;
}
service.cpp
中的ExpandArgsAndExecv
将args解析一下,然后调用execv
执行。这里才是真正执行builtin
命令的地方。
通过Linux
执行execve
函数来执行二进制可执行文件surfaceflinger
(前面通过bp
文件定义cc_binary
编译的),从而启动了surfaceflinger
这个service
。
Action执行的路径:
再简单一点理解就是,init
进程解析init.rc
和surfaceflinger.rc
,然后执行/system/bin/surfaceflinger
,从而启动了surfaceflinger
服务进程。
执行ps -A | grep surfaceflinger,查看进程。存在对应信息,表示surfaceflinger
已经启动。
二、SurfaceFlinger
画面显示流程
https://www.jianshu.com/p/657336b545bd
surfaceflinger服务的main函数入口在main_surfaceflinger,主要操作有:
启动Hidl服务,主要是DisplayService
启动线程池
初始化SurfaceFlinger
将SurfaceFlinger和GpuService注册到ServiceManager
启动SurfaceFlinger线程
HIDL在Android10中已经废弃,功能整合到AIDL中了。
https://source.android.google.cn/docs/core/graphics
官方文档中定义:
无论开发者使用什么渲染 API,一切内容都会渲染到 Surface 上。Surface 表示缓冲区队列中的生产方,而缓冲区队列通常会被 SurfaceFlinger 消耗。在 Android 平台上创建的每个窗口都由 Surface 提供支持。所有被渲染的可见 Surface 都被 SurfaceFlinger 合成到屏幕。
图像流消耗方
图像流的最常见消耗方是 SurfaceFlinger,该系统服务会消耗当前可见的 Surface,并使用窗口管理器中提供的信息将它们合成到屏幕。SurfaceFlinger 是可以修改所显示部分内容的唯一服务。SurfaceFlinger 使用 OpenGL 和 Hardware Composer 来合成一组 Surface。
SurfaceFlinger 接受缓冲区,对它们进行合成,然后发送到屏幕。WindowManager 为 SurfaceFlinger 提供缓冲区和窗口元数据,而 SurfaceFlinger 可使用这些信息将 Surface 合成到屏幕。
就类似这种:
AndroidO之前版本下的显示实现框架如下图所示:
那么在AndroidO及以后版本,随着HAL进程独立化,显示系统实现框架也有所变化,如下图所示:
应用程序可以通过Skia来绘制2D图形,也可以用OpenGL来绘制3D图形,SurfaceFlinger通过OpenGL来混合图形到指定的Surface上,然后这个Surface与其他没有被SurfaceFlinger合成的图层一起送往HWC进行合成。
Surface
:上层图形绘制的画板,Canvas是画笔,上层通过调用Canvas的API向Surface上绘制图形(产生图元)。Surface内部存在多个缓冲区,形成一个BufferQueue
。SurfaceFlinger
:SurfaceFlinger
消费了Application
(SurfaceFlinger
相对Application
是消费者)生成的图元(基本图元有点、线、多边形等,图元就是指图形数据),通过HWC Service
合成Layer, HWC Service把合成的数据交给DRM去输出完成app画面显示到屏幕上。
Layers and Displays
官方文档定义:
Layers and displays are two primitives that represent composition work and interactions with the display hardware.
出处:https://www.jianshu.com/p/f96ab6646ae3
APP绘画的画布是由SurfaceFlinger提供的,而画布是一块共享内存,APP向SurfaceFlinger申请到画布,是将共享内存的地址映射到自身进程空间。 App负责在画布上作画,画完的作品提交给SurfaceFlinger, 这个提交操作并不是把内存复制一份给SurfaceFlinger,而是把共享内存的控制权交还给SurfaceFlinger, SurfaceFlinger把拿来的多个应用的共享内存再送给HWC Service去合成, HWC Service把合成的数据交给DRM去输出完成app画面显示到屏幕上的过程。
DRM深入可参考这里。
DRM(Direct Rendering Manager)学习简介
APP的画面要显示到屏幕上大致上要经过如下图所示系统组件的处理:
图元从Application产生,到SurfaceFlinger消费,关键点在BufferQueue
的理解。
这一系列文章架构讲得非常详细,而且代码很少,大部分代码用省略号代替,阅读很方便,不会迷失在代码中。
Android画面显示流程分析(3)
另外,SurfaceFlinger
中的SW Vsync
模型,也是理解SurfaceFlinger
工作原理中的重要一环。
Android SurfaceFlinger SW Vsync模型
而关于详细的代码跳转,可参考这一系列。
Android 重学系列 SurfaceFlinger的概述
重学系列的代码很详细,但是容易迷失,要记得抓住主线,重点,带着问题去看才行,看到后面,我都看晕了,因为涉及到的东西太多了。后面捋顺了再写一篇SurfaceFlinger
代码流程分析。