Android系统知识梳理-2023
2023-06-22 10:11:25 1 举报
AI智能生成
梳理的Android 框架和机制内容,可以帮助开发、测试同学面试
作者其他创作
大纲/内容
Android系统框架
System Apps
Dialer
Email
Calendar
Camera
...
Java API Framework
Content Providers
View System
Managers
Activity
Location
Package
Notification
Resource
Telephony
Window
Native C/C++ Librayes
Webkit
OpenMAX AL
Libc
Media Framework
OpenGL ES
...
Android Runtime
ART
Core Libraryes
Hardware Abstraction Layer(HAL)
Audio
Bluetooth
Camera
Sensors
...
Linux Kernel
Drivers
Audio
Binder(IPC)
Display
Keypad
Bluetooth
Camera
Shared Memory
USB
WIFI
Power Management
Android操作系统框架(从下往上)
Loader层
Boot ROM: 当手机处于关机状态时,长按Power键开机,引导芯片开始从固化在ROM里的预设代码开始执行,然后加载引导程序到RAM;
Boot Loader:这是启动Android系统之前的引导程序,主要是检查RAM,初始化硬件参数等功能。
Linux内核层
Android平台的基础是Linux内核,比如ART虚拟机最终调用底层Linux内核来执行功能。
启动Kernel的swapper进程(pid=0):
该进程又称为idle进程, 系统初始化过程Kernel由无到有开创的第一个进程, 用于初始化进程管理、内存管理,加载Display,Camera Driver,Binder Driver等相关工作;
启动kthreadd进程(pid=2)
是Linux系统的内核进程,会创建内核工作线程kworkder,软中断线程ksoftirqd,thermal等内核守护进程。kthreadd进程是所有内核进程的鼻祖。
硬件抽象层(HAL)
硬件抽象层 (HAL) 提供标准接口,HAL包含多个库模块,其中每个模块都为特定类型的硬件组件实现一组接口
比如WIFI/蓝牙模块,当框架API请求访问设备硬件时,Android系统将为该硬件加载相应的库模块
Android Runtime & 系统库
每个应用都在其自己的进程中运行,都有自己的虚拟机实例
ART主要功能包括:预先(AOT)和即时(JIT)编译,优化的垃圾回收(GC),以及调试相关的支持。
RT通过执行DEX文件可在设备运行多个虚拟机,DEX文件是一种专为Android设计的字节码格式文件,经过优化,使用内存很少
这里的Native C++系统库主要包括init孵化来的用户空间的守护进程、HAL层以及开机动画等
启动init进程(pid=1),是Linux系统的用户进程,init进程是所有用户进程的鼻祖
init进程会孵化出ueventd、logd、healthd、installd、adbd、lmkd等用户守护进程
init进程还启动servicemanager(binder服务管家)、bootanim(开机动画)等重要服务
init进程孵化出Zygote进程,Zygote进程是Android系统的第一个Java进程(即虚拟机进程)
Zygote是所有Java进程的父进程,Zygote进程本身是由init进程孵化而来的(由init进程通过解析init.rc文件后fork生成)
Framework层
System Server进程,是由Zygote进程fork而来,System Server是Zygote孵化的第一个进程
System Server负责启动和管理整个Java framework,包含ActivityManager,WindowManager,PackageManager,PowerManager等服务
Media Server进程,是由init进程fork而来,负责启动和管理整个C++ framework,包含AudioFlinger,Camera Service等服务。
App层
Zygote进程孵化出的第一个App进程是Launcher,这是用户看到的桌面App;
Zygote进程还会创建Browser,Phone,Email等App进程
所有的App进程都是由Zygote进程fork生成的
Syscall && JNI
Native与Kernel之间有一层系统调用(SysCall)层;
Java层与Native(C/C++)层之间的纽带JNI。
Context
Context 一般称呼其为上下文,它是对当前运行环境的一个描述,持有一些必要的资源和环境
ContextImpl 是 Context 的具体实现类
ContextWrapper 是一个典型的装饰器模式,也叫做修饰模式
这种方式通过组合和扩展装饰类,可以给不同的具体对象提供不同的功能扩展,而不需要增加 ContextImpl 的子类
ConstraintLayout
Fragment 生命周期
setUserVisibleHint():设置Fragment可见或者不可见时会调用此方法。在该方法里面可以通过调用getUserVisibleHint()获得Fragment的状态是可见还是不可见的,如果可见则进行懒加载操作。
onAttach():执行该方法时,Fragment与Activity已经完成绑定,该方法有一个Activity类型的参数,代表绑定的Activity,这时候你可以执行诸如mActivity = activity的操作。
onCreate():初始化Fragment。可通过参数savedInstanceState获取之前保存的值。
onCreateView():初始化Fragment的布局。加载布局和findViewById的操作通常在此函数内完成,但是不建议执行耗时的操作,比如读取数据库数据列表。
onActivityCreated():执行该方法时,与Fragment绑定的Activity的onCreate方法已经执行完成并返回,在该方法内可以进行与Activity交互的UI操作,所以在该方法之前Activity的onCreate方法并未执行完成,如果提前进行交互操作,会引发空指针异常。
onStart():执行该方法时,Fragment由不可见变为可见状态。
onResume():执行该方法时,Fragment处于活动状态,用户可与之交互。
onPause():执行该方法时,Fragment处于暂停状态,但依然可见,用户不能与之交互。
onSaveInstanceState():保存当前Fragment的状态。该方法会自动保存Fragment的状态,比如EditText键入的文本,即使Fragment被回收又重新创建,一样能恢复EditText之前键入的文本。
onStop():执行该方法时,Fragment完全不可见。
onDestroyView():销毁与Fragment有关的视图,但未与Activity解除绑定,依然可以通过onCreateView方法重新创建视图。通常在ViewPager+Fragment的方式下会调用此方法。
onDestroy():销毁Fragment。通常按Back键退出或者Fragment被回收时调用此方法。
onDetach():解除与Activity的绑定。在onDestroy方法之后调用。
序列化
把对象转换为字节序列的过程称为对象的序列化
把字节序列恢复为对象的过程称为对象的反序列化
java.io.ObjectOutputStream代表对象输出流
java.io.ObjectInputStream代表对象输入流
对象的序列化用途
把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;
在网络上传送对象的字节序列;
跨进程传输
Android逆向工程
常规做法
反编译
将Android平台上的可执行文件dex反编译java代码,修改后重新编译替换dex文件
动态调试
动态调试可以在运行时对应用程序进行调试
脱壳
脱壳可以去除应用程序的保护机制,使得应用程序可以被反编译或动态调试
分析恶意代码
分析恶意代码可以检测应用程序中的恶意代码
hook
在 Android 应用程序中,hook 是一种技术,用于修改或监视应用程序的行为
动态修改应用程序行为
监视应用程序的行为
实现插件化
分析应用程序的逻辑
子主题
规避措施
使用加密算法
可以使用加密算法对应用程序的关键数据进行加密,例如用户密码、账户信息等。
使用混淆工具
混淆工具可以将应用程序的代码混淆,使得逆向工程变得更加困难,例如使用 ProGuard 等。
禁止 root 权限
禁止应用程序获取 root 权限可以防止应用程序被恶意软件利用,例如使用 SELinux 等
使用签名证书
签名证书可以用于验证应用程序的真实性和完整性,可以防止应用程序被篡改或冒充。同时,应该定期更换签名证书,以提高安全性
Android端性能测试方案
FPS
首先,使用UI自动化框架来模拟用户操作
操作过程执行对应的命令,获取时间段内的FPS数据,取平均值
子主题
内存占用率
启动应用
adb shell am start -n com.xxx.xxx/.MainActivity
根据包名获取进程id
adb shell pidof com.xxx.xxx
启动UI自动化用例,根据进程id获取到对应的内存信息
adb shell dumpsys meminfo {pid}
CPU占用率
三种方式
1 top 获取cpu信息
2 adb shell dumpsys cpuinfo pid
3.通过读取/proc/pid/stat文件
硬存空间
根据包名获取数据
adb shell df /data/data/com.xxx.xxx
耗电量
1.通过adbshell dumpsys battery
2.基于Android提供的PowerManager.WakeLock来进行
3.功耗的计算=CPU消耗+Wakelock消耗+数据传输消耗+GPS消耗+Wi-Fi连接消耗
Android显示系统
三大组成部分
CPU
CPU负责计算帧数据,把计算好的数据交给GPU
GPU
GPU会对图形数据进行渲染,渲染好后放到buffer(图像缓冲区)里存起来
Display
Display(屏幕或显示器)负责把buffer里的数据呈现到屏幕上
Android-Window机制
WMS(WindowManagerService)继承于IWindowManager.Stub,是Binder的服务端
当一个应用程序创建一个新的 Activity 时,它会向 WMS 发送一个请求,并传递 Activity 的窗口和布局信息;
WMS 根据窗口和布局信息来创建 Activity 的窗口,并将其添加到屏幕上;
当用户与窗口进行交互时,WMS 会接收到相应的事件,并将其传递给对应的 Activity 进行处理;
当 Activity 被销毁时,WMS 会将其窗口和布局信息从屏幕上移除,并释放相关资源。
WindowManagerService 的启动
分析WMS的启动应该从SystemServer#main方法开始,在这个方法中,调用了startOtherServices方法去启动了一些系统服务,其中就包括WMS
WMS的启动过程涉及到3个线程: system_server主线程,android.display线程,android.ui线程
WindowManagerService是一个系统级服务,由SystemService启动,实现了IWindowManager.AIDL接口,运行在system_server进程。
startActivity 过程中 StartingWindow 的流程
StartingWindow是一个用于在Activity创建并初始化成功前显示的临时窗口,当Activity显示后会移除这个临时Window
Starting Window显示时机是AMS找到Activity信息后,创建activity前,在AMS线程中调用(Activity Manager Service)
AppWindowContainerController.addStartingWindow: 控制是否添加
AppWindowContainerController.scheduleAddStartingWindow: 把添加流程放到android.anim线程中执行
StartingData.createStartingSurface: 根据不同类型使用不同的子类创建窗口
WMS: 完成addView的功能
Starting Window移除时机是activity显示第一帧或者activity异常退出等
AppWindowContainerController:removeStartingWindow: 把移除流程放到android.anim线程中执行
StartingSurface.remove: 根据不同类型使用不同的子类移除窗口
WMS: 完成removeView的功能
当从Window的角度看待Activity的启动过程时,可以看到以下流程:
在system_server进程中发送消息到android.anim线程来处理Starting Window逻辑;
在目标进程中,执行AT.handleLaunchActivity方法,会回调目标Activity的onCreate方法,同时初始化一些与Window相关的对象或服务端的Binder引用,然后通过setContentView方法创建一个DecorView对象;
在目标进程中,执行AT.handleResumeActivity方法,会回调目标Activity的onResume方法,然后调用目标Activity的makeVisible方法;
在makeVisible方法中,会调用WindowManagerImpl.addView方法绘制View,并通过Binder远程调用WMS添加Window。
Window内部机制
Window是所有视图的载体,如Activity,PopupWindow,StatusBarWindow,Dialog和Toast的视图,我们想要对Window进行添加和删除就要通过WindowManager来操作,而WindowManager就是通过Binder与WindowManagerService进行跨进程通信,把具体的实现工作交给WindowManagerService
Window在Android开发中是一个窗口的概念,每一个Activity都包含一个Window对象,而Window是一个抽象类,具体实现是PhoneWindow
Android view绘制原理
Android-SurfaceFlinger启动与绘图原理
首先会创建 SurfaceFlinger 对象,在构造器中创建了 DispSync 同步模型对象;
然后执行初始化 SurfaceFlinger 的逻辑:
注册监听,接收 HWC 的相关事件。
启动 APP 和 SF 的 EventThread 线程,用来管理基于 DispSync 创建的两个 DispSyncSource 延时源对象,分别是用于绘制(app–mEventThreadSource)和合成(SurfaceFlinger–mSfEventThreadSource)。启动了 EventThread 线程后,会一直阻塞在 waitForEventLocked 方法中(期间会根据需要设置监听器),直到接收到 Vsync 信号且至少有一个连接正在等待 Vsync 信号才会继续执行线程逻辑,即通知监听者;
通过 MessageQueue.setEventThread 方法创建了一个连接,并通过 Looper.addFd 方法监听 BitTube 数据。
创建 HWComposer 对象(通过 HAL 层的 HWComposer 硬件模块 或 软件模拟产生 Vsync 信号),现在的 Android 系统基本上都可以看成是通过硬件 HWComposer 产生 Vsync 信号,而不使用软件模拟,所以下面解析都只谈及硬件 HWComposer 的 Vsync 信号;
初始化非虚拟的显示屏
启动开机动画服务
最后执行 SurfaceFlinger.run 逻辑,该方法会在 SurfaceFlinger 主线程通过死循环执行 MessageQueue.waitMessage 方法等待消息的到来,其内部调用了 Looper.pollOnce 方法,该方法会从 Looper.addFd 方法监听的 BitTube 中读取数据,当有数据到来时执行对应的回调方法。
当硬件或软件模拟发出 Vsync 信号时
回调 SF 相关方法,SF 调用 DispSync 同步模型的方法处理 Vsync 信号(统计和计算模型的偏移和周期),并根据返回值判断是否使能/关闭 HWC Vsync 信号的发出。
DispSync 根据计算的偏移和周期计算下次 Vsync 信号发生时间,并通知监听者 Vsync 信号到达的事件,传递给 DispSyncSource 延时源,延时源通过 EventThread 来管理 Vsync 信号的收发。
EventThread 调用连接 Connection 对象向 BitTube 发送数据,触发 addFd 函数中设置的回调方法,回调方法进而调用 SF.onMessageReceived 函数,然后进行图像的合成等工作
另一方面,Choreographer 会通过上面创建的 APP 延时源 mEventThreadSource 对象及其对应的 EventThread 线程来监听同步模拟发出的 Vsync 信号,然后进行绘制(measure/layout/draw)操作。
Android-Choreographer原理
Choreographer: 使 CPU/GPU 的绘制是在 VSYNC 到来时开始。Choreographer 初始化时会创建一个表示对 Vsync 信号感兴趣的连接,当有绘制请求时通过 postCallback 方法请求下一次 Vsync 信号,当信号到来后才开始执行绘制任务。
只有当 App 注册监听下一个 Vsync 信号后才能接收到 Vsync 到来的回调。如果界面一直保持不变,那么 App 不会去接收每隔 16.6ms 一次的 Vsync 事件,但底层依旧会以这个频率来切换每一帧的画面(也是通过监听 Vsync 信号实现)。即当界面不变时屏幕也会固定每 16.6ms 刷新,但 CPU/GPU 不走绘制流程。
当 View 请求刷新时,这个任务并不会马上开始,而是需要等到下一个 Vsync 信号到来时才开始;measure/layout/draw 流程运行完后,界面也不会立刻刷新,而会等到下一个 VSync 信号到来时才进行缓存交换和显示。
造成丢帧主要有两个原因:一是遍历绘制 View 树以及计算屏幕数据超过了16.6ms;二是主线程一直在处理其他耗时消息,导致绘制任务迟迟不能开始(同步屏障不能完全解决这个问题)。
可通过Choreographer.getInstance().postFrameCallback()来监听帧率情况。
Binder-进程间通信机制
Binder 是 Android 系统中的一种轻量级进程间通信机制,它可以实现进程之间的数据共享和协作。与传统 IPC 机制相比,Binder 具有以下优点:
高效性:Binder 的通信速度比传统 IPC 机制更快,因为它使用了内核中的共享内存和缓存技术,可以避免数据的复制和传输,从而提高了通信效率。
安全性:Binder 可以提供基于权限的访问控制机制,以确保通信双方的身份和数据的安全性。
灵活性:Binder 可以实现多进程间的数据共享和协作,可以让不同进程之间的代码可以互相调用,实现了更灵活的应用程序设计和开发。
进程和线程
Process
进程(Process)是操作系统中的一个独立的执行单元,它可以包含多个线程和资源。每个进程都有自己独立的内存空间和系统资源,不同的进程之间相互独立,彼此之间不能直接访问和共享资源。Android 系统中每个应用程序都在自己的进程中运行,并且每个进程都有一个唯一的进程 ID(PID)。
进程的主要作用是实现多任务和资源的隔离,可以让不同的应用程序同时运行,避免相互之间的干扰和影响。同时,进程还可以实现数据的存储和共享,可以让不同的应用程序之间共享数据和通信。
Thread
线程(Thread)是进程中的一个执行单元,它可以与其它线程共享进程的资源和内存空间。一个进程可以包含多个线程,不同的线程之间可以并发执行,相互之间可以通过共享内存来进行通信。在 Android 系统中,每个应用程序都至少包含一个主线程(也称为 UI 线程),负责处理用户界面的操作和响应。
线程的主要作用是实现并发处理和异步操作,可以让应用程序在执行耗时任务时不会阻塞用户界面,从而提高应用程序的响应速度和用户体验。同时,线程还可以实现并发数据访问和通信,可以让不同的线程之间共享数据和资源。
在 Android 系统中,进程和线程之间可以通过共享内存和消息传递来进行通信和共享数据
锁机制
锁机制是一种常见的进程和线程访问控制和同步的方式,它可以保证共享资源的互斥和同步。在 Android 系统中,常见的锁包括互斥锁(Mutex)、读写锁(ReadWriteLock)和信号量(Semaphore)等
锁机制的主要优点是实现简单,可以确保共享资源的安全性和一致性。缺点是可能会导致死锁和性能问题,因此需要进行合理的设计和使用。
原子操作
原子操作是一种特殊的操作方式,它可以保证操作的原子性和同步性,即在并发情况下,保证操作的完整性和一致性。在 Android 系统中,常见的原子操作包括原子变量、原子更新器和原子数组等。
原子操作的主要优点是操作简单,可以保证操作的原子性和可靠性。缺点是只能进行简单的操作,比如加减乘除和赋值等,不能进行复杂的操作
消息队列
消息队列是一种常见的线程之间通信和同步的方式,它可以通过消息队列来保证消息的顺序和可靠性。在 Android 系统中,消息队列常见的实现方式包括 Handler、Messenger 和 Event Bus 等。
消息队列的主要优点是通信可靠性高,可以保证消息的顺序和可靠性。缺点是通信效率相对较低,因为需要进行消息的封装、传输和解析等操作
0 条评论
下一页