Chrome OS是Google公司开发的基于Chrome浏览器的操作系统。本文会讲解Chrome OS对于Android系统支持方面的内容。
- 前言
- 获取Chrome OS源码
- Chrome上的Android应用
- ARC++ 项目
- ARCVM 项目
- 获取 Chrome OS 模拟器
- Chrome OS 中的进程
- 为Chrome OS开发Android应用
- 参考资料与推荐读物
前言
Chrome OS与Android都是Google公司开发的操作系统。前者发布于2011年,后者发布于2008年。
当然,大家可能还知道Google的另外一个操作系统,叫做Fuchsia。在今后的文章中,我们也会谈到。
距离Android发布已经超过10年时间,它在移动互联网时代取得了巨大的成就。与此同时,Chrome浏览器也一样非常的成功。相较而言,Chrome OS却仍然不温不火。
目前,Chrome OS主要在以下几种设备上运行:
- Chromebooks
- Chromeboxes
- Chromebits
本文不想对比Chrome OS或者Android系统那个更好,也不会深入讨论Chrome浏览器或者 Chrome OS的具体实现。只将重心发在Chrome OS对于Android App的支持上。因为对于很多人来说,要么是Android平台的开发者,要么是Android系统的用户。
阅读本文需要对Android系统实现有一定的了解,你可以访问Android官方网站获取相应的知识:
或者阅读我之前写过的一些文章:AndroidAnatomy。
获取Chrome OS源码
通过下面的命令可以获取Chrome OS的源码:
mkdir chromeos
cd chromeos
repo init -u https://chromium.googlesource.com/chromiumos/manifest.git
repo sync
上面的命令会将Chrome OS的源码下载在chromeos
目录中。完整的源码大小超过20个G,因此可能需要比较长的时间才能完成下载。
如果你想要编译Chrome OS或者对Chrome OS系统开发有兴趣,下面两个文档是一个比较好的开始。
Chrome上的Android应用
Chrome上对于Android应用的支持经历了三个项目和阶段。
项目名称 | 开发时间 | 状态 | 特点 | 其他说明 |
---|---|---|---|---|
ARC | 2014年 | 已废弃 | 支持各桌面平台的Chrome浏览器 | 需要Android开发者对接,并存在安全问题 |
ARC++ | 2016年 | 正在使用 | Chrome OS专用,通过Linux容器运行 | 安全性有所提升,但仍然不够 |
ARCVM | 2019年 | 开发中 | 独立虚拟机,更加安全 | 不确定是否会与ARC++项目合并 |
ARC是 App/Android Runtime for Chrome 的缩写。
ARCVM 是 ARC Virtual Machine 的缩写。
由于ARC项目已经废弃,因此本文不再讨论。
下面仅对另外两个项目做一些介绍。
ARC++ 项目
前面已经看到,ARC项目是为Chrome浏览器设计的。由于浏览器的安全模型与原生系统有很大差异,因此支持Chrome浏览器的应用需要开发者进行特定的修改。这对应用开发者来说,无疑是增加了负担。
因此ARC++项目的设计目标包括:
- 能够直接访问Google Play商店上的应用
- 尽可能少的修改 Android Framework
- 不破坏Chrome OS安全性
- 维持Chrome的更新模型
在Chrome OS工程中,ARC++项目的源码并非集中在一起,它们分散在多处。
Android container
整体来说,ARC++项目的实现机理是:将Android系统运行在基于Linux namespace的容器中。以此达到与宿主系统(Chrome OS)相隔离的目的。
Linux namespace 是内核提供的一个特性。它通过命名空间的形式将资源隔离,使得不同集合的进程看到不同集合的资源。这项技术也是Linux上容器(例如:lxc 和 docker)实现的基础。
Linux 提供了 7 种类型的命名空间:
- Cgroup
- IPC
- Network
- Mount
- PID
- User
- UTS
关于Linux namespace,读者可以通过下面两个链接了解更多信息:
- Namespaces in operation, part 1: namespaces overview
- Separation Anxiety: A Tutorial for Isolating Your System with Linux Namespaces
run_oci 与 config.json
在 Chrome OS 中,有一个名称为 run_oci 的模块,它是一个小巧的容器运行时,它会读取名称为 config.json 的配置文件来完成Android容器的初始化工作。
config.json 中的描述了需要挂载的文件系统,命名空间,设备节点,cgroup配置以及继承的能力。你可以点击链接查看这个文件中的内容。
Android container的启动与退出
config.json
文件中包含了下面这段配置。
"process": {
"terminal": true,
"user": {
"uid": 0,
"gid": 0,
"additionalGids": [5005]
},
"umask": 0,
"args": [
"/system/bin/init",
"second_stage"
],
"env": [
"INIT_SELINUX_TOOK=1500",
"INIT_STARTED_AT=1000",
"PATH=/sbin:/system/sbin:/system/bin:/system/xbin:/odm/bin:/vendor/bin:/vendor/xbin"
],
...
对Android有所了解的读者在看到/system/bin/init
应该会觉得很熟悉。
在Android系统上,init进程负责了整个系统的启动逻辑。它会读取 /init.rc
文件完成系统的初始化工作,这其中包含启动 Android 系统中最重要的一些进程,例如:zygote
,system_server
,surfaceflinger
等。
如果你不理解这里的内容,请熟悉一下 Android Init Language,或者阅读我之前写过的文章:Android系统启动:init进程与init语言。
Chrome OS 上 Android container 启动和退出的流程如下图所示:
借助于run_oci
,可以很方便的控制Android容器的入口。这样无论是在开发阶段还是运行阶段,Android系统和Chrome OS都很好的解耦和分离开了,这也就非常的便于维护。这种做法是我们在做软件设计(尤其是大型软件系统)时非常值得借鉴学习的。
图形系统
在Linux容器的基础上,Android的相关进程都已经启动。接下来还需要对接用户界面的图形系统。
图形系统的内容包括:
- 负责应用窗口的创建
- 负责应用窗口的状态变化(例如:移动,改变尺寸)
- 负责图形内存的分配
- 负责图形的合成
- 负责图形的渲染
- 负责输入事件处理
对于 Android 图形系统不熟悉的读者,可以先看这里的文章:AOSP: Android Graphics Overview。
Android的图形系统结构如下:
在Android系统上,图形系统的主要组件包括:
Gralloc
:负责分配图形缓冲。HWComposer
:通过硬件确定缓冲合成的最有效方法。SurfaceFlinger
:接受来自多个源的数据缓冲,将它们合成并将它们发送到显示器。WindowManager
:负责创建和管理窗口。
从Android 4.0开始,Android 应用使用的Canvas API通常都会通过硬件加速。另外,还有一些应用会使用 OpenGL ES,甚至使用更新的 Vulkan 接口。
Android系统上的所有界面都通过 Surface 渲染出来。应用程序借助于 Surface
生成应用的界面,并将图形缓冲放入队列中,这些缓冲队列由SurfaceFlinger
处理。在底层,Surface
的图形缓冲通过gralloc
分配。
对于窗口管理来说,Android N(7.0)已经支持多窗口。在《Android 7.0中的多窗口实现解析》一文中,我们已经了解到,Android 的多窗口支持下面三种模式:
- 分屏模式
- 画中画模式
- Freeform 模式
有了这些背景知识之后便可以继续了解ChromeOS对于Android系统的对接逻辑了。
在 ARC++ 这篇文章中,Chromium 项目的开发者 David Revenman 详细介绍了 ARC++ 的项目实现。
这里是他的演讲资料:《Arc++ Graphics: Rendering, Compositing and Window Management》。
ARC++ 项目中图形系统的整体结构如下图所示:
在 Chrome OS 上,gralloc
和 GLES
驱动使用 DRM
(Direct Rendering Manager)来渲染。对于合成,HWComposer
先处理所有的Android Surface,然后再交由Chrome OS来与Chrome OS的其他界面一起合成。
对于窗口管理,位置变更和尺寸改变由Android完成,而对于最大化,最小化和全屏由 Chrome OS 完成。
Chrome OS中的输入事件由 Ozone 抽象层完成。它使用 GpuMemoryBuffer
对象来保存在Android端使用gralloc
或在Chrome OS端使用DRM分配的DRM缓冲区。
Exosphere
是Chrome OS中的一个组件,它允许其他客户端连接到用户界面。它通过验证所请求的操作来保护Chrome OS免受潜在恶意客户端(如Android应用)的侵害。
Android和Chrome OS借助于Wayland
协议来完成窗口管理和输入事件的通信。
Chrome OS 中的相关项目见下面这些链接:
- Ozone Overview
- Wayland implementation for Chromium Ozone classes
- Aura
- components/exo
- wayland/wayland-protocols
ARCVM 项目
虚拟机和容器
在虚拟化技术中,虚拟机和容器是很常见的概念。它们非常相似,但不完全一样。
简单来说,虚拟机是对机器的抽象,而容器是对操作系统的抽象。在实际的运行过程中,每个虚拟机会有独立的操作系统内核。而容器互相之间共享同一个内核。
因此:
- 虚拟机通常更“重”,因为它要占用更多的系统资源。不过好处是每个虚拟机之间隔离得更好,运行在同一个物理机的多个虚拟机,如果其中某一个出现了问题,不会影响其他虚拟机和宿主操作系统。
- 容器通常更“轻”,因为它不需要独立的内核(大家所熟悉的Docker就是一个容器)。但容器的缺点也正是因为它是共享同一个内核:如果某个容器中的进程触及了内核的某个Bug,导致内核出现问题,这将影响整个系统,当然也包括所有运行在这个系统上的容器。
下图是虚拟机(左)和容器(右)的对比图:
Crostini项目
从2018年秋天发布的Chrome OS 69版本开始,用户可以在Chrome OS上面运行Debian Linux,这对于很多技术工作者或者软件开发者来说无疑是极大的方便,有了Linux环境,很多笔记上的工作都可以完成了。
支持这个功能的是Crostini项目。
这个项目的机理是:在Chrome OS的系统上,会运行一个称之为crosvm
的虚拟机管理器(类似于QEMU),在这之上来运行Linux虚拟机。
其架构如下图所示:
这个项目包含了很多的术语,如果你浏览Chrome OS的文档你可能会经常看到这些术语:
Cicerone
:Chrome OS中的守护进程,用来和容器通信。Concierge
:Chrome OS中的守护进程,管理虚拟机和容器的生命周期。crosh
:全称是Chrome OS shell,这是Chrome OS上的命令行工具。Crostini
:在Chrome OS上提供Linux环境的项目名称。crosvm
:Chrome OS上的虚拟机管理器。KVM
:全称是Kernel Virtual Machine,这是Linux提供的虚拟机机制。Termina
:自定义虚拟机的代码名称。Terminal
:获取完整的Linux命令行环境和运行Crostini的公开名称。vsh
:虚拟机中的shell。
关于这个项目的更多内容,读者可以阅读下面两个文档:
在这个项目的基础上,出于对系统稳定性和安全性的考虑,Chrome OS的维护者便倾向于将Android的运行环境从容器向虚拟机方向过渡。于是乎有ARCVM
(Android Runtime for Chrome OS Virtual Machine)的想法就很自然了。
目前该项目还处于早期的开发阶段,你可以通过Gerrit上的patch了解相关内容:message:arcvm Chromium Gerrit。
另外,ARC++和ARCVM项目今后会怎么样,会不会废除前者合并到后者,目前还不确定。
获取 Chrome OS 模拟器
对于大部分人来说,可能并没有运行 Chrome OS 的物理设备。不过通过 Android Studio 可以获取 Chrome OS 的模拟器镜像。借此来熟悉 Chrome OS 的环境。
目前(2019年7月) Google 只提供了预览版的镜像。也许很快就会更新,想要获取最新信息,请访问: Android Developers: Apps for Chrome OS overview。
在安装好 Android Studio 之后,通过下面的方法可以获取 Chrome OS 的模拟器。
- 打开 Android Studio,选择
Tools > SDK Manager
。 - 点击
SDK Update Sites
tab。 - 点击
+
号,添加 URL 为:https://storage.googleapis.com/chrome_os_emulator/addon2-1.xml
,名称随意也可以不填。 - 再次点击
+
号,添加 URL 为https://storage.googleapis.com/chrome_os_emulator/sys-img2-1.xml
,名称随意也可以不填。 - 点击
Apply
。 - 点击
SDK Tools
tab然后在列表中选择Chrome OS device
。 - 点击
OK
就会安装 Chrome OS 的虚拟设备了。 - 重启 Android Studio。
- 在Android Studio中,选择
Tools > AVD Manager
。 - 点击
Create Virtual Device
便可以在Tablet
分类下面看到 Chrome OS 的虚拟机设备:Pixelbook。如下图所示:
当前的 Chrome OS 系统镜像以Android 7.1.1版本为基础,因此还需要下载相应版本的Android Image才能运行。
下载完成之后启动需要通过Google账号进行登录,如下图所示:
登录之后可以上拉任务栏可以看见完整的应用列表。从列表中可以看出,系统中内置了Google的GMS。
当然,这也包括了 Google Play 应用商店。
Chrome OS 中的进程
Chrome OS 的虚拟设备启动之后,我们可以用熟悉的 adb
命令来了解其环境。
首先通过adb shell
进入的系统中。
在登录Google账号之前,系统只启动了部分进程,如下所示:
novato_cheets:/ $ ps
USER PID PPID VSIZE RSS WCHAN PC NAME
root 1 0 8176 2020 0 00000000 S /init
system 2 1 5116 1888 0 00000000 S /system/bin/boot_latch
logd 4 1 11864 3076 0 00000000 S /system/bin/logd
root 5 1 7120 2708 0 00000000 S /system/bin/debuggerd
root 6 1 20060 7964 0 00000000 S /system/bin/vold
root 12 5 6864 412 0 00000000 S debuggerd:signaller
root 19 1 3444 576 0 00000000 S /sbin/healthd
shell 20 1 5064 1872 0 00000000 S /system/bin/bugreportd
system 21 1 6460 2292 0 00000000 S /system/bin/servicemanager
system 22 1 80392 28368 0 00000000 S /system/bin/surfaceflinger
root 23 1 1604804 124292 0 00000000 S zygote
shell 24 1 30528 1260 0 00000000 R /sbin/adbd
shell 279 24 5020 2564 sigsuspend ef676a69 S /system/bin/sh
shell 284 279 6416 2408 0 edd48a69 R ps
一旦登录系统之后,再次通过ps
命令便可以看到更多的Andorid进程被启动了。
novato_cheets:/ $ ps
USER PID PPID VSIZE RSS WCHAN PC NAME
root 1 0 8184 2036 0 00000000 S /init
logd 4 1 12376 3056 0 00000000 S /system/bin/logd
root 5 1 7120 2680 0 00000000 S /system/bin/debuggerd
root 6 1 24416 8060 0 00000000 S /system/bin/vold
root 12 5 6864 536 0 00000000 S debuggerd:signaller
root 19 1 3444 572 0 00000000 S /sbin/healthd
shell 20 1 5064 1856 0 00000000 S /system/bin/bugreportd
system 21 1 6460 2400 0 00000000 S /system/bin/servicemanager
system 22 1 83508 28660 0 00000000 S /system/bin/surfaceflinger
root 23 1 1606816 121436 0 00000000 S zygote
arc-tracing 87 1 17120 6160 0 00000000 S /system/bin/arctraceservice
system 88 1 19212 6204 0 00000000 S /system/bin/arcbridgeservice
audioserver 89 1 33740 10176 0 00000000 S /system/bin/audioserver
cameraserver 90 1 29256 11952 0 00000000 S /system/bin/cameraserver
drm 91 1 18572 7932 0 00000000 S /system/bin/drmserver
root 92 1 7020 3640 0 00000000 S /system/bin/installd
keystore 93 1 15400 6600 0 00000000 S /system/bin/keystore
mediacodec 94 1 36464 13688 0 00000000 S media.codec
media 95 1 29224 11092 0 00000000 S /system/bin/mediadrmserver
mediaex 96 1 51584 13404 0 00000000 S media.extractor
media 97 1 55480 14684 0 00000000 S /system/bin/mediaserver
root 100 1 25992 5236 0 00000000 S /system/bin/netd
system 101 1 15084 6448 0 00000000 S /system/bin/gatekeeperd
root 104 1 5600 2176 0 00000000 S /system/xbin/perfprofd
system 107 23 1810244 189396 0 00000000 S system_server
root 112 100 6420 2900 0 00000000 S /system/bin/iptables-restore
root 123 100 6432 2916 0 00000000 S /system/bin/ip6tables-restore
shell 228 1 12096 1124 0 00000000 R /sbin/adbd
u0_a16 275 23 1047744 79796 0 00000000 S com.android.systemui
radio 335 23 1045676 94992 0 00000000 S com.android.phone
u0_a40 351 23 1083856 94600 0 00000000 S org.chromium.arc.home
u0_a28 447 23 1023400 65240 0 00000000 S android.ext.services
u0_a47 500 23 1028860 67876 0 00000000 S org.chromium.arc.backup_settings
u0_a26 511 23 1030168 70180 0 00000000 S org.chromium.arc.crash_collector
u0_a49 532 23 1028964 68004 0 00000000 S org.chromium.arc.cast_receiver
u0_a23 545 23 1033920 70136 0 00000000 S org.chromium.arc.gms
u0_a56 553 23 1026796 62364 0 00000000 S org.chromium.arc.ime
u0_a46 566 23 1028868 68484 0 00000000 S org.chromium.arc.tts
system 586 23 1069980 93040 0 00000000 S org.chromium.arc.applauncher
u0_a30 600 23 1030132 78984 0 00000000 S org.chromium.arc.intent_helper
u0_a66 634 23 1025280 68548 0 00000000 S com.android.printspooler
u0_a13 655 23 1035140 85384 0 00000000 S android.process.acore
...
当然了,启动了更多的进程需要消耗更多的内存。在 Chrome OS 完全启动之后,其消耗的内存还是比较大的,你可以通过 free -h
或者 dumpsys meminfo
命令来查看。
novato_cheets:/ $ free -h
total used free shared buffers
Mem: 3.8G 2.3G 1.5G 3.1M 302M
-/+ buffers/cache: 2.0G 1.8G
Swap: 5.6G 0 5.6G
借助 Android Studio 和 Android 模拟器还有adb
命令,我们几乎可以把 Chrome OS 当成与 Android 系统一样来开发应用。
为Chrome OS开发Android应用
虽说运行Chrome OS的设备可以直接访问Google Play商店下载Andorid应用。但是,毕竟运行Chrome OS的设备(更像笔记本电脑)和手机存在较大的差异,因此如果希望应用在Chrome OS上能获得更好的体验,还需要开发者进行一定的优化。
这些优化主要在下面四个方面:
- 更大的屏幕:手机设备的屏幕尺寸通常是 4 ~ 7英寸。而运行Chrome OS的设备通常是10 ~ 15英寸。直接将手机的应用界面放大到大屏幕上使用通常体验都不太好,因为控件的留白和字体的大小通常是不合适的。
- 横屏模式:除了游戏和视屏应用之外,手机上的应用大部分都是竖屏的,而运行Chrome OS的设备通常是类似笔记本电脑的横屏。只支持竖屏将浪费很大的屏幕空间。
- 窗口控制:Android N开始支持多窗口。多窗口中提供了Freeform模式,这使得用户可以自由调整窗口的大小和位置。在桌面电脑上,这是几乎必备的功能。
- 外设支持:对于Chrome OS设备来说,除了触摸屏之外,键盘,鼠标和手写笔是很常见的输入设备。对于一些应用来说(例如:绘图应用),这些硬件的支持将极大的提升用户的使用效率。
关于这部分内容不再继续展开,有兴趣的读者可以查看下面几个链接:
- Android Developer: Apps for Chrome OS overview
- Android Apps for Chromebooks and Large Screen Devices (Google I/O ‘17)
- What’s new in Android apps for Chrome OS (Google I/O ‘18)
- Building Android Apps for the Chrome OS Ecosystem (Google I/O’19)
参考资料与推荐读物
- ChromiumOS Quick Start Guide
- Chromium OS Developer Guide
- Git repositories on chromium
- ARC is a project to run Play Store apps on Chrome OS
- Android Developers: Apps for Chrome OS overview
- LWN.net: ARC++
- Google working on new way to run Android apps in Chrome OS called ‘ARCVM’
- [PDF] Arc++ Graphics: Rendering, Compositing and Window Management
- [PDF] Security Evaluation of App Runtime for Chrome
- Android container in Chrome OS
- Preview virtual Chrome OS devices on the Android Emulator
- Hands-on: Fuchsia OS, meet Chrome — or at least a rudimentary Chromium build [Video]