Android init 进程启动分析

前言

Android 系统启动后,内核会创建 0 号内核进程 idle 进程,然后 idle 进程通过调用 kernel_thread 函数,以 kernel_init 函数作为参数,通过回调 kernel_init 函数执行可执行文件 /init 创建 Android 系统中的第一个用户级别的进程 init 进程,init 进程的 pid = 1,它是所有用户空间进程的始祖,init 进程会通过 fork 分裂出 servicemanager(Binder 服务管理服务)、zygote(Android 系统中第一个 Java 进程)以及 surfaceflinger(图形服务)等系统核心服务进程,理解 init 进程的启动过程以及所做的工作将为理解整个 Android 系统运行机制打下基础。

1
2
3
// kernel 3.18 - init/main.c

kernel_thread(kernel_init, NULL, CLONE_FS);
阅读更多

Android 应用进程 ServiceManager 的实现

实现一个普通应用进程中的 ServiceManager,可自由注册和获取 Binder 服务。

文末给出开源仓库地址。

Binder 相关基础可参考:android-binder-设计分析

实名 Binder 与匿名 Binder

实名 Binder

在 Binder 通信模型中,存在一个 ServiceManager 的角色,它作为 Android 系统的服务总管,负责建立 Binder 名字和 Binder 实体的映射。

提示:ServiceManager 中的 Service 和 android.app.Service 组件不是同一个概念。

阅读更多

好用的 Android 日志工具

简介

分享一个 Android 日志工具(Java 层),几乎我的每个项目都会用到,自认为非常好用,这里描述一下它的设计和实现。

它有如下几个特点:

  1. 简单,仅由一个 100 余行的 Java 类实现,猴子都能看懂 ^_^;
  2. 额外可选日志内容,提供线程名信息和调用栈,提供当前日志打印所在类以及所在代码行数;
  3. 方便,包含栈信息,直接用鼠标即可点击到日志打印所在行;
  4. 安全,保证日志字符串完全被优化掉,而不是留在代码中,下面会分析;
  5. 灵活,提供二次封装。

开源仓库地址在文末给出。

阅读更多

Android JNI 指南

前言

编写此文档的用意:

作为 Android NDK 项目开发的参考手册。

对于 NDK 工程的搭建可参考 Android NDK 指南

JNI 简介

JNI(Java Native Interface,Java 原生接口),是 Java 和 C++ 组件用以互相通信的接口。

Android 平台下的 JNI 支持由 Android NDK 提供,它是一套能将 C 或 C++(原生代码)嵌入到 Android 应用中的工具。

为什么要使用 JNI 在 Android 平台下进行编程:

  1. 在平台之间移植应用;
  2. 重复使用现有库,或者提供自己的库供重复使用;
  3. 在某些情况下提供高性能,特别是像游戏这种计算密集型应用;
  4. 提供安全性保障,在二进制层面比字节码层面的逆向工作更加困难。
阅读更多

Android NDK 指南

前言

编写此文档的用意:

  1. 作为搭建基础 NDK 工程的教程;
  2. 作为入门 NDK 工程的参考手册。

NDK 工程构建

可采用三种方式进行 NDK 工程的构建:

  1. 基于 Make 的 ndk-build,这是传统的 ndk-build 构建方式,使用 Makefile 方式进行构建,简洁高效;
  2. CMake 是新型的构建方式,CMake 具有跨平台的特性,通过 CMake 生成 Makefile 后再进行构建,CMake 的配置文件可读性更高;
  3. 其他编译系统,通过引入其他编译系统可对编译过程进行定制,例如引入 obfuscator-llvm 对源码进行混淆和压缩,增强源代码安全性。

下面是每种构建方式的基础示例,使用 Android Studio 4.0 和 NDK 21 进行如下构建。

阅读更多

Android ClassLoader 简析

ClassLoader 加载机制

ClassLoader 是一个抽象类,它为 Java 虚拟机上运行的进程提供类加载的操作,它定义了类加载器的标准接口,具体加载类的逻辑,以及加载类的路径由其具体子类实现。

ClassLoader 对外提供一个 loadClass 方法,使用时调用此方法并传入符合 java 标准的全类名参数,将会返回一个 Class<?> 对象,通过查看 loadClass 方法的实现可以了解到类加载器的加载机制。

阅读更多

Xposed 框架的使用

Xposed 简介

Xposed 框架是 Android 平台上一个非常著名且强大的开源框架,使用它能够对系统进程内运行的方法进行 hook,所以可以用它来做一些系统层面的工作,它拥有无限可能的灵活性,目前市面上基于 Xposed 框架下开发 Xposed 子模块已经数不胜数了。

原理简析

Android 系统运行的核心和起点是 Zygote 进程,所有应用都是从它 fork 子进程产生的,当系统开始运行时由 init.rc 脚本启动, 使用 /system/bin/app_process 程序完成启动,它加载所需的类并调用初始化方法。

Xposed 框架将在这个地方发挥作用,当 Xposed 框架被安装时,一个被扩展的 app_process 程序将被复制到 /system/bin/ 中,这个扩展的 app_process 将向类的路径附加一个 jar 文件,并在某些位置调用其方法,可能是虚拟机创建之后,或者在 Zygote 进程的 main 方法之前。在这个方法里,我们可以在其上下文中做插桩。

阅读更多

Android 二进制 XML 文件解析

前言

Android SDK 在编译 Android 工程时,将会把诸如资源文件和清单文件之类的相关 XML 文件编译为特定的二进制格式,目的是为了压缩其容量以及优化其在运行时的解析效率。

将 XML 文件编译为二进制的 XML 文件是 Android 编译资源时的一个子步骤,Android 在完整的资源编译过程结束后将会生成一个 resources.arsc 文件,它是一个资源文件表,应用在运行时会将它映射在内存中,为了资源的查询和引用。编译 Xml 文件为生成 arsc 文件的一个子步骤,如果 Xml 文件中引用了资源,例如字符串资源,那么 Xml 文件中引用字符串的位置将会包含一个全局字串池的索引,通过索引在 arsc 文件中的全局字符串池中即可查询到引用的具体字符串。

有关 arsc 文件的结构和解析方法可参考:Android arsc 文件解析

阅读更多

Android arsc 文件解析

apk 文件结构

在使用 Android SDK 编译 Android 工程时,它会将工程的源代码和资源打包为一个 apk 文件,apk 文件实质为一个压缩包,一个未签名的 apk 文件典型结构如下:

1
2
3
4
5
6
7
apk file:
assets/ - assets 原始资源文件
lib/ - so 库文件
res/ - 资源文件
classes.dex - 编译后的代码
resources.arsc - 资源信息文件
AndroidManifest.xml - 二进制的清单文件

在 Android 项目的编译过程中,Java 代码将会被编译为 classes.dex 文件,JNI 代码被编译为 .so 文件存放在 lib 目录下,assets 目录和 res/raw 目录中文件的将不会发生变化,对于资源文件中 xml 形式的资源将会被编译为优化过的特定的二进制 xml 格式,而类似于图片这种本身为二进制的类型也不会发生变化,AndroidManifest.xml 清单文件被编译为优化过的二进制格式。

阅读更多