文章目录

  • 概述
  • Linux Kernel
  • AOSP
  • 安卓构建系统
  • rootfs 组织和分区布局
  • 安卓 C 库
  • 为什么 Android 不使用 BusyBox?
  • 安卓初始化系统
  • 安卓守护进程
  • 安卓日志系统
  • 硬件访问和 Android HAL
  • Android 框架和系统服务
  • 安卓应用
  • Android 是不是 Linux 发行版?


 如果您是嵌入式 Linux 开发人员但从未使用过嵌入式 Android,那么本文适合您。如果您开发或维护 Linux 发行版,并且我想开始开发 Android 发行版,那么本文适合您。如果您是一名 Android 应用程序开发人员并想了解一些 Android(内部)的工作原理,本文也适合您。如果你只是好奇,这篇文章也适合你!😃

 我们将从构建系统到分区布局,从 rootfs 的内容到操作系统组件的架构,从 IPC/RPC 机制到硬件访问如何工作的不同角度来比较 GNU/Linux 系统和 Android。

概述

 如果您查看任何嵌入式 Linux 系统的架构,您总会发现相同的主要组件:

  1. 一个或多个引导加载程序用于引导、配置硬件和引导 Linux 内核。
  2. Linux 内核。
  3. 包含库和应用程序的根文件系统 (rootfs)。

android和linux的最大区别是 android与linux系统区别_linux


 如果现在您查看基于 Android 的系统的相同图表,会有什么区别?

  1. 引导程序就在那里。Android 不需要任何特殊的引导加载程序,尽管人们通常会添加对fastboot 的支持,这是谷歌为用户和开发人员创建的协议,用于与基于 Android 的系统上的引导加载程序进行交互。
  2. Linux 内核也在那里,但有“一些”变化。稍后再谈。
  3. 根文件系统也在那里。但它真的不一样!没有什么像来自 Debian 的典型根文件系统或来自 Buildroot 或 OpenEmbedded 的定制 rootfs。

android和linux的最大区别是 android与linux系统区别_linux_02

android和linux的最大区别是 android与linux系统区别_android和linux的最大区别是_03

从上图我们可以看出,Android 用户空间组件清楚地分为三个主要层:

  1. Native:这是所有本机 (C/C++) 应用程序和库所在的位置。之所以称为Native,是因为它在 ART 虚拟机之外运行。本机层主要用于将 Linux 内核接口抽象到框架层。
  2. Framework:这是实现所有操作系统服务的地方(主要是在 Java 中)。对操作系统资源的访问通过称为系统服务的组件(远程)公开,使用称为 Binder 的 IPC/RPC 机制。API 将抽象应用程序对这些系统服务的访问。
  3. Application:通常用Java或Kotlin编写,他们只是看到暴露的操作系统API。

在详细研究 Android 用户空间组件之前,让我们先谈谈内核。

Linux Kernel

 要运行基于 Android 的系统,我们需要在 Linux 内核中启用一些额外的“功能”。如果我尝试讨论大多数功能,这篇文章会太长,但我可以评论一些:

  • Binder:这是Android中使用的IPC(Inter-Process Communication)和RPC(Remote Procedure Call)机制。您可以与 DBUS 做一个粗略的比较,但 DBUS 在用户空间中运行,而 Binder 是一种更快、更轻的基于内核的实现。
  • Ashmem:Android 中的默认共享内存分配器(Google 不喜欢 POSIX SHM)。
  • 低内存杀手:建立在内核OOM(内存不足)杀手之上的逻辑,与守护进程(lmkd)结合,有助于在低内存情况下管理系统。
    大多数这些特性已经在主线内核中可用,但如果你想要“Androidisms”的完整列表,你可以克隆谷歌的内核通用存储库并搜索以“ANDROID:”开头的提交:
$ git clone https://android.googlesource.com/kernel/common kernel-common
$ git checkout remotes/origin/android11-5.4
$ git log --oneline | grep "ANDROID:" | less
5427f8b72fc0 ANDROID: GKI: update xiaomi symbol list
ecb88922f521 ANDROID: GKI: update Vivo symbol list
32b242337266 ANDROID: sysrq: add vendor hook for sysrq crash information
42e516f6b23b ANDROID: ABI: update allowed list for galaxy
de198b0f2d39 ANDROID: GKI: update Vivo symbol list

$ git log --oneline | grep "ANDROID:" | wc -l
1157

 尽管 Linux 内核中有这些(以及其他一些)主要变化,Android 在用户空间组件及其架构(所谓的 Android 平台)方面确实与 GNU/Linux 系统不同,Android 平台的源代码是在名为AOSP(Android 开源项目)的项目中提供。

AOSP

AOSP 由数百个存储库(特别是 Android 11 中的 780 个)组成,您可以在https://android.googlesource.com/ 中查看所有这些存储库。

 源代码是用已知的工具管理的,比如repo和git,它是巨大的!Android 11 是 100GB 的源代码加上一次构建后的 115GB。因此,您确实需要大量磁盘空间来处理 Android 源代码。

克隆最新的 AOSP 源代码就像运行以下两个命令一样简单(可以在repo init 中使用-b来克隆特定的Android 发布标记或分支):

$ repo init -u https://android.googlesource.com/platform/manifest
$ repo sync

几个小时后,您的机器中将拥有 Android 源代码:

$ ls
Android.bp      dalvik       libcore           read-snapshot.txt
art             developers   libnativehelper   sdk
bionic          development  Makefile          system
bootable        device       out               test
bootstrap.bash  external     packages          toolchain
build           frameworks   pdk               tools
compatibility   hardware     platform_testing
cts             kernel       prebuilts

作为一个开源项目,有多个讨论组与社区和开发者进行交流,任何人都可以通过Gerrit 代码审查工具为项目做出贡献。

绝大多数软件组件在 Apache 和 BSD 许可下,一些软件组件在 GPL/LGPL 许可下,一些谷歌应用程序是闭源的(例如谷歌播放、Gmail、谷歌地图、YouTube 等)。这些应用程序在名为Google 移动服务(GMS)的软件包中提供,要获取它们,您需要通过Android 兼容性计划(ACP)对设备进行认证。

当我们下载 AOSP 源代码时,与其他嵌入式 Linux 开发方法相比,我们可以看到一些差异。

与现成的发行版(例如 Debian)不同,您可以轻松下载完整的源代码并从头开始构建发行版(例如,如果您想创建一个自定义的 Debian 系统,您通常从预编译的包中完成) )。

与构建系统方法(例如 Buildroot、OpenEmbedded)相比,在 Android 中,我们似乎有一个使用repo sync命令下载的“大应用程序” 。当然这不是真的。我们在那里有数以千计的项目和存储库,它们最终将组成操作系统映像。而将所有内容放在一起的责任在于 Android 构建系统…

安卓构建系统

 在以前的 Android 版本中,构建系统完全基于 makefile,其中编译每个软件组件的指令在Android.mk文件中定义。下面是在 Android 中构建“Hello World”C 应用程序的Android.mk文件示例:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES = helloworld.c
LOCAL_MODULE = helloworld
LOCAL_MODULE_TAGS = optional

include $(BUILD_EXECUTABLE)

 基于 Makefile 的构建系统有几个缺点,包括增量构建的性能低下,并且在最新版本的 Android 中被Soong 构建系统取代。

 在 Soong 构建系统中,编译软件组件的规则在 Blueprint 文件 ( Android.bp )中定义,其语法类似于 JSON。以下是在 Android 中构建“Hello World”C 应用程序的相同示例,但使用的是蓝图文件:

cc_binary {
    name: "helloworld",
    srcs: ["helloworld.c"],
    tags: ["optional"],
}

 蓝图文件由名为Blueprint的工具处理,该工具生成.ninja文件,其中包含编译 Android 软件组件的所有规则。然后.ninja文件由名为Ninja的工具处理,该工具将编译所有软件组件并生成 Android 图像(稍后将详细介绍图像)。

 在撰写本文时,并非所有 makefile ( Android.mk ) 都转换为蓝图文件 ( Android.bp )。为此,有一个名为kati的工具,负责将Android.mk文件转换为.ninja文件。随着时间的推移,所有Android.mk文件应该会逐渐转换为Android.bp,不再需要在 Android 构建系统中使用 kati 工具。

下图是Android构建过程的总结:

android和linux的最大区别是 android与linux系统区别_linux_04


 构建Android非常简单。您可以使用三个简单的命令来完成此操作:一个用于获取初始化环境的脚本,第二个用于选择目标设备 ( product-variant ),最后一个用于开始构建。以下命令将为模拟器构建 Android:

$ source build/envsetup.sh
$ lunch aosp_x86_64-eng
$ make

几个小时后,我们在out/target/product/ 中得到了图像:

$ cd out/target/product/generic_x86_64/ && ls *.img
cache.img          super_empty.img    vbmeta.img
dtb.img            super.img          vendor_boot-debug.img
encryptionkey.img  system.img         vendor_boot.img
ramdisk-debug.img  system-qemu.img    vendor.img
ramdisk.img        userdata.img       vendor-qemu.img
ramdisk-qemu.img   userdata-qemu.img

现在,所有这些图像是什么?Android 中的 rootfs 是如何组织的?

rootfs 组织和分区布局

Linux 系统上的 rootfs 组织(大部分)是标准化的,基本上由两个标准定义:Filesystem Hierarchy Standard和Linux Standard Base。

Linux 发行版试图符合这些标准,使应用程序易于移植,并在用户和开发人员需要使用不同的 Linux 系统时简化他们的生活。

但正如您所料,Android 是个例外!

这是 Android 系统(Android 11,为 QEMU 构建)的根分区列表。请问/sbin、/usr、/lib等Linux系统常用目录在哪里?

# ls /
acct        d              etc              mnt      sdcard
apex        data           init             odm      storage
bin         data_mirror    init.environ.rc  oem      sys
bugreports  debug_ramdisk  linkerconfig     proc     system
cache       default.prop   lost+found       product  system_ext
config      dev            metadata         res      vendor

他们不在!在Android中,操作系统组件(应用程序、库)位于/system目录(系统分区的挂载点),用户数据/配置(包括运行时安装的应用程序)位于/data目录(系统分区的挂载点)。数据分区)。还有许多其他分区,如缓存(下载的文件和临时数据)、供应商(来自 SoC 制造商的特定文件)和 odm(来自设备制造商的特定文件)。

这是 Android 11 上分区布局的基本概述(可能因制造商/设备而异):

android和linux的最大区别是 android与linux系统区别_应用程序_05

与典型的嵌入式 Linux 系统非常不同,对吧?

那么现在,我们为什么不讨论一下文件系统的内容呢?因为它们也有很大的不同。让我们从 C 库开始。

安卓 C 库

基于 Linux 内核的操作系统的主要组件之一是 C 库。

C 库实现了操作系统的 API,为应用程序提供了通过系统调用访问内核服务的接口。

有几个 C 库可用于 Linux 系统,包括 glibc、uclibc-ng 和 musl。但是 Android 有自己的 C 库:Bionic!

我可以想象至少有三个原因可能促使 Google 实现自己的 C 库:许可、速度和大小。实现非常简单,轻量级,并在 BSD 许可下发布。

需要提及的一件重要事情是它没有完整的 POSIX 支持,这使得为 Android 构建本机 Linux 应用程序变得更加困难。

例如,请参阅下面来自BusyBox 中 libbb/missing_syscalls.c的代码片段。该定义的(机器人)#如果因为一些仿生功能不遵循POSIX标准是必需的。

#if defined(ANDROID) || defined(__ANDROID__)
/*# include <linux/timex.h> - for struct timex, but may collide with <time.h> */
# include <sys/syscall.h>
pid_t getsid(pid_t pid)
{
	return syscall(__NR_getsid, pid);
}

int sethostname(const char *name, size_t len)
{
	return syscall(__NR_sethostname, name, len);
}

struct timex;
int adjtimex(struct timex *buf)
{
	return syscall(__NR_adjtimex, buf);
}

int pivot_root(const char *new_root, const char *put_old)
{
	return syscall(__NR_pivot_root, new_root, put_old);
}

说到 BusyBox……

为什么 Android 不使用 BusyBox?

在嵌入式 Linux 设备上使用 BusyBox 是很常见的。

Busybox 提供(重新)实现常用工具和应用程序,例如初始化程序、shell 和一些用于操作和配置系统的实用程序。

但是默认情况下,Android 不附带 BusyBox!

Android 使用另外两个(概念上相似的)实现,称为Toolbox和Toybox,它们都是在 BSD 许可下发布的。Toolbox 是 Google 实现的工具,Toybox 是社区实现的工具(由 Rob Landley 发起,BusyBox ex-maintainer)。

并且因为这些工具有一些限制,所以在 Android 设备上安装 BusyBox 是很常见的,尤其是在开发过程中。一个动机是在命令行中有一个好的文本编辑器 ( vi ) 可用。

现在,基于 Linux 的操作系统的一个重要部分是 init 系统。初始化在 Android 中是如何工作的?

安卓初始化系统

简而言之,init 应用程序在挂载 rootfs 后立即由内核执行,负责系统初始化和管理。

Linux 系统的 init 进程有多种实现方式,包括 sysvinit、systemd 和 upstart。正如您可能已经预料到的,Android 有自己的初始化系统!

Android init 进程有 3 个主要职责:

  1. 初始化和配置操作系统执行环境(导出环境变量、创建和设置文件和目录的权限、创建链接、挂载文件系统、设置 selinux 等)。
  2. 启动和监视守护进程。
  3. 管理系统属性。

init 进程的行为定义在一个配置文件中(默认为/etc/init/hw/init.rc),它与我们习惯的任何 init 配置文件都有很大的不同。以下是来自默认 Android init.rc文件的片段:

import /init.environ.rc
import /system/etc/init/hw/init.usb.rc
import /init.${ro.hardware}.rc
import /vendor/etc/init/hw/init.${ro.hardware}.rc
import /system/etc/init/hw/init.usb.configfs.rc
import /system/etc/init/hw/init.${ro.zygote}.rc

# Cgroups are mounted right before early-init using list from /etc/cgroups.json
on early-init
    # Disable sysrq from keyboard
    write /proc/sys/kernel/sysrq 0

    # Android doesn't need kernel module autoloading, and it causes SELinux
    # denials.  So disable it by setting modprobe to the empty string.  Note: to
    # explicitly set a sysctl to an empty string, a trailing newline is needed.
    write /proc/sys/kernel/modprobe \n

    ...

on init
    sysclktz 0

    # Mix device-specific information into the entropy pool
    copy /proc/cmdline /dev/urandom
    copy /system/etc/prop.default /dev/urandom

    symlink /proc/self/fd/0 /dev/stdin
    symlink /proc/self/fd/1 /dev/stdout
    symlink /proc/self/fd/2 /dev/stderr

    ...

# Mount filesystems and start core system services.
on late-init
    trigger early-fs

    # Mount fstab in init.{$device}.rc by mount_all command. Optional parameter
    # '--early' can be specified to skip entries with 'latemount'.
    # /system and /vendor must be mounted by the end of the fs stage,
    # while /data is optional.
    trigger fs

on property:ro.debuggable=1
    # Give writes to anyone for the trace folder on debug builds.
    # The folder is used to store method traces.
    chmod 0773 /data/misc/trace
    # Give reads to anyone for the window trace folder on debug builds.
    chmod 0775 /data/misc/wmtrace

service ueventd /system/bin/ueventd
    class core
    critical
    seclabel u:r:ueventd:s0
    shutdown critical

service console /system/bin/sh
    class core
    console
    disabled
    user shell
    group shell log readproc
    seclabel u:r:shell:s0
    setenv HOSTNAME console

...

它确实非常不同。您有动作声明(例如在 init 上)和服务声明(例如服务控制台 /system/bin/sh)。当一个动作在启动时被触发时,假设是early-init,在该触发器中声明的命令将被执行。

这里有很多细节,但我们在这篇文章中没有太多空间来讨论它(我们实际上可以写一篇完整的文章)。现在,让我们关注这个难题的一个重要部分,守护进程!

安卓守护进程

守护进程是在后台运行并负责管理某些系统功能的进程。它们中的大多数在启动时由 init 进程执行,并且通常只要系统正常运行,它们就会在后台运行。

守护进程通常用于控制和集中访问系统资源,在 Android 上,许多守护进程是 Android 框架(Java 代码)和系统资源(网络、存储、能源、无线电、日志记录等)之间的接口。一些例子:

  • ueventd:负责管理硬件设备的连接(设备热插拔)。它相当于 GNU/Linux 系统上的 udev 或 mdev。
  • vold:(卷守护进程)负责监控来自存储设备的事件。
  • rild:(无线电接口层守护进程)管理与调制解调器芯片的通信(语音和数据)。
  • netd:(网络管理服务守护进程)负责管理网络连接(蓝牙、Wi-Fi、USB 等)。它相当于 GNU/Linux 系统上的 NetworkManager 或 connman。
  • installd:(安装守护进程)负责管理 Android 应用程序(* .apk)及其相关资源的安装。
  • lmkd:(低内存杀手守护进程)负责管理内核低内存杀手接口。

这是在 Android 11 上运行的守护进程的(大部分)完整列表:

# ps -A
USER            PID   PPID     VSZ    RSS WCHAN            ADDR S NAME                       
root              1      0 10782796  9696 do_epoll_+          0 S init
root            122      1 10761204  7376 do_sys_po+          0 S ueventd
logd            145      1 10764228  7932 __x64_sys+          0 S logd
lmkd            146      1 10756496  2456 do_epoll_+          0 S lmkd
system          147      1 10759476  5016 do_epoll_+          0 S servicemanager
system          148      1 10761244  6488 do_epoll_+          0 S hwservicemanager
system          149      1 10759572  4028 do_epoll_+          0 S vndservicemanager
root            153      1 10770096  8732 binder_th+          0 S vold
tombstoned      250      1 10755388  2128 do_epoll_+          0 S tombstoned
statsd          266      1 10766140  4572 do_epoll_+          0 S statsd
root            267      1 10781776  9532 binder_th+          0 S netd
credstore       306      1 10764440  7296 binder_th+          0 S credstore
gpu_service     307      1 10762672  6804 binder_th+          0 S gpuservice
system          308      1 10873496 31972 do_epoll_+          0 S surfaceflinger
root            316      1 10756876  2656 do_sys_po+          0 S netmgr
root            318      1 10758880  3072 do_sys_po+          0 S wifi_forwarder
wifi            320      1 10759960  5464 do_select           0 S hostapd_nohidl
logd            326      1 10756544  3160 __skb_wai+          0 S logcat
root            352      1 10773084  6376 0                   0 S adbd
nobody          354      1 10757496  3164 do_sys_po+          0 S traced_probes
nobody          355      1 10757632  3464 do_sys_po+          0 S traced
cameraserver    356      1   58984  17240 binder_th+          0 S cameraserver
drm             357      1   25952   6512 binder_th+          0 S drmserver
incidentd       359      1 10761968  4992 do_epoll_+          0 S incidentd
root            360      1 10765704  6452 binder_th+          0 S installd
iorapd          361      1 10775424  9536 futex_wai+          0 S iorapd
keystore        362      1 10764916  7404 binder_th+          0 S keystore
root            366      1 10765596  5648 binder_th+          0 S storaged
...

你有没有意识到几乎所有的守护进程都是 Android 特有的?是的,他们确实是。Android 是一个操作系统,几乎所有的用户空间组件都是从头开始构建的!

特别值得一提的是日志记录在 Android 上的工作原理,因为它不使用像 journald 或 rsyslog 这样的常见日志记录 Linux 守护进程。所以现在让我们来谈谈这个。

安卓日志系统

在 Android 中,日志守护进程 ( logd ) 负责管理所有操作系统日志,从应用程序到框架和本机应用程序。

对日志的访问是通过/dev/socket/ 中导出的套接字完成的:

# ls /dev/socket/logd*
/dev/socket/logd  /dev/socket/logdr  /dev/socket/logdw

要读取或写入日志,无需直接访问这些套接字。为此,应用程序可以使用liblog库。而在终端中,用户可以使用log命令写入日志,并使用logcat工具读取日志:

# logcat
...
10-14 13:36:51.722   771   934 D SmsNumberUtils: enter filterDestAddr. destAddr="[BajqU4K5_YhSYbs-7QUn0dOwcmI]"
10-14 13:36:51.723   771   934 D SmsNumberUtils: destAddr is not formatted.
10-14 13:36:51.723   771   934 D SmsNumberUtils: leave filterDestAddr, new destAddr="[BajqU4K5_YhSYbs-7QUn0dOwcmI]"
10-14 13:36:57.054   316   316 E netmgr  : qemu_pipe_open_ns:62: Could not connect to the 'pipe:qemud:network' service: 
10-14 13:36:57.054   316   316 E netmgr  : Failed to open QEMU pipe 'qemud:network': Invalid argument
10-14 13:36:57.324   318   318 E wifi_forwarder: qemu_pipe_open_ns:62: Could not connect to the 'pipe:qemud:wififorward' service: 
10-14 13:36:57.325   318   318 E wifi_forwarder: RemoteConnection failed to initialize: RemoteConnection failed to open pipe
...
10-14 14:37:45.408   494  1324 D WifiNl80211Manager: Scan result ready event
10-14 14:37:45.408   494  1324 D WifiNative: Scan result ready event
10-14 14:37:59.109   316   316 E netmgr  : qemu_pipe_open_ns:62: Could not connect to the 'pipe:qemud:network' service: 
10-14 14:37:59.109   316   316 E netmgr  : Failed to open QEMU pipe 'qemud:network': Invalid argument
10-14 14:37:59.574   318   318 E wifi_forwarder: qemu_pipe_open_ns:62: Could not connect to the 'pipe:qemud:wififorward' service: 
10-14 14:37:59.575   318   318 E wifi_forwarder: RemoteConnection failed to initialize: RemoteConnection failed to open pipe
10-14 14:38:00.003   642   642 D KeyguardClockSwitch: Updating clock: 238
10-14 14:38:59.127   316   316 E netmgr  : qemu_pipe_open_ns:62: Could not connect to the 'pipe:qemud:network' service: 
10-14 14:38:59.127   316   316 E netmgr  : Failed to open QEMU pipe 'qemud:network': Invalid argument
10-14 14:38:59.585   318   318 E wifi_forwarder: qemu_pipe_open_ns:62: Could not connect to the 'pipe:qemud:wififorward' service: 
10-14 14:38:59.585   318   318 E wifi_forwarder: RemoteConnection failed to initialize: RemoteConnection failed to open pipe
10-14 14:39:00.003   642   642 D KeyguardClockSwitch: Updating clock: 239
10-14 14:39:59.142   316   316 E netmgr  : qemu_pipe_open_ns:62: Could not connect to the 'pipe:qemud:network' service: 
10-14 14:39:59.142   316   316 E netmgr  : Failed to open QEMU pipe 'qemud:network': Invalid argument
10-14 14:39:59.634   318   318 E wifi_forwarder: qemu_pipe_open_ns:62: Could not connect to the 'pipe:qemud:wififorward' service: 
10-14 14:39:59.634   318   318 E wifi_forwarder: RemoteConnection failed to initialize: RemoteConnection failed to open pipe
10-14 14:40:00.006   642   642 D KeyguardClockSwitch: Updating clock: 240
...

经过几年的 Android 工作,我可以说 Android 日志系统相当不错,在平台上开发时非常有用。

谈到开发,在将 Android 移植到嵌入式设备时,编写与硬件对话的代码是该过程的重要组成部分。那么为什么我们现在不讨论硬件访问在 Android 中是如何工作的呢?

硬件访问和 Android HAL

在嵌入式 Linux 系统上,对硬件设备的访问通常通过/dev或/sys 中的条目暴露给应用程序。但是在 Android 上,我们依靠一个称为HAL(硬件抽象层)的附加层来抽象对硬件设备的访问。

android和linux的最大区别是 android与linux系统区别_总结_06

主要思想是将系统服务(稍后会详细介绍)与 Linux 内核公开的接口解耦,因此如果内核接口发生变化,您只需更换 HAL,系统服务将继续工作。大多数 HAL 基本上是作为独立进程运行的服务,该进程公开通过 Binder 使用的接口(以称为HIDL的语言声明)。Android 中大多数支持的硬件设备都有 HAL 定义和实现,如显示器、相机、音频、传感器等。

但是要完全理解上图,就得说说Android框架和系统服务。

Android 框架和系统服务

因此,Android 框架是所有 Java(以及现在的 Kotlin)代码所在的地方。我们在那里有向应用程序公开的系统服务和 API。

尤其是系统服务,是Android操作系统中非常重要的一部分。它们基本上是公开接口(通过 Binder)以供其他系统服务和应用程序(通过 API)使用的对象。

在 Android 终端上,您可以使用以下命令列出系统服务:

# service list
Found 184 services:
0	DockObserver: []
1	SurfaceFlinger: [android.ui.ISurfaceComposer]
2	accessibility: [android.view.accessibility.IAccessibilityManager]
3	account: [android.accounts.IAccountManager]
4	activity: [android.app.IActivityManager]
5	activity_task: [android.app.IActivityTaskManager]
6	adb: [android.debug.IAdbManager]
7	alarm: [android.app.IAlarmManager]
8	android.hardware.identity.IIdentityCredentialStore/default: [android.hardware.identity.IIdentityCredentialStore]
9	android.hardware.light.ILights/default: [android.hardware.light.ILights]
10	android.hardware.power.IPower/default: [android.hardware.power.IPower]
11	android.hardware.rebootescrow.IRebootEscrow/default: [android.hardware.rebootescrow.IRebootEscrow]
12	android.hardware.vibrator.IVibrator/default: [android.hardware.vibrator.IVibrator]
13	android.security.identity: [android.security.identity.ICredentialStoreFactory]
14	android.security.keystore: [android.security.keystore.IKeystoreService]
15	android.service.gatekeeper.IGateKeeperService: [android.service.gatekeeper.IGateKeeperService]
16	app_binding: []
17	app_integrity: [android.content.integrity.IAppIntegrityManager]
18	appops: [com.android.internal.app.IAppOpsService]
19	appwidget: [com.android.internal.appwidget.IAppWidgetService]
20	audio: [android.media.IAudioService]
21	auth: [android.hardware.biometrics.IAuthService]
...

假设您正在编写一个 Android 应用程序来读取传感器。这是将要发生的事情:

  1. 应用程序将从 Android API (SensorManager) 调用方法以从传感器请求数据。
  2. API (SensorManager) 将向系统服务(在本例中为 SensorService)发送消息(通过 Binder)。
  3. 系统服务负责管理对其控制的资源的访问。在此示例中,SensorService 管理对传感器的访问。它会做的第一件事是检查权限:应用程序是否有权访问传感器?如果没有,它将向应用程序返回一个异常。如果访问被授予,它会通过 Binder 向 HAL(传感器 HAL)发送消息以请求来自传感器的数据。
  4. 传感器 HAL 将读取传感器,可能通过内核 IIO 驱动程序公开的文件,并将数据返回到系统服务 (SensorService)。
  5. 系统服务(SensorService)将传感器数据返回给应用程序。

这是另一个解释这些组件如何相互通信的图表:

android和linux的最大区别是 android与linux系统区别_Android_07

现在您看到 Android 与典型 Linux 系统的真正区别了吗?

我们仍然需要谈论应用程序…

安卓应用

在嵌入式设备上使用 Android 的优势之一是定义明确的 API 集,这大大简化了开发并显着提高了生产力。

在 Android 中,应用程序是使用 Google SDK 用 Java 或 Kotlin 编写的,并打包在扩展名为.apk 的文件中,其中包含应用程序使用的编译代码、数据和资源。

Android 应用程序基本上由 4 类组件组成:活动、服务、广播接收器和内容提供器。一个应用程序可以包含一个或多个组件,一件好事是组件可以被重用并通过一种称为意图的机制相互通信。

最后,即使我们想使用Android但不关心操作系统内部架构,我们仍然需要学习Android范式,这与通常的Linux应用程序开发有很大不同,比如说在Qt或GTK。

让我们现在结束?

Android 是不是 Linux 发行版?

我们可以在这篇文章中看到,Android 确实与典型的 GNU/Linux 系统不同,从我们管理源代码和构建系统的方式到文件系统的组织和组件,以及所有组件通过 IPC 进行通信的模块化架构/RPC。

我们可以清楚地看到的唯一相似之处是 Linux 内核的用法。在 Android 中,几乎所有其他东西都不同。

那么 Android 是 Linux 发行版吗?

这取决于您如何“分类”Linux 发行版。如果Linux发行版是任何使用Linux内核的系统,那么我们大概可以说Android是Linux发行版。如果 Linux 发行版是一个遵循相同标准并共享一些公共组件的系统,例如 GNU 项目提供的那些,那么 Android 绝对不是 Linux 发行版。

值得一提的是,随着时间的推移,Android 正在不断发展。Google 面临的主要挑战之一是软件更新。他们无法更新任何设备,因为它不在他们的控制之下。

Apple 制造 SoC、设备本身(当然!)和软件,几乎控制着供应链的每个方面。因此,他们可以根据需要(随时)更新现场的所有设备。

现在谷歌没有这个能力。除了 Pixel 设备,他们对三星或小米等其他公司制造的设备没有太多控制权。

但他们想要这种控制。这就是为什么他们创建项目来改善这种情况,例如Project Trebble、Generic System Images和Generic Kernel Image。

我们在本文中看到的许多建筑设计都来自这些项目,而且可能还会有更多。是不是更好,只有用户和市场会告诉你。