1. 操作系统设计目标
a. 用户目标:方便使用,易于学习,可靠,安全等
b. 系统目标:易于实现和维护,灵活,可靠,不易出错,高效等
通常操作系统的设计需要在用户目标和系统目标下做权衡。下面将主要围绕操作系统的设计方法与典型的操作系统结构进行介绍。
2. 操作系统的机制和策略
策略:表示“要做什么”,类似于Java的接口
机制:代表“如何做”,类似于Java中的实现类
将策略和具体机制相分离,可以通过多种不同的策略来适应不同的应用需求,而不需要重新来实现机制,另一方面可以通过不断的完善具体的机制以不断地完善一个策略的实现。
3. M.A.L.H方法
管理复杂系统的重要方法是M.A.L.H方法,即模块化(module)、抽象(abstraction)、分层(layering)、层级(hierarchy)。
a. 模块化:模块化是通过分而治之的原则,将一个复杂的系统通过分解为一系列通过明确定义的接口进行交互的模块。在划分模块的时候,要尽量保证代码的高内聚和低耦合。
b. 抽象:抽象是在模块化的基础上,将接口与内部实现相分离,从而使各个模块之间可以通过对应的接口进行相互调用,而不需要关注各自的具体实现。(附:我们在实现接口时应该尽量遵循宽进严出准则,即一个模块的接口要能够容忍各种可能的输入,抑制错误甚至是恶意输入,避免错误在模块间传播,并且尽可能的严格控制模块对外的输出。)
c. 分层:虽然良好的模块化和抽象可以将一个大系统分解为一系列可以较好的进行交互的模块,但是对于一个庞大的系统而言,分解的模块越多,就会导致模块间的关系越复杂,因此还需要分层与层级来进一步控制复杂度。分层是指将模块按照一定的原则按照对应的层次进行划分,相邻的层之间可以通过接口进行调用,但是不能跨层调用。类似于计算机网络中的OSI七层模型,以及TCP/IP协议的分层。
图1 过多的模块会导致交互非常复杂,需要通过分层与层级来降低复杂度
d. 层级:层级是模块的另一种组织方式,可以理解为对于已经分好的层的具体划分,分层和层级的区别主要是:“分层是指不同的类模块间的层级,层级是指同类模块间的分层”。M.A.L.H方法可以合理地降低系统的复杂度,是组织各个功能模块的有效方法。早期的操作系统(如MS——DOS)缺乏模块化能力,不区分用户态、内核态,使得一个极小的应用程序错误都会导致整个系统崩溃。后来操作系统设计人员利用硬件提供的特权级,对系统进行分层,避免错误的传播。并根据不同的需求,设计了不同的操作系统架构。
4. 操作系统内核架构
随着操作系统功能的不断增多,提供合理的层级结构,对于降低操作系统复杂度,提高操作系统可靠性、安全性变得尤为重要。图2列举了一些常见的操作系统内核架构。
图2 操作系统内核架构图
a. 简要结构:将应用程序与操作系统放置在同一个地址空间中,无需底层硬件实现特权级隔离、内存管理等。该结构的优势在于应用程序对于操作系统的调用可以直接通过函数调用来完成,较为高效(因为其无需从用户态转换到内核态),但是倘若应用程序有一点微小的错误,就有可能导致整个系统崩溃。随着操作系统的功能的完善,它的设计与实现难度也越来越高。除了MS-DOS外,当前采用简要结构的操作系统主要还包括FreeRTOS与uCOS等,这些操作系统主要运行在微控处理单元等相对比较简单的硬件上,这些硬件通常没有实现现在意义上的内存管理单元,隔离能力较弱或者缺失,难以运行复杂的操作系统。
b. 宏内核:其特征在于操作系统的所有模块,包括进程管理,内存管理、文件管理、设备管理等均运行在内核态,具备直接操控硬件的能力。图3展示了一个典型的宏内核架构。
图3 宏内核基本结构
c. 微内核:随着宏内核操作系统的功能不断增长,系统的复杂度持续增加,在可靠性、安全性方面导致了更多的问题。因为在宏内核的模式下,所有的内核模块均运行在特权空间,一个单点的错误就会导致整个系统崩溃或被攻破。在一般的工业界系统代码中每千行代码大约有6-16个缺陷,虽然这些缺陷一般来说不会被触发,部分缺陷即使被触发,也不会带来严重影响。但是对于一个千万行代码级的软件而言,潜在的缺陷数量触目惊心。因此研究人员尝试对宏内核架构的操作系统进行解耦,将单个模块、功能从内核中拆分出来,作为一个独立的服务部署到运行环境中,内核仅保存少量的功能,为这些服务提供通信等基础能力。使各服务之间可以相互协作,已完成各种功能。微内核的瓶颈在于进程间通信,早期的微内核系统是由罗彻斯特大学开发的,由于Mach对进程间通信的设计过于通用,致使Mach微内核自身资源占用过大,性能较差。随后德国信息技术研究中心认为是过度的抽象导致了IPC性能差。并提出了微内核设计原则。 微内核设计原则:一个操作系统内核的功能只有在将其放在内核态以外会影响整个系统功能时,才能将它放置在内核态。通过高性能的IPC以及实现极小化的微核,性能可以得到显著提高。d. 外核架构:1. 过度的硬件资源抽象可能会造成硬件资源损失,违反“抽象但不隐藏能力原则”。2. 操作系统所提供的硬件资源抽象是针对所有应用的通用抽象,这些抽象对于一些具体的应用来说并不是最佳的选择。在许多场景中,应用程序比操作系统更了解如何去抽象和使用硬件资源,因此,应当由应用来尽可能的控制对于硬件资源的抽象,同时提出了库操作系统(LibOS)的概念,将对于硬件的抽象封装到LibOS中,通过直接链接,降低应用开发的复杂度。图4展示了外核操作系统的架构。
图4 外核操作系统的架构
外核架构可以为不同的应用提供定制化的服务,按照不同领域的应用的需求,将硬件资源抽象为一系列的库(LibOS)。可以实现:1. 按照领域的特点和需求,动态组装成最合适的库,最小化非必要的代码,从而获得更高的性能。2. 处于硬件特权级的操作系统内核可以做到非常小,并且多个LibOS之间具有强隔离性,可以提升系统的安全性和可靠性。外核系统的劣势在于LibOS通常是为某种应用特定的,,缺乏跨场景的通用性,应用生态差。e. 多内核架构:即一个处理器上可能集成多种功能、性能甚至指令集结构各异的处理器核。可以将一个众核系统看成一个由多个独立处理器通过网络互联而成的分布式系统。图5展示了多核操作系统架构。
图5 多内核操作系统架构
5. Android系统框架图6展示了Android操作系统的架构,在Linux内核之上运行的Android系统框架主要包括以下几个组件。
图6 Android操作系统架构
硬件抽象层:Android在Linux内核上提供了一层应用抽象层,可以避免与Linux内核版本的实现产生耦合,在者封装了一些硬件实现的细节,更好的实现Linux的内核与Android系统框架的解耦。Android库:Android库提供了一些方便Android应用开发的自定义库,也重新实现了一些标准库。
Android运行环境:Android的主要应用开发语言是Java,需要一个运行时环境将字节码转换成机器指令。自5.0以后采用Ahead-of-Time(AOT)预先编译的方式,将Java代码编译成机器指令,避免了运行时开销。
Android应用框架:Android应用框架提供了应用运行所需要的基础服务,包括服务管理,活动管理,包管理,窗口管理等。这些服务利用操作系统内核提供的资源抽象,为应用提供了一种方便资源调度的应用服务。