李峰峰博客

深入解析 iOS 系统架构

2023-10-07

一、iOS 的诞生

1、macOS 的历史

1984 年,Apple 发布了第一款计算机 Macintosh 128K,Macintosh 以其标志性的图形用户界面(GUI)和用户友好的设计,彻底改变了计算机行业,取代了当时普遍使用的命令行界面。

这个阶段,Macintosh 中的操作系统名称为 System Software,这是 macOS 系统最早期的名称。

1985 年,史蒂夫·乔布斯被“驱逐”离开了 Apple,离开 Apple 后,乔布斯创立了 NeXT 公司,致力于生产高性能的工作站和开发新的操作系统 NeXTSTEP。

NeXTSTEP 基于卡内基梅隆大学开发的 Mach 微内核,这使得系统具有模块化、高效和灵活的特点。Mach 微内核提供了基本的操作系统功能,如进程管理、内存管理和进程间通信(IPC)。NeXTSTEP 所使用的 Objective-C 开发语言,作为 macOS、iOS 的开发语言沿用至今。

NeXTSTEP 拥有优雅的图形用户界面,提供了直观的用户体验。其 GUI 中使用了 PostScript 技术来呈现高质量的文本和图形,与当时的其他操作系统相比显得非常先进。NeXTSTEP 还集成了多种服务功能,包括文件服务器、邮件服务器等,增强了系统的多功能性。

这里不得不提到这个阶段另一家著名的公司 Sun Microsystems(简称 Sun),该公司在 2010 年已被 Oracle Corporation 收购,Sun 在当时以其高性能工作站和服务器而闻名,目前仍然流行的 Java 就是其杰作之一。

Sun 的工作站最初通过直接调用底层 Unix 操作系统和 SunView 窗口系统工具包进行编程,并使用基于这些接口构建的库,这导致即使是简单项目的编程也变得复杂。为了应对这一问题,Sun 在 20 世纪 80 年 代中期推出了 NeWS 窗口系统,尝试使用面向对象的编程模型,但由于复杂的应用程序编程接口(API)和普遍较差的性能,NeWS 并未得到广泛应用,最终被放弃。

为了解决这一问题,1993 年 Sun 决定与 NeXT 进行合作构建其面向对象的应用框架,并对 NeXT 进行 1000 万美元的投资。Sun 与 NeXT 合作,从 NeXTSTEP 操作系统中提取出的核心面向对象编程接口和框架,这些接口和框架经过精简和适配,以便能够在 Sun 的 Solaris 操作系统上运行。最终,Sun 和 NeXT 合作开发出了 OpenStep,OpenStep 就是从 NeXTSTEP 提取出的面向对象编程接口和框架,开发者基于 OpenStep 框架开发出的应用,就可以运行在任何符合 OpenStep 规范的操作系统上。

NeXT 与 Sun 分别基于 OpenStep 改造其现有操作系统,使其操作系统支持基于 OpenStep 开发的应用。1994 年,NeXT 最终发布了一个兼容 OpenStep 的 NeXTSTEP 版本,命名为 OPENSTEP(注意大小写),OPENSTEP 操作系统实际上是 NeXTSTEP 操作系统的 4.0 版本。

1994 发布的官方 OpenStep API 首次将 API 分为 Foundation 和 Application Kit,并首次使用 “NS” 前缀(早期版本的 NeXTSTEP 使用 “NX” 前缀,仅包含 Application Kit)。这个 “NS” 前缀,则是 NeXT/Sun 的简写,这就是 “NS” 前缀的来历。

1996 年,Apple 宣布以 4.29 亿美元收购 NeXT。这一交易旨在获取 OPENSTEP 操作系统的技术,用于开发新一代的 Macintosh 操作系统。史蒂夫·乔布斯也随着这次收购重新回到了 Apple。

收购 NeXT 后,Apple 融合了早期的 System Software 和 OPENSTEP (更准确的说,是 OPENSTEP 慢慢吸收了 System Software),开发出了新一代操作系统:Mac OS X。“Mac” 是 Macintosh 的缩写。

1999 年,Apple 将操作系统 Mac OS X 的底层(Mach 内核及其上的 BSD 层)重新打包,并以开源形式发布了 Darwin 操作系统。并在后续,Apple 以 Darwin 为核心诞生了 iOS、tvOS、watchOS、BridgeOS(用于 Macbook Touch Bar 的 OS) 等一系列变体操作系统:

使用如下命令可以查看系统所使用的 Darwin 版本信息:

1
uname -v


直到现在,macOS、iOS 中仍然可以看到 OPENSTEP 的痕迹。OPENSTEP 对应的 OpenStep 框架演变成了现在 macOS 上的 Cocoa 框架,OpenStep 的 Foundation 和 Application Kit 演变成了 Cocoa 框架中的 Foundation 和 AppKit。

2012 年时候,Apple 简化“Mac OS X” 命名,去掉“Mac”前缀,更名为“ OS X”。

2016 年,苹果公司宣布 OS X 更名为 macOS,以便与苹果其他操作系统 iOS、watchOS 和 tvOS 保持统一的命名风格。

2、macOS 的衍生品 — iOS

2005 年,苹果公司启动了一个名为“Project Purple”的秘密项目,目标是开发一款革命性的移动设备,即后来的 iPhone。在技术上,乔布斯面临两个选择:

  • 把 Mac 缩小:即基于 macOS 技术开发 iPhone 操作系统。
  • 把 iPod 扩大:即基于 iPod 的操作系统开发 iPhone 操作系统。
    • iPod 使用的操作系统是一个专为嵌入式设备设计的系统,是基于 Pixo OS 定制化开发出来的。

史蒂夫·乔布斯采用了内部竞争的策略,让 Mac 团队和 iPod 团队分别提出各自的方案,并通过竞争来激发创新和找到最佳的技术解决方案。最终,Mac 团队胜出,决定基于 macOS 开发 iPhone 使用的操作系统,即后来的 iOS 系统。为了适应移动设备的资源限制,苹果对 macOS 的许多组件进行了优化。例如,内存管理和电源管理系统进行了调整,以适应 iPhone 的硬件配置。

2007 年 1 月,苹果公司于 Macworld 开发者大会上为 iOS 揭幕,并宣布于同年 6 月推出。在揭幕时,乔布斯称:“iPhone 运行 OS X,并且可使用‘桌面应用程序’”,最初随 iPhone 发布的操作系统并没有独立的名称,直至 2008 年才正式取名为 iPhone OS。

2010 年 6 月,苹果公司于全球开发者大会中,宣布把 iPhone OS 重命名为 iOS,然而,思科系统已经使用 “iOS” 商标多年,用于其网络设备的操作系统,iOS 在思科的定义是 “Internetwork Operating System”。为避免商标侵权纠纷,苹果公司与思科系统达成了协议,从思科获得了“iOS”商标的使用权。

iOS 作为 iPhone 中的操作系统名称,沿用至今。

所以,从本质上看,iOS 实际上就是 macOS,但是两者还是有一些显著的区别的:

  • 目标架构

    • iOS:iOS 的内核和二进制文件编译的目标架构是基于 ARM 架构。
      • ARM 处理器设计在电源管理方面具有显著优势,这对于移动设备来说非常重要。
    • macOS:早期 macOS 的内核和二进制文件编译的目标架构主要是 Intel 的 x86_64 架构。
      • Intel 处理器在性能方面表现出色,适用于桌面和笔记本电脑等需要高性能计算的设备。
      • 2020 年,新款 MacBook 从 Intel x86_64 架构的处理器转向自家设计的基于 ARM 架构的 Apple Silicon 处理器。
        • x86 是 32 位架构,而 x86_64 是其 64 位扩展版本
  • 内核源码开放性

    • iOS:iOS 的内核源码是闭源的,尽管苹果公司承诺 macOS 的内核 XNU 要一直开源,但这一承诺并不适用于 iOS。
    • macOS:macOS 的内核 XNU 是开源的,苹果公司定期发布其源代码。
  • 系统 GUI

    • iOS:iOS 的系统 GUI 是 SpringBoard,这是一个触屏应用加载器。
      • SpringBoard 的设计专注于触摸交互,适用于移动设备。
    • macOS:macOS 的 GUI 是 Aqua,这是一个鼠标驱动的界面,特别为窗口系统设计。
      • Aqua 界面专注于窗口管理和多任务处理,提供了丰富的桌面操作体验。
  • 内存限制

    • iOS:iOS 的内存管理更加紧凑,因为移动设备上没有几乎无穷的交换空间。开发者需要适应更严苛的内存限制和编程模型。
    • macOS:macOS 可以利用更大的物理内存和交换空间,内存管理相对宽松。
  • 系统限制和安全性

    • iOS:iOS 系统的限制更加严格,应用程序不允许访问底层 UNIX API(即 Darwin),也没有 root 访问权限,只能访问自己的目录数据。只有苹果的应用可以访问整个系统。App Store 的应用被严格限制,必须通过苹果的审查。
    • macOS:macOS 系统的限制相对宽松,用户和应用程序可以访问底层 UNIX API,具有更高的系统权限。用户可以安装和运行未经过苹果审查的应用程序。

3、CUP 架构的统一

iPhone 4 之前,iPhone 使用的是三星研发的基于 ARM11 架构的处理器,从 iPhone 4 开始,苹果转向使用自家设计的 A 系列处理器,首款为 A4。A 系列处理器基于 ARM 架构,由苹果自主设计并由合作伙伴制造。而 Mac,则主要使用的是 Intel x86_64 处理器。

Mac 基于 Intel x86_64,遇到了如下问题:

  • 性能和能效瓶颈

    • 性能提升有限:近年来,Intel 处理器的性能提升速度放缓,未能满足苹果对高性能计算的需求。
    • 能效比不足:Intel 处理器在能效比方面表现不佳,特别是在笔记本电脑和移动设备中,电池续航时间成为一个重要问题。
  • 散热和功耗

    • 功耗较高:Intel 处理器的功耗较高,导致设备发热严重,影响用户体验和设备寿命。
    • 散热问题:高功耗带来的散热问题,使得设备设计需要更复杂的散热系统,增加了设计难度和成本。
  • 生态系统整合

    • 架构不统一:苹果的移动设备(如 iPhone 和 iPad)使用的是 ARM 架构,而 Mac 设备使用的是 Intel x86_64 架构。这种架构不统一导致开发者需要为不同架构编写和优化应用程序,增加了开发和维护的复杂性。

近年来,媒体报道中多次记载了苹果对英特尔研发速度和质量的疑惑和不满。一份 2018 年的报告指出英特尔芯片的问题导致了苹果对 MacBook 的重新设计(链接)。2019 年,苹果指责英特尔芯片库存的短缺导致了 Mac 销量的下降(链接)。

到 2020 年,有报道指出在 2018 款 iPad Pro 中使用的基于 ARM 架构的 Apple A12X Bionic 处理器已经能够在性能上和在 MacBook Pro 中使用的英特尔 Core i7 处理器打平。

最早在 2018 年,就有媒体报道苹果计划用自家设计的处理器取代 Mac 设备中的 Intel 处理器,这一计划被称为“Project Kalamata”。

最终,2020 年的全球开发者大会(WWDC 2020)上,Apple 公布自己研发的基于 ARM64 架构的新一代处理器:Apple Silicon。Apple Silicon 是苹果公司为其自家设计的基于 ARM 架构的处理器所使用的总称,而 M 系列处理器是 Apple Silicon 家族中的具体产品系列之一。Apple 同时发布了新版操作系统 macOS Big Sur,是首个支持 Apple Silicon 的 macOS 版本。以及发布了搭载首款 M 系列处理器 M1 以及 macOS Big Sur 系统的一系列 MacBook 设备。

macOS Big Sur 系统的发布标志着苹果开始从 x86-64 架构(Intel 处理器)过渡到 ARM 架构(Apple Silicon 处理器)。为了确保这一过渡的顺利进行,并确保用户在新旧架构上的无缝体验,苹果采取了一系列技术措施,使得自带应用和第三方应用能够同时支持 x86-64 与 ARM 架构:

  • 通用二进制(Universal Binary)

    • 通用二进制是一种包含多个架构版本的应用程序包。在 macOS Big Sur 系统中,苹果引入了新的通用二进制格式,使得应用程序可以同时包含 x86-64 和 ARM 架构的代码。
    • 实现方式:
      • 编译工具:通过 Xcode 开发工具,开发者可以将他们的应用程序编译为通用二进制,包含适用于 Intel 和 Apple Silicon 的代码。
      • 自动选择:当用户在不同架构的 Mac 上运行应用程序时,系统会自动选择并执行适用于当前硬件架构的代码。
  • Rosetta 2

    • Rosetta 2 是一个动态二进制翻译层,允许基于 x86-64 架构的应用程序在 Apple Silicon 设备上运行。
    • 工作原理:
      • 动态翻译:当用户在 Apple Silicon 设备上运行仅支持 x86-64 架构的应用程序时,Rosetta 2 会在运行时将 x86-64 指令动态翻译为 ARM 指令。
      • 性能优化:Rosetta 2 不仅支持动态翻译,还能在应用程序安装或首次运行时进行静态翻译,以提高性能。

至此,iPhone、iPad、Mac 实现了 CPU 架构的统一。CPU 架构的统一就意味着软件生态的统一,开发者开发一个 APP,就可以同时运行在 iPhone、iPad、Mac 设备上。

二、iOS 架构

前面已经提到,iOS 起源于 macOS,本质上 iOS 就是精简版的 macOS,下图是 Apple 官方文档对 macOS & iOS 架构层次划分:

可以看到,Apple 对 macOS & iOS 在架构上分层,本质上是一样的。

这里主要关注 iOS,在 Apple 官方架构分层上,iOS 系统架构层次如下:

  • 触摸层(Cocoa Touch)

    • 提供了开发者常用的框架。
    • 包括 UIKit、MapKit、iAd 等。
  • 媒体层(Media)

    • 为 Cocoa Touch 层提供 UI 渲染和多媒体服务。
    • 包括 Metal、CoreText、QuartzCore、CoreGraphics 等。
      • 我们常用的 CoreAnimation 位于 QuartzCore 中。
  • 核心服务层(Core Services)

    • 提供了如字符串操作、集合管理、网络、URL工具、联系人管理和偏好设置等服务的框架。
    • 还提供了基于设备硬件特性的服务,例如 GPS、指南针、加速度计和陀螺仪。
    • 包括 Foundation、CoreFoundation、CFNetwork、CoreLocation、CoreData 等。
  • 核心系统层(Core OS)

    • 提供了系统级的底层功能,一般来说开发者不需要接触这些技术。
    • 这一层主要由三部分组成:
      • Darwin
        • Darwin 是 macOS 和 iOS 操作系统开发的核心,是基于 XNU 内核的操作系统。Darwin 包含了核心的操作系统组件,包括内核、驱动程序、文件系统和网络堆栈等。
        • Darwin 提供了开发者常用的 libSystem 库。libSystem 是一个综合性的基础库,包含了多个子库,例如 libdispatch(GCD)、libsystem_blocks(Block)、libpthread(pthread) 等。
      • 64-Bit Support
        • iOS 最初设计支持在使用 32 位架构的设备上运行二进制文件。从 iOS 7 开始,引入了对 64 位架构的编译、链接和调试二进制文件的支持。
        • iOS 使用与 OS X 和其他 64 位 UNIX 系统相同的 LP64 模型,LP64 模型通过定义特定数据类型的大小,提供了一种在 64 位系统中管理内存和数据的标准方式。
      • Frameworks
        • 核心系统层提供了一系列安全性或与外部硬件配件通信相关的框架,通过使用这些框架,开发者可以很容易地实现安全和硬件交互功能。
        • 包括 Accelerate、CoreBluetooth、Security 等框架。

在上述架构层次中,Darwin 是整个系统的基础。不同的是,macOS 上的 Darwin 是开源的,而 iOS 中的 Darwin 是在 ARM 上的移植,这个 Darwin 则是不开源的。架构层次的其他部分在 macOS & iOS 上也都是不开源的,属于 Apple 的私有知识产权。

“Cocoa Touch 层(触摸层)” 与 “Cocoa Touch”
在上述 iOS 架构中,”Cocoa Touch 层(触摸层)”并不完全等价于 “Cocoa Touch”,”Cocoa Touch 层”是 iOS 架构中的一个特定层次,专注于用户界面和交互,并非传统意义上的 “Cocoa Touch”。

那么,Cocoa Touch 是什么呢?
关于这个问题,Apple 官方文档中给出了明确的答案:

Cocoa and Cocoa Touch are the application development environments for OS X and iOS, respectively. Both Cocoa and Cocoa Touch include the Objective-C runtime and two core frameworks:
Cocoa, which includes the Foundation and AppKit frameworks, is used for developing applications that run on OS X.
Cocoa Touch, which includes Foundation and UIKit frameworks, is used for developing applications that run on iOS.

即:Cocoa Touch 是 iOS 应用的开发环境,包含了 iOS 开发所用到的一系列框架和技术。Cocoa Touch 中两个最核心的框架分别是 UIKit、Foundation,UIKit、Foundation 分别位于 iOS 系统架构的不同层次中,UIKit 位于触摸层(Cocoa Touch 层),Foundation 位于核心服务层(Core Services 层)。

iOS 中的 “Cocoa Touch” 等价于 macOS 中的 “Cocoa”,macOS 的 Cocoa 两个最核心的框架是 AppKit、Foundation,其中 AppKit 就等价于 iOS 中的 UIKit。在基于 macOS 开发出 iOS 系统之后,macOS 中的 Cocoa 就演变成了 iOS 中的 Cocoa Touch。

在开发时,”Cocoa Touch” 通常泛指所有继承自根类 NSObject 的类或对象。

三、Darwin

Darwin 是 Apple 1999 年开源出的操作系统,Darwin 是一个完整的操作系统,也是 macOS、iOS、tvOS、watchOS、BridgeOS 系统的基础。

Darwin 操作系统的主要作用,是在应用程序和硬件之间,提供一层抽象。Darwin 提供了应用程序与硬件交互的抽象接口,使开发者在开发应用程序时,避免了和硬件的直接交互,也就避免了对不同硬件的适配。由于操作系统可以运行在不同的硬件上,因此开发者编写的代码就具有了可移植性。

iOS 在 Darwin 基础上,向开发者提供了图形渲染能力及面向对象开发环境,如 Metal、QuartzCore、CoreGraphics 和 Cocoa Touch,开发者可以在此基础上,进行 APP 的开发。Darwin 的内核是 XNU,Darwin 所承担的具体工作,都是由 XNU 来完成的。当 APP 需要内核 XNU 提供服务时,就需要通过 Darwin 提供的系统调用相关的 API,从用户态切换到内核态,内核 XNU 在内核态完成具体工作后,再切换回用户态,由 APP 完成后续工作。

Darwin 架构如下:

1、libSystem.B.dylib

libSystem.B.dylib 是 Darwin 系统上的非常重要的一个核心动态链接库,几乎所有的系统服务和应用程序都依赖它,libSystem.B.dylib 通过整合多个系统库的符号和链接信息,提供了统一的接口,使得开发者只需链接一个库即可访问多种基础功能,简化了开发过程,同时保持系统库的模块化和可扩展性。

libSystem.B.dylib 主要包含符号表和链接信息,而不包含实际的实现代码。它充当一个伪装库(stub library),在编译时提供符号解析,在 APP 启动时由动态链接器(dyld)解析并加载实际的实现库。

以 iOS 15.6.1 为例,其 libSystem.B.dylib 位于如下目录中:

1
/Users/lifengfeng/Library/Developer/Xcode/iOS DeviceSupport/iPhone13,2 15.6.1 (19G82)/Symbols/usr/lib/libSystem.B.dylib

每个版本模拟器,libSystem.B.dylib 所处位置可能不同,可以使用如下命令查找 libSystem.B.dylib 的位置:

1
sudo find / -name libSystem.B.dylib 2>/dev/null

找到 libSystem.B.dylib 后,可以使用 otool 工具查看 libSystem.B.dylib 里依赖的具体系统库:

  • otool -L:用于显示 Mach-O 文件的动态库依赖列表,简洁地列出所有依赖的动态库及其版本信息。
  • otool -l:用于显示 Mach-O 文件的所有加载命令,提供详细的元数据信息,包括段信息、依赖库、符号表等。

可以使用 otool -L 命令打印 libSystem.B.dylib 依赖的系统库信息:

1
otool -L /Users/lifengfeng/Library/Developer/Xcode/iOS\ DeviceSupport/iPhone13,2\ 15.6.1\ \(19G82\)/Symbols/usr/lib/libSystem.B.dylib

打印内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/Users/lifengfeng/Library/Developer/Xcode/iOS DeviceSupport/iPhone13,2 15.6.1 (19G82)/Symbols/usr/lib/libSystem.B.dylib:
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1311.120.1)
/usr/lib/system/libcache.dylib (compatibility version 1.0.0, current version 85.0.0, reexport)
/usr/lib/system/libcommonCrypto.dylib (compatibility version 1.0.0, current version 60191.100.1, reexport)
/usr/lib/system/libcompiler_rt.dylib (compatibility version 1.0.0, current version 103.1.0, reexport)
/usr/lib/system/libcopyfile.dylib (compatibility version 1.0.0, current version 1.0.0, reexport)
/usr/lib/system/libcorecrypto.dylib (compatibility version 1.0.0, current version 1218.120.10, reexport)
/usr/lib/system/libdispatch.dylib (compatibility version 1.0.0, current version 1325.120.2, reexport)
/usr/lib/system/libdyld.dylib (compatibility version 1.0.0, current version 1.0.0, reexport)
/usr/lib/system/libmacho.dylib (compatibility version 1.0.0, current version 994.2.0, reexport)
/usr/lib/system/libremovefile.dylib (compatibility version 1.0.0, current version 60.0.0, reexport)
/usr/lib/system/libsystem_asl.dylib (compatibility version 1.0.0, current version 392.100.2, reexport)
/usr/lib/system/libsystem_blocks.dylib (compatibility version 1.0.0, current version 79.1.0, reexport)
/usr/lib/system/libsystem_c.dylib (compatibility version 1.0.0, current version 1507.100.9, reexport)
/usr/lib/system/libsystem_collections.dylib (compatibility version 1.0.0, current version 1507.100.9, reexport)
/usr/lib/system/libsystem_configuration.dylib (compatibility version 1.0.0, current version 1163.140.3, reexport)
/usr/lib/system/libsystem_containermanager.dylib (compatibility version 1.0.0, current version 1.0.0, reexport)
/usr/lib/system/libsystem_coreservices.dylib (compatibility version 1.0.0, current version 133.0.0, reexport)
/usr/lib/system/libsystem_darwin.dylib (compatibility version 1.0.0, current version 1.0.0, reexport)
/usr/lib/system/libsystem_dnssd.dylib (compatibility version 1.0.0, current version 1557.140.4, reexport)
/usr/lib/system/libsystem_featureflags.dylib (compatibility version 1.0.0, current version 56.0.0, reexport)
/usr/lib/system/libsystem_info.dylib (compatibility version 1.0.0, current version 1.0.0, reexport)
/usr/lib/system/libsystem_m.dylib (compatibility version 1.0.0, current version 3204.80.2, reexport)
/usr/lib/system/libsystem_malloc.dylib (compatibility version 1.0.0, current version 374.120.1, reexport)
/usr/lib/system/libsystem_networkextension.dylib (compatibility version 1.0.0, current version 1.0.0, reexport)
/usr/lib/system/libsystem_notify.dylib (compatibility version 1.0.0, current version 301.0.0, reexport)
/usr/lib/system/libsystem_product_info_filter.dylib (compatibility version 1.0.0, current version 10.0.0, reexport)
/usr/lib/system/libsystem_sandbox.dylib (compatibility version 1.0.0, current version 1657.140.3, reexport)
/usr/lib/system/libsystem_kernel.dylib (compatibility version 1.0.0, current version 8020.142.2, reexport)
/usr/lib/system/libsystem_platform.dylib (compatibility version 1.0.0, current version 273.100.5, reexport)
/usr/lib/system/libsystem_pthread.dylib (compatibility version 1.0.0, current version 486.100.11, reexport)
/usr/lib/system/libsystem_symptoms.dylib (compatibility version 1.0.0, current version 1.0.0, reexport)
/usr/lib/system/libsystem_trace.dylib (compatibility version 1.0.0, current version 1375.140.2, reexport)
/usr/lib/system/libunwind.dylib (compatibility version 1.0.0, current version 202.2.0, reexport)
/usr/lib/system/libxpc.dylib (compatibility version 1.0.0, current version 2236.140.2, reexport)

在上述的打印信息中,列出了 libSystem.B.dylib 依赖的其他系统动态链接库的信息,其中,每一行中的 “reexport” 表示该动态库使用了 LC_REEXPORT_DYLIB 命令重新导出这些依赖库中的符号。这样,任何链接到 libSystem.B.dylib 的 APP 或其他动态库都可以直接使用这些被重新导出的符号,而无需直接链接到这些底层库。

当一个应用程序或动态库加载包含 LC_REEXPORT_DYLIB 命令的动态库时,动态链接器(dyld)会立即解析并加载所有 LC_REEXPORT_DYLIB 指定的库。这意味着这些库会在 APP 冷启动时,随着 libSystem.B.dylib 一起加载到内存中。

同时,可以在上述的打印信息中,可以看到我们开发中常用的一些系统库,例如:

  • libdispatch.dylib:提供了 GCD
  • libsystem_blocks.dylib:提供了 Block
  • libsystem_pthread.dylib:提供了 pthread
  • libsystem_c.dylib:提供了标准 C 库,如字符串操作、输入输出、数学运算等。

2、用户态 & 内核态

(1)什么是用户态、内核态

一个 iOS APP 从开发到运行,大致流程如下:

  • 在开发时,我们使用高级语言(如 Objective-C 或 Swift)编写源代码文件。
  • 源代码文件经过编译器的处理,首先被转换为汇编语言,这个过程是将高级语言的语法和结构转换为更接近硬件的汇编语言。
  • 之后编译器会将汇编语言进一步编译为机器语言,机器语言是由二进制代码组成的语言,这些二进制代码就是 CPU 指令集中的指令。机器语言是可以直接被 CPU 执行的代码。
    • 这些机器语言的代码以及其他信息最终会被打包成一个 Mach-O 文件。
  • 当用户启动 APP 时,iOS 操作系统会将 APP 的这些机器语言指令从磁盘加载到内存中并执行。

如下图:

CPU 指令集可以直接操作硬件的,如果指令操作的不规范,会对整个计算机系统产生很大的影响,甚至会导致操作系统或其他程序的崩溃。因此,为了防止应用程序崩溃而导致的内核崩溃,内核与应用程序之间需要进行严格的分离。基于软件的分离会产生巨大的开销,所以现代的操作系统都是依靠硬件来分离,分离的结果就是用户态与内核态。

为了保护系统的安全和稳定,硬件设备商直接在硬件层面对 CPU 指令设置了权限,在 iPhone 设备上,CPU 采用的是 ARM 架构,其指令集操作的权限等级主要分为用户模式(User mode)和特权模式(Privileged mode),这两种模式对应于操作系统的用户态和内核态。

  • 用户模式(User mode)

    • 对应于操作系统的用户态。
    • 用户模式是应用程序的运行模式。在这种模式下,应用程序只能访问自己的内存空间,不能直接访问硬件或其他程序的内存,也不能执行特权指令。如果应用程序需要执行这些特权操作,如读写文件、创建进程等,必须通过系统调用的方式,请求操作系统代为完成。
  • 特权模式(Privileged mode)

    • 对应于操作系统的内核态。
    • 特权模式是操作系统内核的运行模式。在这种模式下,操作系统可以访问所有的硬件和内存,可以执行所有的 CPU 指令。特权模式通常用于处理系统调用、中断等系统级的任务。

在特权模式下,又可以细分为以下几种子模式,以处理不同的系统级任务:

  • 系统模式(System mode)

    • 这是操作系统内核的正常运行模式。
    • 在这种模式下,操作系统可以访问所有的硬件和内存,可以执行所有的 CPU 指令。当用户态应用程序需要执行高权限的操作(如文件读写、网络通信、进程管理等),会触发系统调用,并在系统模式下完成对应工作。
  • 中断模式(IRQ mode)和快速中断模式(FIQ mode)

    • 这些模式用于处理硬件中断。
    • 中断模式(IRQ mode)
      • 用于处理标准硬件中断请求(Interrupt Requests, IRQs)。
      • 当系统外设(如键盘、鼠标、网络设备等)需要 CPU 处理某个事件时,它们会发出中断信号,请求系统的注意。
    • 快速中断模式(FIQ mode)
      • 用于处理快速、紧急的硬件中断请求(Fast Interrupt Requests, FIQs)。
      • 设计用于需要最低延迟和最高优先级的中断处理场景,该模式对时间敏感的任务(如音频和视频处理、实时通信等)提供最佳支持。
  • 异常模式(Abort mode)

    • 这种模式用于处理内存访问异常。
    • 当程序试图访问一个无效的内存地址时,CPU 会切换到异常模式,执行预设的异常处理程序。
  • 未定义模式(Undefined mode)

    • 这种模式用于处理未定义的指令。
    • 当程序试图执行一个未定义的指令时,CPU 会切换到未定义模式,执行预设的错误处理程序。

(2)用户态、内核态的转换

前面已经提到,用户态、内核态的区分是由硬件(CPU)提供的,当我们开发的 APP 需要内核 XNU 提供服务时,就需要从用户态切换到内核态,由 XNU 在内核态完成对应工作后,再切回回用户态,由 APP 继续完成后续的工作。

用户态、内核态转换,主要有两种方式:

  • 自愿转换
    • 当应用程序需要内核服务的时候,应用程序通过系统调用进入内核态。这种转换方式就是自愿切换。
  • 非自愿转换
    • 当发生执行异常、中断或处理器陷阱的时候,代码的执行会被挂起,并且保留发生错误时候的完整状态。控制权被转交给预定义的内核态错误处理程序或中断服务程序(interrupt serviceroutine, ISR)。

在 XNU 中,系统调用有四种类别:

  • BSD 系统调用

    • “经典” 的系统调用,是 XNU 的 BSD 提供的接口,又称“BSD 调用”。
    • BSD 提供的这些接口遵循 POSIX 标准,提供与 Unix 类操作系统兼容的功能,如文件操作、进程管理、网络通信等。
    • 如常用的 openreadwritemmap 等 C 函数内部都是使用 syscall 指令将控制权转移到内核态。
  • Mach 陷阱

    • XNU 的 Mach 提供的接口。
    • 用于进程间通信(IPC)、任务管理、内存管理和其他底层操作系统功能。
    • 用户态程序通过调用 Mach API 函数(如 mach_msgtask_createvm_allocate 等)发起 Mach 陷阱,这些函数内部使用 trap 指令将控制权转移到内核态。
  • 机器相关的调用

    • 用于访问 CPU 特定的功能。
    • 例如 CPU 缓存管理、性能监控、特殊寄存器访问等。
  • 诊断调用

    • 专门用于内核调试和诊断,提供内核状态监控、调试信息输出等功能。
    • 这些调用通常不用于普通应用程序,而是用于开发和调试内核模块或驱动程序。

3、XNU

(1)XNU 概述

内核 XNU 是 Darwin 的核心,也是整个 iOS 的核心。XNU 是 “X is Not Unix” 的缩写,这是一个带有调侃意味的命名。Unix 社区有一种幽默文化,喜欢用反讽或自嘲的方式命名项目。例如:

  • GNU:GNU’s Not Unix,是一个递归缩写,表明 GNU 项目虽然与 Unix 兼容,但不是 Unix。
  • PINE:”Pine Is Not Elm”,PINE 是一个邮件客户端,名字表明它不是另一个著名的 Unix 邮件客户端 Elm。

XNU 虽然是 “X is Not Unix” 的缩写,但它仍然深受 UNIX 的设计影响,特别是在 BSD 方面,XNU 通过 BSD 提供了与 UNIX 兼容的功能,使得许多 UNIX 应用程序可以在 macOS 和 iOS 上运行。

1969 年,Ken Thompson 和 Dennis Ritchie 等人在贝尔实验室开发了操作系统 UNIX,UNIX 的设计强调简单性、可移植性、模块化和多用户支持,这些设计原则影响了许多后来的操作系统。UNIX 并不是一个开源的操作系统,但在 1970 年代和 1980 年代,AT&T(贝尔实验室的母公司)通过许可协议将 UNIX 源代码提供给学术机构和商业公司,加州大学伯克利分校就是这些学术机构之一。

加州大学伯克利分校的计算机系统研究小组(CSRG)在 UNIX 的基础上进行了大量的改进和扩展,开发出了 BSD 系列操作系统。在 1990 年代,BSD 社区进行了大量工作,以移除 BSD 版本中所有 AT&T 的专有代码。最终在 1994 年发布了 BSD 的新版本 4.4BSD-Lite,这个版本 BSD 已经不含 AT&T 的专有代码。4.4BSD-Lite 及其后续版本是完全开源的,任何人都可以自由使用、修改和分发这些代码,这使得 BSD 系统成为真正的开源 UNIX 实现。

BSD 系统引入了许多关键技术和概念,如虚拟内存、TCP/IP 网络协议栈、文件系统(如 FFS)等,BSD 的开源发布为后来的开源操作系统奠定了基础,许多开源项目直接或间接地受益于 BSD 的代码和设计。FreeBSD、OpenBSD、NetBSD 是三个比较著名的 BSD 血统的操作系统:

  • FreeBSD
    • 一个基于 4.4BSD-Lite 的开源操作系统,以其高性能和先进的网络功能著称。
  • OpenBSD
    • 专注于安全性和代码审计的开源操作系统。
  • NetBSD
    • 以其可移植性著称,支持多种硬件平台的开源操作系统。

其中,FreeBSD 以其高性能、稳定性和丰富的网络功能著称,广泛用于服务器和嵌入式系统。Darwin 中的 BSD 就是基于 FreeBSD 进行开发的,XNU 中的 BSD 为 Darwin 提供了 POSIX 兼容的 API 和工具集,让 Darwin 具备了与 Unix 类操作系统兼容的功能,使得许多 UNIX 应用程序可以在 macOS 和 iOS 上运行。

(2)XNU 的架构

所有操作系统的架构上,都包含内核,但内核的设计上却有所不同。目前主流的,主要有三种风格的内核:宏内核、微内核和混合内核。

宏内核

宏内核又称 “巨内核”、”单内核”,这是一个比较经典的内核架构,也是 UNIX 和 Linux 世界采用的主要内核架构。宏内核的特点是将所有内核功能全部放在一个地址空间中。

宏内核大致架构如下图:

宏内核将所有内核功能全部放在一个地址空间中,并且将这个地址空间映射到每一个进程的内存中。这种设计使得除了硬件强制的内核态和用户态之间的隔离外,用户态和内核态其实没有任何分别,所以从用户态到内核态的切换非常高效,基本上就相当于一次线程切换的开销。

微内核

微内核并不像宏内核那么常见,微内核的特点是内核只包含最核心的内核功能,通常包括进程间通信(IPC)、线程管理、虚拟内存管理、时钟和定时器等。

内核功能之外的部分全部交给各个独立的用户态服务程序完成,这些用户态服务程序包括文件系统服务、网络协议栈服务、进程管理服务等。服务程序之间的所有通信都由消息传递完成。消息传递机制允许将消息(通常都是透明的)以及后续消息投递至服务程序的队列中排队,服务程序可以从队列中取出消息并且依次处理。

微内核大致架构如下图:

微内核由于功能简单、代码量少,所以相较于宏内核,微内核更加稳定,并且更容易移植到其他平台。

但微内核也有其显著的缺点,微内核的消息传递在底层需要通过内存复制操作以及数次上下文切换操作来实现,而这些操作对计算速度的影响都不小。这一个缺点太严重了,所以“纯粹” 的微内核操作系统基本上只具有学术意义,而没有商业应用,在现代操作系统中则更少见。

混合内核

混合内核就是同时包含宏内核和微内核的架构,同时吸收了两种内核架构的优点,兼顾了健壮性、可移植性和运行效率。内核中最核心的部分,如进程间通信(IPC)、线程管理、虚拟内存管理、时钟和定时器等,仍然由微内核负责,其余部分则交由宏内核负责,并且都在内核态之中,而且都在同一个内存空间之中。

XNU 是一个由宏内核 BSD 与微内核 Mach 组成的混合内核:

XNU 主要由三部分组成:

  • Mach

    • Mach 最初是一个在卡内基梅隆大学(CMU)开发的研究型操作系统,致力于研制一个用于操作系统的轻量级且高效的平台。
    • Mach 提供内核最基础的 API 和功能,主要包括:
      • 进程间通信(IPC)
      • 线程管理和调度
      • 虚拟内存管理
      • 时钟和定时器
  • BSD

    • BSD 建立在 Mach 之上,提供了 POSIX 标准的 API,使得许多 UNIX 应用程序可以在 macOS 和 iOS 上运行。
    • BSD 提供了更高层次的抽象功能,主要包括:
      • 文件系统访问
      • 进程管理
      • 资源控制
      • 网络协议栈
  • I/O Kit

    • 一个面向对象的框架,用于开发设备驱动程序,提供了与硬件交互的标准接口,提高驱动程序的安全性和可维护性。

XNU 也是完全开源的,GitHub 链接是:https://github.com/apple-oss-distributions/xnu