前言
你是否对于Android系统的各大进程例如Zygote、init、SystemServer进程,以及Android的关键服务AMS,ServiceManager服务的关系感到混乱?总是记了又忘,难以在大脑中形成一个完整的结构?本文通过几个简单的shell命令让你看到系统的运行情况,使你对系统中的进程线程有一个直观的感受,方便你后续再进一步的分析各大服务的源码。
Android重要进程一览
首先在terminal执行adb devices
命令确保你已经连接到一个虚拟机或者真机并在线了,然后再执行adb shell ps
命令即可看到当前设备的所有运行中的进程。下面表格仅列出了我们熟悉的一些进程。
USER | PID | PPID | NAME |
---|---|---|---|
root | 1 | 0 | init |
root | 151 | 1 | init |
root | 312 | 1 | Zygote64 |
system | 179 | 1 | servicemanager |
system | 180 | 1 | hwservicemanager |
system | 511 | 312 | system_server |
shell | 4149 | 1745 | ps |
- USER代表进程的当前用户。root是Linux内置的超级用户,而system则是Android系统用户。
- PID代表进程的ID。
- PPID代表父进程ID,即创建该进程的进程ID。这里可以很明显的看到,Linux创建了
init
进程,init进程又创建了Zygote64
、servicemanager
等进程,Zygote进程又创建了system_server
进程。
执行
adb shell
进入shell之后再执行ps
命令可能和看到的结果并不相同,那是因为使用的shell终端不同,此时使用ps -A
命令即可看到完整的。直接执行adb shell ps
命令使用的是电脑中的shell终端,而执行adb shell
进入的shell则是设备中的shell终端。
init进程下线程一览
执行adb shell ps -T 1
命令即可查看PID为1的进程下的所有线程。
USER | PID | TID | PPID | CMD |
---|---|---|---|---|
root | 1 | 1 | 0 | init |
root | 1 | 150 | 0 | init |
执行adb shell ps -T 151
命令即可查看PID为151的进程下的所有线程。
USER | PID | TID | PPID | CMD |
---|---|---|---|---|
root | 151 | 151 | 1 | init |
- PID代表进程的ID。
- TID代表线程ID。
- PPID代表父进程ID,即创建该进程的进程ID。
并不了解为何系统会有两个init进程、三个init线程,如果后续了解到会再补充。
Zygote64进程下线程一览
执行adb shell ps -T 312
命令即可查看PID为312的进程下的所有线程。所有的应用进程都是通过Zygote进程fork出来的子进程,所以他所有的线程都会在应用线程创建的时候就存在。
USER | PID | TID | PPID | CMD |
---|---|---|---|---|
root | 312 | 312 | 1 | main |
root | 312 | 7390 | 1 | Jit thread pool |
root | 312 | 7391 | 1 | HeapTaskDaemon |
root | 312 | 7392 | 1 | ReferenceQueueD |
root | 312 | 7393 | 1 | FinalizerDaemon |
root | 312 | 7394 | 1 | FinalizerWatchd |
main
即通常所说的主线程。Jit thread pool
不认识,暂时没在源码里查到HeapTaskDaemon
用于释放堆内存即通常说的GCReferenceQueueDaemon
负责软、弱、虚引用的对象的回收FinalizerDaemon
用来回调【即将被回收的对象】的finalize方法;FinalizerWatchdogDaemon
监视FinalizerDaemon线程,如果在回调【即将被回收的对象】的finalize方法时超过了100_0000_0000纳秒(即10秒),那么进程会被强行kill掉
ServiceManager进程下线程一览
执行adb shell ps -T 179
命令即可查看PID为179的进程下的所有线程。可以看到ServiceManager进程下仅有一个同名线程,说明ServiceManager线程专门用于Binder服务的管理。
USER | PID | TID | PPID | CMD |
---|---|---|---|---|
system | 179 | 179 | 1 | servicemanager |
SystemServer进程下线程一览
执行adb shell ps -T 511
命令即可查看PID为511的进程下的所有线程。SystemServer进程下有多达150个线程,这里仅列举出部分我们熟悉的线程。这里可以看到有:
- 1个
ActivityManagerService
线程,这是ActivityManagerService所使用的线程。 - 4个
ActivityManager
线程,暂时不知道干嘛的。 android.anim
主要工作:Choreographer运行在这个线程中,负责协调动画相关内容。android.anim.lf
主要工作:负责协调SurfaceAnimation动画相关内容。android.bg
所有线程共享的一个后台线程,本身并不包含处理任务的代码,具体的工作由Runnable或者Handler完成。TODO 具体工作内容还需进一步分析。android.display
线程,主要用于:- DisplayManagerService(display adapter,viewport ,event…)
- InputManagerService (keyboard , input device …)
- WindowManagerService 实例的创建
android.fg
一个共享前台线程,源代码为FgThread.java,主要用于:- AccountManagerService
- BatteryStatsService
- DreamManagerService
- MountService
- NetworkManagementService
- PackageManagerService
- usb相关(debug, device, portmanager)
- WindowManagerService(screenshotApplicationsInner)
android.io
线程,主要有用于:- BluetoothManagerService 相关操作
- MountService里的obb操作
- Tethering 网络共享(usb /wifi/mobile?)
- TvInputManagerService tv里channel session相关
android.ui
主要处理:- AMS UiHandler里show各种msg
- DisplayManagerService里的overlay相关msg
- PointerEventDispatcher inputevent相关
- VoiceInteractionManagerService Voice交互
- WindowManagerPolicy init操作
AsyncTask #1
是我们的AsyncTask所使用的线程。查看AsyncTask源码可知AsyncTask最多可同时启动20个线程,但空闲时只保留1个线程。当然不一定是保留编号为1的线程,所以#后面跟的编号并不一定是1。
WARNING:新版本谷歌已经将AsyncTask废弃并建议用户使用Concurrent并发包。Binder:511_1~Binder:511_20
SystemServer所使用的Binder线程池,9.0源码里SystemServer的Binder线程数量最多为31个。但小米手机里的有32个,暂时不清楚为什么……queued-work-looper
异步任务所使用的线程,最著名的使用方法是SharedPreference的Apply方法。
USER | PID | TID | PPID | CMD |
---|---|---|---|---|
system | 511 | 612 | 312 | AccountManagerS |
system | 511 | 556 | 312 | ActivityManager |
system | 511 | 557 | 312 | ActivityManager |
system | 511 | 558 | 312 | ActivityManager |
system | 511 | 559 | 312 | ActivityManager |
system | 511 | 1766 | 312 | AdbDebuggingMan |
system | 511 | 615 | 312 | AlarmManager |
system | 511 | 535 | 312 | android.anim |
system | 511 | 536 | 312 | android.anim.lf |
system | 511 | 543 | 312 | android.bg |
system | 511 | 534 | 312 | android.display |
system | 511 | 531 | 312 | android.fg |
system | 511 | 533 | 312 | android.io |
system | 511 | 532 | 312 | android.ui |
system | 511 | 583 | 312 | AsyncTask #1 |
system | 511 | 666 | 312 | AudioService |
system | 511 | 529 | 312 | Binder:511_1 |
…… | …… | …… | …… | …… |
system | 511 | 2266 | 312 | Binder:511_20 |
system | 511 | 616 | 312 | CameraService_p |
system | 511 | 564 | 312 | FileObserver |
system | 511 | 520 | 312 | HeapTaskDaemon |
system | 511 | 541 | 312 | HwBinder:511_1 |
…… | …… | …… | …… | …… |
system | 511 | 815 | 312 | HwBinder:511_5 |
system | 511 | 519 | 312 | Jit thread pool |
system | 511 | 585 | 312 | PackageInstalle |
system | 511 | 575 | 312 | PackageManager |
system | 511 | 577 | 312 | PackageManager |
system | 511 | 574 | 312 | PackageManagerB |
system | 511 | 3726 | 312 | queued-work-loo |
system | 511 | 696 | 312 | SyncManager |
system | 511 | 560 | 312 | Thread-2 |
system | 511 | 567 | 312 | Thread-3 |
system | 511 | 568 | 312 | Thread-4 |
system | 511 | 570 | 312 | Thread-5 |
system | 511 | 569 | 312 | Thread-6 |
system | 511 | 669 | 312 | Thread-10 |
system | 511 | 685 | 312 | Thread-11 |
system | 511 | 846 | 312 | Thread-13 |
部分资料来源:System server里创建常见的几个thread
附加题 Hello World应用进程创建后有多少个线程
可以看到除了从Zygote继承过来的6个线程之外,系统还为进程创建了Signal Catcher
、Profile Saver
、 RenderThread
以及3个Binder构成的线程池。
Signal Catcher
源代码在signal_catcher.cc,具体的启动方式是在runtime.cc的InitNonZygoteOrPostFork方法中启动的,参见SignalCatcher的线程启动。此进程主要功能:一是打印当前进程的堆栈(Java、Native、Kernel),同时把当前虚拟机的一些状态信息也打印出来,并保存在traces.txt文件中;二是进行进程的强制GC并保存GC的profile信息。Profile Saver
Profile收集线程,源代码在profile_saver.cc,用于更新app的profile文件,指导dex2oat如何将dex编译成oat文件。Android profile-guided dex2oatRenderThread
渲染线程,Android 5.0之后,Android应用程序的Open GL线程从主线程中独立出来,称为Render Thread。源代码在RenderThread.cpp,具体主线程和渲染线程的分工可以看Android Systrace 基础知识 - MainThread 和 RenderThread 解读。如果你在应用的Application标签下配置android:hardwareAccelerated="false"关闭默认开启的硬件加速则不会有此线程。
USER | PID | TID | PPID | CMD |
---|---|---|---|---|
u0_a169 | 6401 | 6401 | 291 | pty_application |
u0_a169 | 6401 | 6411 | 291 | Signal Catcher |
u0_a169 | 6401 | 6414 | 291 | Jit thread pool |
u0_a169 | 6401 | 6415 | 291 | HeapTaskDaemon |
u0_a169 | 6401 | 6416 | 291 | ReferenceQueueD |
u0_a169 | 6401 | 6417 | 291 | FinalizerDaemon |
u0_a169 | 6401 | 6418 | 291 | FinalizerWatchd |
u0_a169 | 6401 | 6419 | 291 | Binder:6401_1 |
u0_a169 | 6401 | 6420 | 291 | Binder:6401_2 |
u0_a169 | 6401 | 6421 | 291 | Binder:6401_3 |
u0_a169 | 6401 | 6423 | 291 | Profile Saver |
u0_a169 | 6401 | 6424 | 291 | RenderThread |
总结
此次研究仅是对Android系统内部的进程和线程有了一个初步的了解。相对于其他文章的源代码分析、调用链分析,直接的查看系统当前进程、线程运行情况能让初学者对线程和进程的关系、Android启动过程中进程的创建流程有一个更直观的了解。本文适合作为Android各大服务源代码分析的前置文章,仅供各位参考,文章中有任何讹误欢迎在评论区指出,感谢!