Android 与其他基于 Linux 的系统有何不同?
文章目錄
- 概述
- Linux Kernel
- AOSP
- 安卓構(gòu)建系統(tǒng)
- rootfs 組織和分區(qū)布局
- 安卓 C 庫
- 為什么 Android 不使用 BusyBox?
- 安卓初始化系統(tǒng)
- 安卓守護(hù)進(jìn)程
- 安卓日志系統(tǒng)
- 硬件訪問和 Android HAL
- Android 框架和系統(tǒng)服務(wù)
- 安卓應(yīng)用
- Android 是不是 Linux 發(fā)行版?
原文:https://embeddedbits.org/what-differs-android-from-other-linux-based-systems/
?如果您是嵌入式 Linux 開發(fā)人員但從未使用過嵌入式 Android,那么本文適合您。如果您開發(fā)或維護(hù) Linux 發(fā)行版,并且我想開始開發(fā) Android 發(fā)行版,那么本文適合您。如果您是一名 Android 應(yīng)用程序開發(fā)人員并想了解一些 Android(內(nèi)部)的工作原理,本文也適合您。如果你只是好奇,這篇文章也適合你!😃
?我們將從構(gòu)建系統(tǒng)到分區(qū)布局,從 rootfs 的內(nèi)容到操作系統(tǒng)組件的架構(gòu),從 IPC/RPC 機(jī)制到硬件訪問如何工作的不同角度來比較 GNU/Linux 系統(tǒng)和 Android。
概述
?如果您查看任何嵌入式 Linux 系統(tǒng)的架構(gòu),您總會發(fā)現(xiàn)相同的主要組件:
?如果現(xiàn)在您查看基于 Android 的系統(tǒng)的相同圖表,會有什么區(qū)別?
從上圖我們可以看出,Android 用戶空間組件清楚地分為三個主要層:
在詳細(xì)研究 Android 用戶空間組件之前,讓我們先談?wù)剝?nèi)核。
Linux Kernel
?要運(yùn)行基于 Android 的系統(tǒng),我們需要在 Linux 內(nèi)核中啟用一些額外的“功能”。如果我嘗試討論大多數(shù)功能,這篇文章會太長,但我可以評論一些:
- Binder:這是Android中使用的IPC(Inter-Process Communication)和RPC(Remote Procedure Call)機(jī)制。您可以與 DBUS 做一個粗略的比較,但 DBUS 在用戶空間中運(yùn)行,而 Binder 是一種更快、更輕的基于內(nèi)核的實現(xiàn)。
- Ashmem:Android 中的默認(rèn)共享內(nèi)存分配器(Google 不喜歡 POSIX SHM)。
- 低內(nèi)存殺手:建立在內(nèi)核OOM(內(nèi)存不足)殺手之上的邏輯,與守護(hù)進(jìn)程(lmkd)結(jié)合,有助于在低內(nèi)存情況下管理系統(tǒng)。
大多數(shù)這些特性已經(jīng)在主線內(nèi)核中可用,但如果你想要“Androidisms”的完整列表,你可以克隆谷歌的內(nèi)核通用存儲庫并搜索以“ANDROID:”開頭的提交:
?盡管 Linux 內(nèi)核中有這些(以及其他一些)主要變化,Android 在用戶空間組件及其架構(gòu)(所謂的 Android 平臺)方面確實與 GNU/Linux 系統(tǒng)不同,Android 平臺的源代碼是在名為AOSP(Android 開源項目)的項目中提供。
AOSP
AOSP 由數(shù)百個存儲庫(特別是 Android 11 中的 780 個)組成,您可以在https://android.googlesource.com/ 中查看所有這些存儲庫。
?源代碼是用已知的工具管理的,比如repo和git,它是巨大的!Android 11 是 100GB 的源代碼加上一次構(gòu)建后的 115GB。因此,您確實需要大量磁盤空間來處理 Android 源代碼。
克隆最新的 AOSP 源代碼就像運(yùn)行以下兩個命令一樣簡單(可以在repo init 中使用-b來克隆特定的Android 發(fā)布標(biāo)記或分支):
$ repo init -u https://android.googlesource.com/platform/manifest $ repo sync幾個小時后,您的機(jī)器中將擁有 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作為一個開源項目,有多個討論組與社區(qū)和開發(fā)者進(jìn)行交流,任何人都可以通過Gerrit 代碼審查工具為項目做出貢獻(xiàn)。
絕大多數(shù)軟件組件在 Apache 和 BSD 許可下,一些軟件組件在 GPL/LGPL 許可下,一些谷歌應(yīng)用程序是閉源的(例如谷歌播放、Gmail、谷歌地圖、YouTube 等)。這些應(yīng)用程序在名為Google 移動服務(wù)(GMS)的軟件包中提供,要獲取它們,您需要通過Android 兼容性計劃(ACP)對設(shè)備進(jìn)行認(rèn)證。
當(dāng)我們下載 AOSP 源代碼時,與其他嵌入式 Linux 開發(fā)方法相比,我們可以看到一些差異。
與現(xiàn)成的發(fā)行版(例如 Debian)不同,您可以輕松下載完整的源代碼并從頭開始構(gòu)建發(fā)行版(例如,如果您想創(chuàng)建一個自定義的 Debian 系統(tǒng),您通常從預(yù)編譯的包中完成) )。
與構(gòu)建系統(tǒng)方法(例如 Buildroot、OpenEmbedded)相比,在 Android 中,我們似乎有一個使用repo sync命令下載的“大應(yīng)用程序” 。當(dāng)然這不是真的。我們在那里有數(shù)以千計的項目和存儲庫,它們最終將組成操作系統(tǒng)映像。而將所有內(nèi)容放在一起的責(zé)任在于 Android 構(gòu)建系統(tǒng)…
安卓構(gòu)建系統(tǒng)
?在以前的 Android 版本中,構(gòu)建系統(tǒng)完全基于 makefile,其中編譯每個軟件組件的指令在Android.mk文件中定義。下面是在 Android 中構(gòu)建“Hello World”C 應(yīng)用程序的Android.mk文件示例:
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS)LOCAL_SRC_FILES = helloworld.c LOCAL_MODULE = helloworld LOCAL_MODULE_TAGS = optionalinclude $(BUILD_EXECUTABLE)?基于 Makefile 的構(gòu)建系統(tǒng)有幾個缺點,包括增量構(gòu)建的性能低下,并且在最新版本的 Android 中被Soong 構(gòu)建系統(tǒng)取代。
?在 Soong 構(gòu)建系統(tǒng)中,編譯軟件組件的規(guī)則在 Blueprint 文件 ( Android.bp )中定義,其語法類似于 JSON。以下是在 Android 中構(gòu)建“Hello World”C 應(yīng)用程序的相同示例,但使用的是藍(lán)圖文件:
cc_binary {name: "helloworld",srcs: ["helloworld.c"],tags: ["optional"], }?藍(lán)圖文件由名為Blueprint的工具處理,該工具生成.ninja文件,其中包含編譯 Android 軟件組件的所有規(guī)則。然后.ninja文件由名為Ninja的工具處理,該工具將編譯所有軟件組件并生成 Android 圖像(稍后將詳細(xì)介紹圖像)。
?在撰寫本文時,并非所有 makefile ( Android.mk ) 都轉(zhuǎn)換為藍(lán)圖文件 ( Android.bp )。為此,有一個名為kati的工具,負(fù)責(zé)將Android.mk文件轉(zhuǎn)換為.ninja文件。隨著時間的推移,所有Android.mk文件應(yīng)該會逐漸轉(zhuǎn)換為Android.bp,不再需要在 Android 構(gòu)建系統(tǒng)中使用 kati 工具。
下圖是Android構(gòu)建過程的總結(jié):
?構(gòu)建Android非常簡單。您可以使用三個簡單的命令來完成此操作:一個用于獲取初始化環(huán)境的腳本,第二個用于選擇目標(biāo)設(shè)備 ( product-variant ),最后一個用于開始構(gòu)建。以下命令將為模擬器構(gòu)建 Android:
幾個小時后,我們在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現(xiàn)在,所有這些圖像是什么?Android 中的 rootfs 是如何組織的?
rootfs 組織和分區(qū)布局
Linux 系統(tǒng)上的 rootfs 組織(大部分)是標(biāo)準(zhǔn)化的,基本上由兩個標(biāo)準(zhǔn)定義:Filesystem Hierarchy Standard和Linux Standard Base。
Linux 發(fā)行版試圖符合這些標(biāo)準(zhǔn),使應(yīng)用程序易于移植,并在用戶和開發(fā)人員需要使用不同的 Linux 系統(tǒng)時簡化他們的生活。
但正如您所料,Android 是個例外!
這是 Android 系統(tǒng)(Android 11,為 QEMU 構(gòu)建)的根分區(qū)列表。請問/sbin、/usr、/lib等Linux系統(tǒng)常用目錄在哪里?
# 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中,操作系統(tǒng)組件(應(yīng)用程序、庫)位于/system目錄(系統(tǒng)分區(qū)的掛載點),用戶數(shù)據(jù)/配置(包括運(yùn)行時安裝的應(yīng)用程序)位于/data目錄(系統(tǒng)分區(qū)的掛載點)。數(shù)據(jù)分區(qū))。還有許多其他分區(qū),如緩存(下載的文件和臨時數(shù)據(jù))、供應(yīng)商(來自 SoC 制造商的特定文件)和 odm(來自設(shè)備制造商的特定文件)。
這是 Android 11 上分區(qū)布局的基本概述(可能因制造商/設(shè)備而異):
與典型的嵌入式 Linux 系統(tǒng)非常不同,對吧?
那么現(xiàn)在,我們?yōu)槭裁床挥懻撘幌挛募到y(tǒng)的內(nèi)容呢?因為它們也有很大的不同。讓我們從 C 庫開始。
安卓 C 庫
基于 Linux 內(nèi)核的操作系統(tǒng)的主要組件之一是 C 庫。
C 庫實現(xiàn)了操作系統(tǒng)的 API,為應(yīng)用程序提供了通過系統(tǒng)調(diào)用訪問內(nèi)核服務(wù)的接口。
有幾個 C 庫可用于 Linux 系統(tǒng),包括 glibc、uclibc-ng 和 musl。但是 Android 有自己的 C 庫:Bionic!
我可以想象至少有三個原因可能促使 Google 實現(xiàn)自己的 C 庫:許可、速度和大小。實現(xiàn)非常簡單,輕量級,并在 BSD 許可下發(fā)布。
需要提及的一件重要事情是它沒有完整的 POSIX 支持,這使得為 Android 構(gòu)建本機(jī) Linux 應(yīng)用程序變得更加困難。
例如,請參閱下面來自BusyBox 中 libbb/missing_syscalls.c的代碼片段。該定義的(機(jī)器人)#如果因為一些仿生功能不遵循POSIX標(biāo)準(zhǔn)是必需的。
#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 設(shè)備上使用 BusyBox 是很常見的。
Busybox 提供(重新)實現(xiàn)常用工具和應(yīng)用程序,例如初始化程序、shell 和一些用于操作和配置系統(tǒng)的實用程序。
但是默認(rèn)情況下,Android 不附帶 BusyBox!
Android 使用另外兩個(概念上相似的)實現(xiàn),稱為Toolbox和Toybox,它們都是在 BSD 許可下發(fā)布的。Toolbox 是 Google 實現(xiàn)的工具,Toybox 是社區(qū)實現(xiàn)的工具(由 Rob Landley 發(fā)起,BusyBox ex-maintainer)。
并且因為這些工具有一些限制,所以在 Android 設(shè)備上安裝 BusyBox 是很常見的,尤其是在開發(fā)過程中。一個動機(jī)是在命令行中有一個好的文本編輯器 ( vi ) 可用。
現(xiàn)在,基于 Linux 的操作系統(tǒng)的一個重要部分是 init 系統(tǒng)。初始化在 Android 中是如何工作的?
安卓初始化系統(tǒng)
簡而言之,init 應(yīng)用程序在掛載 rootfs 后立即由內(nèi)核執(zhí)行,負(fù)責(zé)系統(tǒng)初始化和管理。
Linux 系統(tǒng)的 init 進(jìn)程有多種實現(xiàn)方式,包括 sysvinit、systemd 和 upstart。正如您可能已經(jīng)預(yù)料到的,Android 有自己的初始化系統(tǒng)!
Android init 進(jìn)程有 3 個主要職責(zé):
init 進(jìn)程的行為定義在一個配置文件中(默認(rèn)為/etc/init/hw/init.rc),它與我們習(xí)慣的任何 init 配置文件都有很大的不同。以下是來自默認(rèn) 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 keyboardwrite /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 initsysclktz 0# Mix device-specific information into the entropy poolcopy /proc/cmdline /dev/urandomcopy /system/etc/prop.default /dev/urandomsymlink /proc/self/fd/0 /dev/stdinsymlink /proc/self/fd/1 /dev/stdoutsymlink /proc/self/fd/2 /dev/stderr...# Mount filesystems and start core system services. on late-inittrigger 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 fson 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/wmtraceservice ueventd /system/bin/ueventdclass corecriticalseclabel u:r:ueventd:s0shutdown criticalservice console /system/bin/shclass coreconsoledisableduser shellgroup shell log readprocseclabel u:r:shell:s0setenv HOSTNAME console...它確實非常不同。您有動作聲明(例如在 init 上)和服務(wù)聲明(例如服務(wù)控制臺 /system/bin/sh)。當(dāng)一個動作在啟動時被觸發(fā)時,假設(shè)是early-init,在該觸發(fā)器中聲明的命令將被執(zhí)行。
這里有很多細(xì)節(jié),但我們在這篇文章中沒有太多空間來討論它(我們實際上可以寫一篇完整的文章)。現(xiàn)在,讓我們關(guān)注這個難題的一個重要部分,守護(hù)進(jìn)程!
安卓守護(hù)進(jìn)程
守護(hù)進(jìn)程是在后臺運(yùn)行并負(fù)責(zé)管理某些系統(tǒng)功能的進(jìn)程。它們中的大多數(shù)在啟動時由 init 進(jìn)程執(zhí)行,并且通常只要系統(tǒng)正常運(yùn)行,它們就會在后臺運(yùn)行。
守護(hù)進(jìn)程通常用于控制和集中訪問系統(tǒng)資源,在 Android 上,許多守護(hù)進(jìn)程是 Android 框架(Java 代碼)和系統(tǒng)資源(網(wǎng)絡(luò)、存儲、能源、無線電、日志記錄等)之間的接口。一些例子:
- ueventd:負(fù)責(zé)管理硬件設(shè)備的連接(設(shè)備熱插拔)。它相當(dāng)于 GNU/Linux 系統(tǒng)上的 udev 或 mdev。
- vold:(卷守護(hù)進(jìn)程)負(fù)責(zé)監(jiān)控來自存儲設(shè)備的事件。
- rild:(無線電接口層守護(hù)進(jìn)程)管理與調(diào)制解調(diào)器芯片的通信(語音和數(shù)據(jù))。
- netd:(網(wǎng)絡(luò)管理服務(wù)守護(hù)進(jìn)程)負(fù)責(zé)管理網(wǎng)絡(luò)連接(藍(lán)牙、Wi-Fi、USB 等)。它相當(dāng)于 GNU/Linux 系統(tǒng)上的 NetworkManager 或 connman。
- installd:(安裝守護(hù)進(jìn)程)負(fù)責(zé)管理 Android 應(yīng)用程序(* .apk)及其相關(guān)資源的安裝。
- lmkd:(低內(nèi)存殺手守護(hù)進(jìn)程)負(fù)責(zé)管理內(nèi)核低內(nèi)存殺手接口。
這是在 Android 11 上運(yùn)行的守護(hù)進(jìn)程的(大部分)完整列表:
# 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 ...你有沒有意識到幾乎所有的守護(hù)進(jìn)程都是 Android 特有的?是的,他們確實是。Android 是一個操作系統(tǒng),幾乎所有的用戶空間組件都是從頭開始構(gòu)建的!
特別值得一提的是日志記錄在 Android 上的工作原理,因為它不使用像 journald 或 rsyslog 這樣的常見日志記錄 Linux 守護(hù)進(jìn)程。所以現(xiàn)在讓我們來談?wù)勥@個。
安卓日志系統(tǒng)
在 Android 中,日志守護(hù)進(jìn)程 ( logd ) 負(fù)責(zé)管理所有操作系統(tǒng)日志,從應(yīng)用程序到框架和本機(jī)應(yīng)用程序。
對日志的訪問是通過/dev/socket/ 中導(dǎo)出的套接字完成的:
# ls /dev/socket/logd* /dev/socket/logd /dev/socket/logdr /dev/socket/logdw要讀取或?qū)懭肴罩?#xff0c;無需直接訪問這些套接字。為此,應(yīng)用程序可以使用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 ...經(jīng)過幾年的 Android 工作,我可以說 Android 日志系統(tǒng)相當(dāng)不錯,在平臺上開發(fā)時非常有用。
談到開發(fā),在將 Android 移植到嵌入式設(shè)備時,編寫與硬件對話的代碼是該過程的重要組成部分。那么為什么我們現(xiàn)在不討論硬件訪問在 Android 中是如何工作的呢?
硬件訪問和 Android HAL
在嵌入式 Linux 系統(tǒng)上,對硬件設(shè)備的訪問通常通過/dev或/sys 中的條目暴露給應(yīng)用程序。但是在 Android 上,我們依靠一個稱為HAL(硬件抽象層)的附加層來抽象對硬件設(shè)備的訪問。
主要思想是將系統(tǒng)服務(wù)(稍后會詳細(xì)介紹)與 Linux 內(nèi)核公開的接口解耦,因此如果內(nèi)核接口發(fā)生變化,您只需更換 HAL,系統(tǒng)服務(wù)將繼續(xù)工作。大多數(shù) HAL 基本上是作為獨立進(jìn)程運(yùn)行的服務(wù),該進(jìn)程公開通過 Binder 使用的接口(以稱為HIDL的語言聲明)。Android 中大多數(shù)支持的硬件設(shè)備都有 HAL 定義和實現(xiàn),如顯示器、相機(jī)、音頻、傳感器等。
但是要完全理解上圖,就得說說Android框架和系統(tǒng)服務(wù)。
Android 框架和系統(tǒng)服務(wù)
因此,Android 框架是所有 Java(以及現(xiàn)在的 Kotlin)代碼所在的地方。我們在那里有向應(yīng)用程序公開的系統(tǒng)服務(wù)和 API。
尤其是系統(tǒng)服務(wù),是Android操作系統(tǒng)中非常重要的一部分。它們基本上是公開接口(通過 Binder)以供其他系統(tǒng)服務(wù)和應(yīng)用程序(通過 API)使用的對象。
在 Android 終端上,您可以使用以下命令列出系統(tǒng)服務(wù):
# 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] ...假設(shè)您正在編寫一個 Android 應(yīng)用程序來讀取傳感器。這是將要發(fā)生的事情:
這是另一個解釋這些組件如何相互通信的圖表:
現(xiàn)在您看到 Android 與典型 Linux 系統(tǒng)的真正區(qū)別了嗎?
我們?nèi)匀恍枰務(wù)搼?yīng)用程序…
安卓應(yīng)用
在嵌入式設(shè)備上使用 Android 的優(yōu)勢之一是定義明確的 API 集,這大大簡化了開發(fā)并顯著提高了生產(chǎn)力。
在 Android 中,應(yīng)用程序是使用 Google SDK 用 Ja??va 或 Kotlin 編寫的,并打包在擴(kuò)展名為.apk 的文件中,其中包含應(yīng)用程序使用的編譯代碼、數(shù)據(jù)和資源。
Android 應(yīng)用程序基本上由 4 類組件組成:活動、服務(wù)、廣播接收器和內(nèi)容提供器。一個應(yīng)用程序可以包含一個或多個組件,一件好事是組件可以被重用并通過一種稱為意圖的機(jī)制相互通信。
最后,即使我們想使用Android但不關(guān)心操作系統(tǒng)內(nèi)部架構(gòu),我們?nèi)匀恍枰獙W(xué)習(xí)Android范式,這與通常的Linux應(yīng)用程序開發(fā)有很大不同,比如說在Qt或GTK。
讓我們現(xiàn)在結(jié)束?
Android 是不是 Linux 發(fā)行版?
我們可以在這篇文章中看到,Android 確實與典型的 GNU/Linux 系統(tǒng)不同,從我們管理源代碼和構(gòu)建系統(tǒng)的方式到文件系統(tǒng)的組織和組件,以及所有組件通過 IPC 進(jìn)行通信的模塊化架構(gòu)/RPC。
我們可以清楚地看到的唯一相似之處是 Linux 內(nèi)核的用法。在 Android 中,幾乎所有其他東西都不同。
那么 Android 是 Linux 發(fā)行版嗎?
這取決于您如何“分類”Linux 發(fā)行版。如果Linux發(fā)行版是任何使用Linux內(nèi)核的系統(tǒng),那么我們大概可以說Android是Linux發(fā)行版。如果 Linux 發(fā)行版是一個遵循相同標(biāo)準(zhǔn)并共享一些公共組件的系統(tǒng),例如 GNU 項目提供的那些,那么 Android 絕對不是 Linux 發(fā)行版。
值得一提的是,隨著時間的推移,Android 正在不斷發(fā)展。Google 面臨的主要挑戰(zhàn)之一是軟件更新。他們無法更新任何設(shè)備,因為它不在他們的控制之下。
Apple 制造 SoC、設(shè)備本身(當(dāng)然!)和軟件,幾乎控制著供應(yīng)鏈的每個方面。因此,他們可以根據(jù)需要(隨時)更新現(xiàn)場的所有設(shè)備。
現(xiàn)在谷歌沒有這個能力。除了 Pixel 設(shè)備,他們對三星或小米等其他公司制造的設(shè)備沒有太多控制權(quán)。
但他們想要這種控制。這就是為什么他們創(chuàng)建項目來改善這種情況,例如Project Trebble、Generic System Images和Generic Kernel Image。
我們在本文中看到的許多建筑設(shè)計都來自這些項目,而且可能還會有更多。是不是更好,只有用戶和市場會告訴你。
總結(jié)
以上是生活随笔為你收集整理的Android 与其他基于 Linux 的系统有何不同?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 蓝桥杯Python初级组测试题之Turt
- 下一篇: 2021-10-18血压计方案|血压计模