admin管理员组文章数量:1579374
文章目录
- 概述
- Linux Kernel
- AOSP
- 安卓构建系统
- rootfs 组织和分区布局
- 安卓 C 库
- 为什么 Android 不使用 BusyBox?
- 安卓初始化系统
- 安卓守护进程
- 安卓日志系统
- 硬件访问和 Android HAL
- Android 框架和系统服务
- 安卓应用
- Android 是不是 Linux 发行版?
原文:https://embeddedbits/what-differs-android-from-other-linux-based-systems/
如果您是嵌入式 Linux 开发人员但从未使用过嵌入式 Android,那么本文适合您。如果您开发或维护 Linux 发行版,并且我想开始开发 Android 发行版,那么本文适合您。如果您是一名 Android 应用程序开发人员并想了解一些 Android(内部)的工作原理,本文也适合您。如果你只是好奇,这篇文章也适合你!😃
我们将从构建系统到分区布局,从 rootfs 的内容到操作系统组件的架构,从 IPC/RPC 机制到硬件访问如何工作的不同角度来比较 GNU/Linux 系统和 Android。
概述
如果您查看任何嵌入式 Linux 系统的架构,您总会发现相同的主要组件:
- 一个或多个引导加载程序用于引导、配置硬件和引导 Linux 内核。
- Linux 内核。
- 包含库和应用程序的根文件系统 (rootfs)。
如果现在您查看基于 Android 的系统的相同图表,会有什么区别?
- 引导程序就在那里。Android 不需要任何特殊的引导加载程序,尽管人们通常会添加对fastboot 的支持,这是谷歌为用户和开发人员创建的协议,用于与基于 Android 的系统上的引导加载程序进行交互。
- Linux 内核也在那里,但有“一些”变化。稍后再谈。
- 根文件系统也在那里。但它真的不一样!没有什么像来自 Debian 的典型根文件系统或来自 Buildroot 或 OpenEmbedded 的定制 rootfs。
从上图我们可以看出,Android 用户空间组件清楚地分为三个主要层:
- Native:这是所有本机 (C/C++) 应用程序和库所在的位置。之所以称为Native,是因为它在 ART 虚拟机之外运行。本机层主要用于将 Linux 内核接口抽象到框架层。
- Framework:这是实现所有操作系统服务的地方(主要是在 Java 中)。对操作系统资源的访问通过称为系统服务的组件(远程)公开,使用称为 Binder 的 IPC/RPC 机制。API 将抽象应用程序对这些系统服务的访问。
- 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/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/ 中查看所有这些存储库。
源代码是用已知的工具管理的,比如repo和git,它是巨大的!Android 11 是 100GB 的源代码加上一次构建后的 115GB。因此,您确实需要大量磁盘空间来处理 Android 源代码。
克隆最新的 AOSP 源代码就像运行以下两个命令一样简单(可以在repo init 中使用-b来克隆特定的Android 发布标记或分支):
$ repo init -u https://android.googlesource/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非常简单。您可以使用三个简单的命令来完成此操作:一个用于获取初始化环境的脚本,第二个用于选择目标设备 ( 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 上分区布局的基本概述(可能因制造商/设备而异):
与典型的嵌入式 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 个主要职责:
- 初始化和配置操作系统执行环境(导出环境变量、创建和设置文件和目录的权限、创建链接、挂载文件系统、设置 selinux 等)。
- 启动和监视守护进程。
- 管理系统属性。
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: 238
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: 239
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: 240
...
经过几年的 Android 工作,我可以说 Android 日志系统相当不错,在平台上开发时非常有用。
谈到开发,在将 Android 移植到嵌入式设备时,编写与硬件对话的代码是该过程的重要组成部分。那么为什么我们现在不讨论硬件访问在 Android 中是如何工作的呢?
硬件访问和 Android HAL
在嵌入式 Linux 系统上,对硬件设备的访问通常通过/dev或/sys 中的条目暴露给应用程序。但是在 Android 上,我们依靠一个称为HAL(硬件抽象层)的附加层来抽象对硬件设备的访问。
主要思想是将系统服务(稍后会详细介绍)与 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 应用程序来读取传感器。这是将要发生的事情:
- 应用程序将从 Android API (SensorManager) 调用方法以从传感器请求数据。
- API (SensorManager) 将向系统服务(在本例中为 SensorService)发送消息(通过 Binder)。
- 系统服务负责管理对其控制的资源的访问。在此示例中,SensorService 管理对传感器的访问。它会做的第一件事是检查权限:应用程序是否有权访问传感器?如果没有,它将向应用程序返回一个异常。如果访问被授予,它会通过 Binder 向 HAL(传感器 HAL)发送消息以请求来自传感器的数据。
- 传感器 HAL 将读取传感器,可能通过内核 IIO 驱动程序公开的文件,并将数据返回到系统服务 (SensorService)。
- 系统服务(SensorService)将传感器数据返回给应用程序。
这是另一个解释这些组件如何相互通信的图表:
现在您看到 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。
我们在本文中看到的许多建筑设计都来自这些项目,而且可能还会有更多。是不是更好,只有用户和市场会告诉你。
版权声明:本文标题:Android 与其他基于 Linux 的系统有何不同? 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.elefans.com/dongtai/1727855412a1133960.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论