JasonWang's Blog

Android常用的性能分析工具

在Android系统开发过程中,经常碰到CPU占用率高、内存泄露、内存占用高等性能相关的问题,这时通常需要抓取系统的trace日志,用以查看进程的CPU占用,内存分配等情况。怎么抓取系统trace, 这时一般需要用到系统性能相关的分析工具。这篇文章就以Android S为例,说明Android开发中常用的一些性能优化工具的使用方法,主要包括如下几个工具:

Android中HAL服务无法使用网络的问题

最近有同学在Android S(12)上遇到了一个奇怪的网络问题,说自己的audio HAL服务尝试通过以太网创建socket与其他局域网的节点通讯时,总是提示Operation Not Permitted。原先怀疑是Selinux的问题,但是目前在开发版本中selinux是完全关闭的;从问题发生的现象看,只有属于audioserver这个UID的进程才有问题,其他的如system/root的进程则没有问题。

据此,我们可以推断,audioserver这个UID的进程没有相关权限,所以导致无法使用局域网的网络。记得在早前的Android版本中,很多网络系统调用会通过netd代理进行权限检查,比如socket/connect/bind等系统调用都会先通过netdClient这个库的接口进行权限检查,而后才真正进行系统调用。

如何用FFmpeg在Android上实现音视频解码

最近开发投屏功能,需要对H.264视频数据流进行解码,然后显示出来。Android原生的MediaCodec虽然使用了硬件解码,但是延迟较大(超过300ms),无法满足要求。于是研究了下如何基于FFMPEG来做视频流的软解码。这里对整个过程做简要的总结,看下如何在Android Studio中完成FFMPEG的视频解码:

  • 简单介绍下FFMPEG框架
  • 如何利用交叉编译生成所需要的FFMPEG共享库, 以及如何进行Android Studio的配置
  • FFMPEG解码H264的大致调用流程
理解Android eBPF

Android从9.0版本开始全面支持eBPF(extended Berkeley Packet Filters), 其主要用在流量统计上, 也可以用来监控CPU/IO/内存等模块的状态.简单来说, eBPF可以与内核的kprobe/tracepoints/skfilter等模块相结合, 将eBPF的函数hook到内核事件从而监控相应的系统状态.

Android为eBPF提供了许多封装的库, 并提供了eBPF加载器bpfloader:

  • bpfloader: 位于/system/bpf/bpfloader, 系统启动时负责加载位于/system/etc/bpf 中的eBPF目标文件
  • libbpf_android: 位于/system/bpf/libbpf_android提供创建bpf容器/加载bpf目标文件的接口
  • libbpf: 位于/external/bcc, 封装了bpf的系统调用, 提供如attach/dettach程序的接口
  • libnetdbpf: 位于/system/netd/libnetdbpf, 实现了netd流量统计功能的函数

目前在Android(Q)上有两处eBPF的代码: 一个是/system/netd/bpf_progs/netd.c, 主要是用于流量统计;一个是/system/bpfprogs/time_in_state.c用于监控CPU运行频率以及上下文切换的耗时.

接下来我们就从三个部分来深入理解下Android是如何利用eBPF的:

  • eBPF程序与目标文件格式
  • Android eBPF加载与执行流程
  • Android如何基于eBPF实现流量统计
从Wifi热点功能说一说Android Wifi框架

之前帮着解决了项目中WIFI相关的问题, 一直想梳理下WIFI的框架, 方便后续代码阅读以及问题的解决. 恰好年初修改了车机上WIFI热点相关的一些代码, 重新看了下Android 10(Q)的逻辑, 于是想通过WIFI热点相关的功能作为切入点, 完整的梳理下Android WIFI的整体框架.

先不多说, 看下Android WIFI的大致框架:

android wifi framwork

一个ADB无法识别设备的问题

这两天隔壁部门的同事反馈说新项目上, 车机(Android系统)上挂载的USB外设(一个可以上网的TBOX设备)无法通过ADB(Android Debug Bridge)进行连接. 心里有点纳闷, USB不都识别到了吗, 上次也把ADB相关的客户端都移植过去了, 为啥还会识别不到设备了? 只得从头开始理下ADB相关的代码与逻辑.先来看看ADB的基本原理.

ADB(全称Android Debug Bridge)是Android上用途十分广泛的调试工具, 可用于与开发设备进行连接;ADB命令既可以用来主机与设备之间传输文件, 也可以通过SHELL命令对设备进行操作. 如下所示, 是ADB的一个工作原理图:

How ADB works

Recovery模式如何支持ADB

这两天顺着recovery模式下一个网络需求, 为了便于调试又在recovery下做了ADB功能. 在Android早期的如4.4版本, recovery模式下支持ADB配置起来比较简单(支持adb devices/adb reboot/adb pull/push等常用指令), 但在Android 9.0下USB辅助设备一般都通过configfs的方式来配置了, 因此相对来说要适配的东西就多一些, 如果额外要适配adb shell命令, 则要修改adbd的源代码了.这篇文章就来看看如何在Recovery模式下解决这几个问题.

在进入正题之前, 先了解下USB相关的基础知识.

USB全称是Universal Serial Bus, 是一种广泛用于主机与外设之间的连接的串行总线.USB设备使用的是一种层级的结构, 最多可支持多达127个设备, 每个USB设备对应一个功能(function), 比如USB打印机提供了打印服务; 存储设备则提供了存储数据的功能.

USB system architecture

SELinux在Android中的应用

SELinux(Security Enhanced Linux)是Linux下的安全控制机制, 为进程访问系统资源提供了访问控制(access control)策略. 早期, Linux基于用户身份/用户组的DAC(Discretionary Access Control作为访问控制策略: 每个进程都有所属的UID, 每个文件都有所属的UID/GID以及文件模式(读写执行等), 一个进程是否可以访问某个文件就是基于UID/GID/文件模式来管理的.换句话说,只要某个资源序属于该用于或该用户组, 则该用户对该资源具有绝对控制权力, 这样一旦用户获得了root权限, 那么整个系统就成了肉鸡. 可见, DAC的安全控制策略比较粗放.

SELinux最初是由美国Utah大学与NSA(National Security Agency)的安全小组研究出来的安全框架FLASK演变而来, 后被合入到Linux 2.6版本.相较于DAC, SELinux采用的是更细粒度的MAC(Mandatory Access Control).对于DAC而言, 资源的权限是由每个用户自己控制的, 而MAC则将所有的权限收拢, 由一个统一的管理者(SELinux)统一来分配所有的资源权限, 如果访问者没有事先分配到某个资源的权限, 则不会允许访问.这样即使是root用户也要收到安全策略的约束. Android在4.3开始引入SELinux, 到了5.0版本之后, 则开始全面支持了.

Android netd工作原理详解

NETD是Android一个专门管理网络链接, 路由/带宽/防火墙策略以及iptables的系统Daemon进程, 其在Anroid系统启动时加载:

1
2
3
4
5
6
7
8

service netd /system/bin/netd
class main
socket netd stream 0660 root system
socket dnsproxyd stream 0660 root inet
socket mdns stream 0660 root system
socket fwmarkd stream 0660 root inet

Android进程Crash处理流程

之前的一篇文章,讲到了应用程序无响应(ANR)时Android的处理逻辑。这篇文章,就来分析下应用进程发生崩溃(Crash)时,Android是如何处理的?总的说来,Android主要有两大类Crash:

  • Java(JVM)层: 应用程序发生运行时错误(如空指针,浮点运算错误,数据索引超出界限)或者系统进程崩溃(长时间无响应);
  • Native层: native进程或者kernel发生运行时错误;