1. Android系统架构概览:从硬件到应用的四层架构

做Android底层开发这么多年,我经常被问到同一个问题:「Android系统到底是怎么跑起来的?」

说实话,这个问题看似简单,但真要讲清楚,得从整个架构说起。今天我就带大家从硬件到应用,把Android的四层架构捋一遍。你想想看,一个手机从按下电源键到屏幕上出现桌面,中间经历了多少层?每一层又在干什么?

嗯,我们先看一张经典的架构图(脑补一下):

┌─────────────────────────────────────┐
│         应用层 (Applications)        │
│   (电话、短信、浏览器、第三方App)    │
├─────────────────────────────────────┤
│       系统服务层 (Framework)         │
│   (ActivityManager、WindowManager等) │
├─────────────────────────────────────┤
│      硬件抽象层 (HAL)               │
│   (Camera HAL、Audio HAL、GPS HAL)  │
├─────────────────────────────────────┤
│        Linux内核层 (Kernel)          │
│   (进程调度、内存管理、驱动)         │
└─────────────────────────────────────┘
        硬件 (CPU、GPU、传感器等)

说白了,Android就是典型的分层架构。每一层各司其职,又通过定义好的接口互相通信。我习惯把这四层比作一个公司的组织架构——底层是执行部门,顶层是决策部门,中间是管理层和翻译官。

1.1 Linux内核层:地基中的地基

Android为什么选Linux内核?很多人觉得是因为开源。其实更关键的是——Linux内核提供了最成熟的内存管理、进程调度、网络协议栈。你想想,一个手机要同时跑几十个App,还要保证系统不卡顿,这活儿真不好干。

我在项目中遇到过一件事:某款手机在低内存场景下频繁卡死,查了三天,最后发现是内核的lowmemorykiller阈值设置不合理。嗯,这种问题在应用层根本看不出来,必须深入到内核层才能定位。

内核层主要干这几件事:

  • 进程调度:决定哪个App先跑,哪个后跑
  • 内存管理:分配和回收内存,防止内存泄漏
  • 驱动支持:屏幕、触摸、WiFi、蓝牙……所有硬件都得有驱动
  • 安全机制:基于Linux的权限模型,每个App都是独立用户

核心要点:内核层是Android的「心脏」,但它不直接跟应用层打交道。应用层想用硬件?得通过中间两层。

1.2 硬件抽象层(HAL):硬件的「翻译官」

这里有个问题:为什么Android要搞一个HAL层?

直接让Framework调用内核驱动不行吗?

我告诉你,不行。因为硬件厂商太多了。高通、联发科、三星……每家都有自己的驱动实现方式。如果Framework直接跟驱动耦合,那Google得累死——每出一个新硬件就得改Framework。

HAL的作用就是定义一套标准接口。厂商只需要实现这套接口,Framework不用关心底层是哪个芯片。说白了,HAL就是硬件的「翻译官」——把千奇百怪的硬件实现,翻译成Framework能听懂的统一语言。

举个例子,Camera HAL:

// HAL层定义的统一接口
typedef struct camera_device_t {
    int (*open)(const struct hw_module_t* module, 
                const char* id, 
                struct hw_device_t** device);
    int (*close)(struct hw_device_t* device);
    int (*set_parameters)(struct camera_device_t* dev, 
                          const char* params);
    // ... 其他接口
} camera_device_t;

你看,不管你是索尼的传感器还是三星的传感器,只要实现了这套接口,Framework就能正常调用。我曾经帮一个ODM厂商调试摄像头,他们HAL层实现有bug,导致预览画面一直黑屏。查了两天,最后发现是set_parameters里少处理了一个参数。

个人经验:调试HAL层问题时,建议先确认接口是否被正确调用。我习惯在HAL层加日志,打印每个函数的入参和返回值。这招虽然土,但特别管用。

1.3 系统服务层(Framework):Android的「大脑」

Framework层是Android最复杂的一层,也是我们做系统开发打交道最多的一层。它运行在Java虚拟机(ART)上,提供各种系统服务。

常见的系统服务有:

服务名称 职责 我踩过的坑
ActivityManagerService 管理Activity生命周期、进程调度 AMS死锁导致ANR,排查了一整天
WindowManagerService 管理窗口层级、触摸事件分发 窗口层级错乱,App界面被状态栏遮挡
PackageManagerService 管理App安装、卸载、权限 签名校验失败,第三方App装不上
PowerManagerService 管理电源状态、休眠唤醒 wake lock没释放,手机一晚上掉电50%

Framework层跟HAL层怎么通信?通过JNI(Java Native Interface)。Java代码调用Native代码,Native代码再调用HAL接口。举个例子:

// Framework层(Java)
public class Camera {
    private native int nativeOpen(String id);
    
    public void open() {
        nativeOpen("0");  // 调用JNI
    }
}

// JNI层(C++)
JNIEXPORT jint JNICALL
Java_android_hardware_Camera_nativeOpen(JNIEnv* env, 
                                        jobject thiz, 
                                        jstring id) {
    // 调用HAL接口
    return hal_camera_open(env->GetStringUTFChars(id, NULL));
}

你看,这一层一层的调用,就像剥洋葱。每一层只关心自己的事,通过接口跟上下层通信。

注意:Framework层的服务都是单例的,运行在system_server进程里。如果这个进程挂了,整个系统就会重启——也就是我们常说的「软重启」。我曾经手贱改错了AMS代码,导致手机无限重启,最后只能刷机。

1.4 应用层:用户看到的世界

应用层就是用户直接接触的部分。电话、短信、浏览器、微信、抖音……所有你能看到的App都属于这一层。

应用层通过Binder IPC机制跟Framework层通信。Binder是Android特有的进程间通信方式,效率比Linux传统的Socket高得多。

举个例子,一个App想打开摄像头:

  1. App调用Camera.open()
  2. Framework的CameraService收到请求
  3. CameraService通过JNI调用HAL层
  4. HAL层调用内核驱动
  5. 驱动操作硬件

整个过程看起来很长,但实际上毫秒级就能完成。我优化过相机启动速度,从点击图标到预览画面出现,目标控制在500ms以内。这中间每一层都得优化——HAL层的初始化、Framework层的服务调度、内核驱动的响应速度。

1.5 各层交互方式总结

说了这么多,我给大家总结一下各层的交互方式:

  • 应用层 ↔ Framework层:Binder IPC(跨进程通信)
  • Framework层 ↔ HAL层:JNI + HAL接口(跨语言调用)
  • HAL层 ↔ 内核层:系统调用(open/ioctl/read/write)
  • 内核层 ↔ 硬件:驱动直接操作寄存器

你想想看,这个架构设计得其实很巧妙。每一层都只依赖下一层提供的接口,不关心具体实现。这样带来的好处是:

  • 可移植性:换硬件只需要改HAL层和驱动
  • 可维护性:每层可以独立升级
  • 安全性:应用层不能直接访问硬件,必须通过系统服务

一句话总结:Android的四层架构,说白了就是「分层解耦、各司其职」。内核管硬件,HAL做翻译,Framework提供服务,应用层负责展示。每一层都不可或缺,每一层都有它的设计哲学。

好了,第一章的内容就到这里。下一章我会带大家深入Linux内核层,看看Android到底在内核里动了哪些手脚。到时候我会分享一些我在内核调试中遇到的奇葩问题——比如为什么手机休眠后唤不醒,为什么WiFi断流等等。

嗯,这些坑我都踩过,希望你能少走弯路。