Fuchsia - 简析

一点猜测

Fuchsia 是为了取代 Android 的吗?

我觉得不是的,因为现在 Android 作为移动平台的操作系统已经非常成熟,暂时也没有遇到影响演进的瓶颈,Fuchsia 如果是为了代替 Android 而做的话则不合逻辑。

那么 Fuchsia 为何而生?

谷歌可能想让 Fuchsia 成为一个兼容 PC/平板/手机/IOT 的统一平台,虽然目前 Android 有能力运行在 平板/Watch/PC/IOT 设备上,但实际除了手机,其他平台都是不温不火。尤其是 PC/平板 设备上。Android 就目前架构来说还是不合适 PC 这种场景。
从我的观点来说,Android 架构之初过于紧凑。其一 Runtime 限定为 JVM 变种,包括 Framework 等重要系统组成部分以来 JVM Runtime 环境,虽然也可以通过在 App 中附带其他 Runtime 和 Framework 来解决此问题,但是很显然如果想使用 Android Framework 则必须启动 JVM Runtime,并且每个 App 都要导入单独的 Framework 实例,造成大量资源浪费而且无法形成整体;其二 UI Framework 亦是为手机等小屏设备所设计,虽然现在引入了分屏,甚至多显示器支持,但是多数 App 是无法也不准备为其优化的。
还有一点也是从谷歌角度来说,谷歌看上去不希望再继续以来 Linux 内核。一是 GPL 开源协议的问题;二是谷歌可能希望另起炉灶,这对于技术成熟的谷歌来说可能不是什么复杂的工程。

那么如何验证我的猜测

现支持的架构

先来看一下支持的 CPU 架构

  • ARM64
  • X86(32/64)

支持的平台

  • Generic-ARM
  • PC

支持的一些硬件协议

  • PCIE/PCI
  • HDCP(HDMI)
  • INTEL_RNG
  • HID
  • INTEL_HDA/GPU
  • ACPI

官方建议运行的设备

  • Acer Switch Alpha 12
  • Intel NUC (also this)
  • Pixelbook

可见对 PC 平台支持的很周到了,现在主要支持 X86 和 ARM 设备

Android 会被 Fuchsia 取代吗?

我觉得在 Fuchsia 完全成熟之后是完全有可能的,从架构来讲,Fuchsia 的 Framework 分为前端和后端,后端包括一些服务和库(可能是 native 库/Dart/Go 库);而前端则会有非常多种,而且可以随时添加。

就目前来讲 Fuchsia 支持的前端开发语言/框架包括:

  • C/C++
  • Dart
  • FIDL
  • Go
  • Rust
  • Flutter modules - how to write a graphical module using Flutter

而对语言的支持,Fuchsia 在 Topaz 层抽象出了一个 Runtime 库,用于存放所支持语言的运行时

而目前支持的 Runtime 包括:

  • chromium
  • dart
  • dart_runner
  • flutter_runner
  • web_runner
  • web_runner_prototype
  • web_view

在这里插入图片描述

而某天出现一个 Android Runner 是完全有可能的,并且 Fuchsia 已经开始移植 libc 以及 Android 一些 lib

在这里插入图片描述

所以,在 Fuchsia 上市初期,一定会通过兼容已有的 Android 应用来度过原始应用匮乏的时期。不过说起来从 Fuchsia 的架构设计来看,并没有要求前端一定要用何种语言或者框架开发,甚至移植过来的 Android Framework 可能被当作主力 Runtime 也不一定,就像 Chrome OS 那样。只是官方推荐的还是 Flutter 框架。

所以,当 Android 成为 Fuchsia 的子集之后,Android 系统本身可能会被取代的,而 Android Framework 会在成熟的 Fuchsia 平台上继续演进一段时间直到完全淘汰。

四层结构

Fuchsia 系统源码分为四层:

  • Zircon (内核)
  • Garnet (平台相关基础库和服务)
  • Peridot (系统框架和相关)
  • Topaz (Runtime/前端框架和系统UI/系统程序)

Zircon

Zircon 是 Fuchsia 的内核,谷歌在文档中说 “Zircon 不是 Linux” 足以透露其对抛弃 Linux 的野心。
Zircon 继承自 LK 微内核 https://github.com/littlekernel/lk, 这是一个嵌入式实时内核,但不包括现在 Zircon 的 MMU/System Call 的实现。

Core

Zircon 是微内核架构,核心代码无非完成以下核心任务:

  • 多任务调度
  • MP 多处理器支持/管理
  • 时钟管理
  • IPC 通讯
  • IO

内核核心代码

当然 Zircon 内核远远不止这些,一些必须的功能则交给内核外围实现,他们仍然属于内核部分

Kernel Object

Zircon 与 Linux 这些老前辈有些不同,Zircon 是由 C++ 作为主体 + 少量平台实现的汇编开发的。

使用 C++ 对于内核来说可能有些大胆,但是在设备 Ram 富余并且内存管理完善的
现在来说也不失为一种选择,并且使用 C++ 在内核架构和编码上还带来了难以估量的好处:

Zircon 中的一切使用对象进行管理,被称为 Object-Base,任何资源都是用对象来表达。

/zircon/system/ulib/zxcpp 中可以一窥 Zircon 在裸机上运行 C++ 的细节,基本是关于对象管理操作符的重载和在裸机上实现内存管理。

在这里插入图片描述

Handler

用户态与内核态通信是通过 System Call,由中断实现,Zircon 也不例外。但是 Zircon 将这样过程抽象为 Handler 的交互。
前面说过任何资源在 Zircon 内核中都是一个对象,那么用户态想要访问内核资源即访问内核对象。Zircon 将 Handler(句柄) 抽象为内核对象的引用,可以理解为一个 Handler 是与某个内核对象的链接或者会话。
当然 Handler 不仅仅可以在用户态持有,前面说过 Zircon 是一个 Object-Base 的内核,Handler 在内核态就是一个 C++ 对象,在用户态时才表示得像一个“句柄”,其实是一个 32 位整数,表示内核对象的 ID。

线程调度

关于 Zircon 的线程调度模型其实没什么特别的,现代操作系统的实现方式都趋于一致。

  • 每个 CPU 内核拥有一个调度器
  • 每个调度器管理着一组最高优先级为 32 的优先级队列
  • 由于 Zircon 是实时内核,所以调度器仅会从最高优先级队列中寻找合适的线程执行
  • Zircon 也使用时间片
  • Zircon 使用临时优先级,优先级继承来解决优先级反转问题

Channel

Channel 是一个进程间双向通讯的实现,可以传输普通数据和 Handler,有点类似 Android 中的 Binder
不同的是,Binder 是同步的,每个进程都维护着一个 Binder 线程池,每当有 Binder 调用发生,目标进程都会从线程池中选取一个线程阻塞处理送来的消息。
Channel 是单线程异步的,有点像 Android 上的消息队列 Looper,Client 进程异步发送消息,当队列中收到 Server 返回数据时,通过 Callback 监听返回。Server 在队列中等待 Client 发来的消息。
需要注意的是 Channel 本身不提供异步实现,异步是其包装 FIDL 实现的,单考虑到 Channel 基本上都是搭配 FIDL 使用,所以有以上描述。关于 FIDL 具体在下面介绍。

Driver

驱动管理也是内核的重要任务

Zircon 的驱动分为两大层

  • Core Driver
  • Hardware Driver

在这里插入图片描述

Core Driver

顾名思义,核心驱动管理着一组类似的硬件实例并把他们抽象成了一个统一的硬件接口,比如网卡核心驱动,与特定的网卡型号无关,用户只需要把它当作网卡设备就好了,无需关注它是哪种特定型号的网卡。

而且核心驱动又抽象成了三种:

  • Concurrent Device Driver
    并行设备,设备支持并发请求操作
  • Sequential Device Driver
    串行设备,同时仅支持单个操作请求,核心驱动将会将多个请求串行
  • Bus Driver
    如果一个驱动含有多个子设备,例如 PCI/USB 总线设备,那么这个控制器的驱动称为总线设备驱动

Hardware Driver

一个硬件驱动就是某个特定型号的硬件驱动,可以说是硬件驱动实现了核心驱动的接口,硬件驱动接受核心驱动的管理和请求并将其转换成在对应设备上的操作。
硬件驱动将会尽量简化,他们仅仅作为核心驱动的实现模块,不支持 RPC,不会与上层直接通讯,内部不会有工作线程,当然这也不是严格要求。

驱动管理的组件

Zircon 的驱动管理包含 4 个主要组件:

  • DevMgr
  • DevHost
  • DDK
  • Driver
DevMgr

顾名思义 Device Manager 设备管理器,负责加载和管理驱动实例,控制驱动的生命周期,包括加载文件系统和启动 AppMgr

DevHost

DevHost 是驱动进程的容器,由 DevMgr 按需创建,实现驱动间的隔离以保证安全和稳定。

DDK

The Driver Development Kit 是驱动开发包,简单来说就是驱动开发的 SDK,由一组 API,ABI 和文档组成。

Driver

Driver 就是驱动的实现,上面已经介绍过,实际上一个个驱动就是一个个共享库,由 DevMgr 加载,运行在一个个 DevHost 中。

Banjo

Banjo 是 Zircon 用于定义驱动间 ABI 调用的接口描述语言,有点类似下面的 FIDL。

FIDL

FIDL 类似于 Android 的 AIDL,用于描述 RPC 的接口语言,他其实是对 Channel 的包装,就像 AIDL 是 Binder 的包装一样。

FIDL 其实严格意义上不完全属于 Zircon 内核,FIDL 由两部分组成:

  • FIDL 基础库
    这部分在内核和内核外都存在,主要是 FIDL 运行期间调用的接口,是对 Channel 的封装。实现了 RPC 的消息打包解包/异步分发,以及 RPC Client 和 Server 的基类封装。
  • FIDL 语言编译器
    实现了 FIDL -> 目标语言 Stub 代码的转换,目前支持 C/C++/Go/Dart/Rust。其作用其实就是帮助开发者自动生成 RPC 接口序列化成数据传输的过程。

我们可以看到,核心驱动都使用 FIDL 像外界暴露设备操作接口:

在这里插入图片描述

Job

一个 Job 控制一组进程,Job 本身也是一颗树,所以也可以拥有和控制着它的子 Job。
父 Job 可以 Trace 子 Job 或自己 Job 下面的各种进程,包括内存,CPU,System Call 等等等。

Job 在内核中也是一个对象,对象中包含:

  • 父 Job 的引用
  • 一组进程的引用
  • 子 Job 的引用
  • 一组控制策略

Flutter

从 Google 的文档来看 Flutter 其实是 Fuchsia 的附属产品:

“Flutter is a functional-reactive user interface framework optimized for Fuchsia and is used by many system components. Flutter also runs on a variety of other platform, including Android and iOS. Fuchsia itself does not require you to use any particular language or user interface framework.”

以上是谷歌对 Flutter 的描述。

总结一下,Google 在设计 Fuchsia 中考虑到了多种框架兼容的可能性,但是 Flutter 作为一个优秀的 UI 框架,Fuchsia 中众多的系统组件是用 Fuchsia 实现的。并且 Google 也建议开发者使用 Flutter 实现 Fuchsia App。

其实通过 Flutter 在其他主流平台上的推广也可以看出谷歌正在为日后的 Fuchsia 积累 App 和开发者,当 Fuchsia 上市之后,这些 Flutter App 和 开发者就能很快适应 Fuchsia 的环境。

Library

Zircon vDSO(System Call Lib)

  • 如果你开发的是内核程序,那么你可以直接调用系统调用的接口
  • 但是如果你是用户态程序,则需要通过加载 vDSO 来获得这些系统调用的接口,并且这是用户态调用 System Call 的唯一途径

Zircon vDSO 在用户态的可见形式是一个动态链接库 libzircon.so, 用户态程序 load 该 so 即可调用其中的 System Call 函数。
但是 libzircon.so 并不是一个真正的 elf 文件,他不是位于文件系统中的真实文件,而是 Zircon 内核虚拟出来的。

Libzx

libzx 就是 libzircon 的一个 C++ 包装,因为 libzircon 暴露的是 C 接口,并且 libzx 增加了一些安全检查。

DDK

上面说过,这个库提供了驱动操作的 API

LIBC

标准 libc 库,用户态以 libc.so 呈现,用户态程序可以用作静态或动态链接,但是 Zircon 属于微内核,所以 libc 也仅实现了一部分,例如 signals, fork, exec 都是不支持的。
Fuchsia 的 libc 是基于 Musl Libc 实现的:https://www.musl-libc.org

POSIX I/O

标准 I/O 库,类似上面的 LIBC,这也是一个标准库,用于兼容不同 OS 之间的 IO 操作。包含 文件/Socket/Pipes 等实现,这层定义了一些标准的 IO 接口,例如:read, write, open, close, seek。。。这个库在 Fuchsia 中被称为 fdio,在用户态以 libfdio.so 呈现。

FBL

别看错,不是 FBI,FBL 是 Fuchsia Base Library 的简称,FBL 实现的多是一些静态的 C++ 工具类,他与系统调用及内核无关。
简单了解一些 FBL 所提供的一些实现:

  • utility code
    • basic algorithms
    • integer type limits
    • type traits
    • atomics
    • alloc checking new
  • allocators
    • slab allocation
    • slab malloc
  • arrays
    • fixed sized arrays
    • fixed sized arrays
      which stack allocates small arrays
  • inline containers
    • doubly linked list
    • hash table
    • singly linked list
    • wavl trees
  • smart pointers
    • intrusive refcounted mixin
    • intrusive refcounting pointer
    • unique pointer
  • raii utilities
    • auto call
      code upon leaving scope
    • AutoLock

简单总结就是,运算/内存管理/数组/Map/智能指针/自动锁 等现代 C++ 的依赖。

FBL 在内核态和用户态都可以使用

  • system/ulib/fbl 内核或者用户程序都可以使用
  • kernel/lib/fbl 供内核态使用

FXL

FXL 是一个完全与 Fuchsia 和 Zircon 无关的静态 lib,例如日志和引用计数,完全的工具库。

Framework

Fuchsia Boot Sequence

启动顺序

  1. AppMgr
  2. SysMgr
  3. BaseMgr

AppMgr

AppManager 位于 Garnet 层,管理 Framework 所有的进程,包括系统框架和服务进程,也包括用户应用程序进程。
AppManager 在 Framework 初始化时被首先启动,有点类似 Android 中的 Zygote 进程。

SysMgr

  • System Manager 位于 Garnet 层,负责启动并管理系统组件以及系统服务。
  • 系统服务是懒加载的,当有其他进程请求对应的系统服务时,System Manager 将此请求分发到合适的系统服务,如果对应服务进程尚未启动,那么 System Manager 负责准备环境并让服务启动。
    所有系统服务都注册在 /system/data/bootstrap/services.config 文件中
  • 并且 System Manager 运行了很多系统组件,要在启动时运行的组件列表包含在/system/data/bootstrap/apps.config 中。

BaseMgr

Base Manager 的任务是用户管理
负责用户的登陆,会话,启动 Shell 或者 UI

Namespaces

命名空间是 Fuchsia 用来组织文件访问和服务发现的。

实际上命名空间在 Fuchsia 中无处不在,虽然操作系统没有一个统一的命名空间实现,但是每个重要部分都要自己的实现。

#pragma once

#include <stdint.h>

#include <zircon/compiler.h>
#include <zircon/types.h>

__BEGIN_CDECLS;

typedef struct fdio_namespace fdio_ns_t;

zx_status_t fdio_ns_create(fdio_ns_t** out);

zx_status_t fdio_ns_destroy(fdio_ns_t* ns);

zx_status_t fdio_ns_bind(fdio_ns_t* ns, const char* path, zx_handle_t h);

zx_status_t fdio_ns_bind_fd(fdio_ns_t* ns, const char* path, int fd);

int fdio_ns_opendir(fdio_ns_t* ns);

zx_status_t fdio_ns_chdir(fdio_ns_t* ns);

zx_status_t fdio_ns_install(fdio_ns_t* ns);

zx_status_t fdio_ns_get_installed(fdio_ns_t** ns);

typedef struct fdio_flat_namespace {
    size_t count;
    zx_handle_t* handle;
    uint32_t* type;
    const char* const* path;
} fdio_flat_namespace_t;

zx_status_t fdio_ns_export(fdio_ns_t* ns, fdio_flat_namespace_t** out);
zx_status_t fdio_ns_export_root(fdio_flat_namespace_t** out);

zx_status_t fdio_ns_connect(fdio_ns_t* ns, const char* path,
                            uint32_t zxflags, zx_handle_t h);

zx_status_t fdio_ns_open(fdio_ns_t* ns, const char* path,
                         uint32_t zxflags, zx_handle_t* out);

__END_CDECLS;

这是 FDIO 实现的命名空间管理

  • 命名空间是一个对象树,有点类似文件系统
  • 每个组件都会绑定一个命名空间,这个命名空间决定了该组件可以访问的资源,组件也可发布自己的对象使其包含在其他命名空间中,那样其他绑定该命名空间的对象就可以访问该组件。
  • 命名空间也可以独立与组件使用

可能还是有点抽象,命名空间到底是个什么概念。。。
大家知道 Linux 中一切皆为文件,在 Shell 中输入 ls,列举出来的是该目录下的所有文件,当然这个文件可能是某个设备描述符,也有可能是某个管道节点。
类似的,Fuchsia 中一切皆为对象,如果你在 Shell 中输入 ls,那么列举出来的就是当前 Shell 绑定的命名空间下可达的对象,这些对象可能包括

  • Files 文件
  • Dirs 文件夹
  • Sockets 套接字
  • Services 服务
  • Devices 设备

这些对象也像 Linux 中的文件系统,拥有路径,例如 house/box/cat

在这里插入图片描述

这是 Shell 命名空间的根路径:

  • svc 代表提供给组件的服务
  • dev 代表设备树
  • config 代表组件的配置信息
  • data 则代表本地的持久化存储

。。。。

在命名空间中,是无法访问到该命名空间根路径的父路径的,例如是哟 cd … 这样就保证了安全性

Sandboxing

Fuchsia 使用上文所描述的命名空间实现了沙箱模型

一个空进程,当没有配置沙箱也就是没有绑定命名空间时,该进程无法访问任何资源对象,甚至无法分配内存无法执行代码。
需要赋予进程特定的命名空间以控制进程对资源对象的访问。

Fuchsia Package

Fuchsia 的软件包是软件分发的载体单元,类似于 Android 的 APK。
其内部由清单文件,元数据,资源文件,一个或者多个可执行文件组成

meta/
metadata 元数据
contents 所有文件
signature 签名

FAR

Fuchsia 软件包的格式是 FAR,其并不是常见的 ZIP 压缩格式,而是 Google 自定义的格式,简单说是字节序列块。
由开头的索引块和其他数据块组成。

Component

组件是软件包中的可执行单元,类似与 Android 的四大组件

Fuchsia 中有两个默认组件实现:

  • Modules 模块,类似 Android 中的 Activity,通常要求绑定 UI
  • Agents 代理,有点类似于 Android 中的 Service,不需要显示 UI,每个代理都是单例,目的是为其他组件提供服务

组件运行在沙箱中,通过命名空间访问外部资源对象。

Metadata - Component Manifest

依然和 Android 类似,组件需要在软件包中的清单中注册以便与软件包管理服务发现该组件。
Fuchsia 清单文件是后缀名为 cmx 的 JSON 格式文件,位于包中 /meta/ 目录下
组件声明主要附带以下信息:

  • bin 可执行单元
  • sandbox 沙箱环境配置
  • Intent 类似 Android 的意图接收配置
  • 其他。。。

由于 Fuchsia 的松散架构,软件包中组件对应的可执行代码可以为多种实现,不同于 Android 组件只可以为 Dex 中的 class,至少我在例子中看到了 Native Code 和 Dart/Flutter 两种实现。

//Native
{
    "program": {
        "binary": "bin/app"
    },
    "sandbox": {
        "system": [ "data/sysmgr" ],
        "services": [ "fuchsia.sys.Launcher", "fuchsia.netstack.Netstack" ]
    }
}
//Dart/Flutter
{
    "program": {
        "data": "data/simple_flutter"
    },
    "runner": "flutter_jit_runner"
}

可以看见当可执行单元不是 native 时,你可以配置执行该组件代码的 Runtime。这里就是指定了 flutter runner
可以参考我前面对 Fuchsia 支持多 Runtime 的分析

Intent

你依然可以看到很多继承自 Android 的特性,例如 Intent

和 Android 相同,开发者可以为清单中的组件声明可以接收的 Intent:
即配置 Intent Filter

{
  "binary": "bin/myPersonPreviewer",
  "suggestion_headline": "See details about person",
  "intent_filters": [
    {
      "action": "com.google.fuchsia.preview.v1",
      "parameters": [
        {
          "name": "entityToPreview",
          "type": "https://fuchsia.instagram.com/types/Friend"
        }
      ],
    }
  ]
  "composition_pattern": "ticker"
}

元数据其他细节

  • outgoing services 可导出的服务,类似 Android exported ?
  • Attributes that define display constraints 定义显示属性
  • composition_pattern 看上去是定义 Mudle 显示的样式的,比如设定为 stick,将会显示成停靠在屏幕底部的的一个小弹窗,如果设为 comments-right 则会显示在其他窗口的右边

Package Manager

和 Android 一样,包管理服务会管理 Fuchsia Package 的安装卸载升级,在安装时也会解析保存 Fuchsia 包的元数据。

比较有趣的是 Fuchsia 的 Package Manager 后端是 Go 实现的:https://fuchsia.googlesource.com/garnet/+/master/go/src/pm#Structure-of-a-Fuchsia-Package

  • 10
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值