在讲解 Zygote 之前,考虑到不同的系统版本源码都不相同,以下分析的源码基于 Android 8.0.0。
当系统启动时,init 进程是继 Linux 内核启动后第二个启动的进程,它是在用户空间被创建的进程,可以通过命令 adb shell ps 查看 init 进程的 pid:
上图中 PID 是当前进程的 id,PPID 是父进程的 id,并且 Linux 的进程 PID 是按启动顺序从前往后排序。
init 进程在上图中的 pid=1,而 Linux 内核的 pid=0,这也是验证了 init 进程是继 Linux 内核启动后启动的下一个进程。
init 进程主要有两个作用:
启动系统关键的服务
守护关键服务,如果其中一个关键服务被杀死,将会重启手机
怎样的服务属于关键服务?关键服务是对于手机而言必不可少的服务,比如网络服务、蓝牙服务、铃声服务等,同样可以通过 adb shell ps 查看 ppid=1 的其他服务,就是由 init 进程启动守护的关键服务:
上图中例如 installd、servicemanager、surfaceflinger 等 ppid=1 的都是由 init 进程启动的关键服务。
所以 如果要实现一个系统服务又不想被杀死,最好的方式就是让服务由 init 进程启动成为关键服务。
init 进程也是一段可执行的程序,所以也有对应的相关代码。init.c 代码具体是在 Android 源码目录 /system/core/init/init.cpp。
而我们常说的 init.rc,你可以理解为它是 init 进程要执行的任务清单,其实就是一个执行脚本:
import /init.environ.rc
import /init.usb.rc
import /init.${ro.hardware}.rc
import /init.usb.configfs.rc
import /init.${ro.zygote}.rc // 启动 zygote 的执行脚本
...
可以看到 init.rc 任务清单中其实也是导入的其他待执行的任务清单的文件路径,其中就有启动 zygote 的执行脚本,ro.zygote 会根据系统类型获取对应的执行脚本文件,例如 32 位获取的就是 init.zygote32.rc,64 位获取的就是 init.zygote64.rc:
system/core/rootdir/init.zygote32.rc
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
priority -20
user root
group root readproc
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
onrestart restart wificond
writepid /dev/cpuset/foreground/tasks
第一行脚本信息记录的要执行的程序入口位置,会先执行 /system/bin/app_process 下的 app_main.c,-Xzygote /system/bin --zygote --start-system-server 是入口程序传入的参数。
上面提到,init.rc 是一段执行脚本,其中就有启动 Zygote 进程的执行文件 init.zygote32.rc 或 init.zygote64.rc,该文件会执行 /frameworks/base/cmds/app_process/app_main.c 的 main() 函数启动 Zygote:
/frameworks/base/cmds/app_process/app_main.c
#if defined(__LP64__)
static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist64";
static const char ZYGOTE_NICE_NAME[] = "zygote64";
#else
static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist32";
static const char ZYGOTE_NICE_NAME[] = "zygote";
#endif
// argv 就是脚本传入的参数 -Xzygote /system/bin --zygote --start-system-server
int main(int argc, char* const argv[]) {
...
while (i < argc) {
const char* arg = argv[i++];
if (strcmp(arg, "--zygote") == 0) {
zygote = true;
niceName = ZYGOTE_NICE_NAME;
} else if (strcmp(arg, "--start-system-server") == 0) {
startSystemServer = true;
}
...
}
...
for (; i < argc; ++i) {
args.add(String8(argv[i]));
}
// 将 app_process 修改为 zygote
if (!niceName.isEmpty()) {
runtime.setArgv0(niceName.string(), true /* setProcName */);
}
if (zygote) {
// 在 system/core/rootdir/init.zygote32.rc(或 init.zygote.64.rc) 解析到参数 --zygote,所以 zygote == true,通过 runtime.start() 创建 Zygote 进程
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
}
...
}
上面的代码 将 app_process 修改为了 Zygote,所以 Zygote 一开始并不是这个名称,而是在启动时才被修改为 Zygote。
Zygote 虽然是在 Framework native 层由 C 语言的 main() 入口执行创建的,因为 init 进程是在用户空间,init 进程创建了 Zygote,所以 Zygote 是在用户空间。
我们接着看 runtime.start() 做了什么事情:
/frameworks/base/core/jni/AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector& options, bool zygote)
{
...
// 创建虚拟机,startVm() 有很多虚拟机的参数配置,比如内存大小
// 内存调优和其他虚拟机的调优就是在这个函数处理
/* start the virtual machine */
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
if (startVm(&mJavaVM, &env, zygote) != 0) {
return;
}
onVmCreated(env);
// 动态注册 java 调用 native 的 jni
// 我们在写 java 代码时能声明 native 方法调用 C/C++ 函数,就是因为在这里做了注册处理了映射关系
/*
* Register android functions.
*/
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
...
// 调用 com.android.internal.os.ZygoteInit 的 main 方法
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
if (startMeth == NULL) {
ALOGE("JavaVM unable to find main() in '%s'\n", className);
} else {
env->CallStaticVoidMethod(startClass, startMeth, strArray);
}
...
}
runtime.start() 主要做了三件事情:
startVm() 创建虚拟机
startReg() 动态注册 java 调用 native 的 jni
反射调用 ZygoteInit 的 main()
通过 startVm() 创建虚拟机,startVm() 有很多虚拟机的参数配置,比如堆内存大小,如果是系统工程师,内存调优和其他虚拟机的调优就是在这个函数处理。
startReg() 动态注册 java 调用 native 的 jni,我们在写 java 代码时能声明 native 方法调用 C/C++ 函数,就是因为在这里做了注册处理了映射关系。以 MessageQueue 为例子:
// 在 startReg() 动态注册,将 java 和 C/C++ 的函数关联
static const JNINativeMethod gMessageQueueMethods[] = {
{."nativeInit", "()J", (void*)android_os_MessageQueue_nativeInit },
...
};
int register_android_os_MessageQueue(JNIEnv* env) {
...
}
最终就是调用 ZygoteInit 的 main() 方法,到这里就开始进入 java 的世界。
我们简单总结下 Zygote 在 native 的处理流程,如下图:
在 native 创建了 Zygote,并且通过 AndroidRuntime.start() 从 native 层转到 java 层 ZygoteInit 的 main() 入口继续处理 Zygote 相关流程:
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
// argv 就是 init.{ro.zygote}.rc 脚本写的参数
// -Xzygote /system/bin --zygote --start-system-server
public static void main(String argv[]) {
// 创建 ServerSocket
ZygoteServer zygoteServer = new ZygoteServer();
...
boolean startSystemServer = false;
String socketName = "zygote";
String abiList = null;
boolean enableLazyPreload = false;
for (int i = 1; i < argv.length; i++) {
if ("start-system-server".equals(argv[i])) {
startSystemServer = true;
} else if ("--enable-lazy-preload".equals(argv[i])) {
enableLazyPreload = true;
} else if (argv[i].startsWith(ABI_LIST_ARG)) {
abiList = argv[i].substring(ABI_LIST_ARG.length());
} else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
socketName = argv[i].substring(SOCKET_NAME_ARG.length());
} else {
throw new RuntimeException("Unknown command line argument: " + argv[i]);
}
...
}
zygoteServer.registerServerSocket(socketName);
...
// 加载系统类、系统资源等
if (!enableLazyPreload) {
...
preload(bootTimingsTraceLog);
...
}
...
// 创建 SystemServer
if (startSystemServer) {
startSystemServer(abiList, socketName, zygoteServer);
}
// ZygoteServer 创建 ServerSocket 作为服务器
// 开启循环,等待接收 socket 通信 fork app 进程的请求
// 没有消息会一直阻塞休眠等待,Zygote 进程会一直存活运行
zygoteServer.runSelectLoop(abiList);
zygoteServer.closeServerSocket();
...
}
在 ZygoteInit 的 main() 入口方法主要做了三件事情:
我们先看下预先加载资源 preload() 做了什么事情:
static void preload(TimingsTraceLog bootTimingsTraceLog) {
...
// 系统类加载
preloadClasses();
...
// 系统资源加载
preloadResources();
...
// openGL加载
preloadOpenGL();
...
// 系统共享库加载
preloadSharedLibraries();
// 文字资源加载
preloadTextResources();
...
}
private static final String PRELOADED_CLASSES = "/system/etc/preloaded-classes";
private static void preloadClasses() {
...
InputStream is;
try {
// 获取要加载的系统资源文件流
is = new FileInputStream(PRELOADED_CLASSES);
} catch (FileNotFoundException e) {
Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");
return;
}
...
BufferedReader br
= new BufferedReader(new InputStreamReader(is), 256);
int count = 0;
String line;
while ((line = br.readLine()) != null) {
...
try {
// 读取 /system/etc/preloaded-classes 的类路径并加载
Class.forName(line, true, null);
}
...
}
...
}
public static final boolean PRELOAD_RESOURCES = true;
private static void preloadResources() {
...
mResources = Resources.getSystem();
mResources.startPreloading();
if (PRELOAD_RESOURCES) {
TypedArray ar = mResources.obtainTypedArray(
com.android.internal.R.array.preloaded_drawables);
int N = preloadDrawables(ar);
ar.recycle();
ar = mResources.obtainTypedArray(
com.android.internal.R.array.preloaded_color_state_lists);
N = preloadColorStateLists(ar);
ar.recycle();
...
}
mResources.finishPreloading();
}
preload() 主要是预先加载了系统类、系统资源、系统共享库、openGL、文字资源等,其中系统类是读取的 preloaded-classes。因为系统类较多,下面只截取了文件的一部分,具体可以在源码查看该文件:
frameworks/base/preloaded-classes
...
android.app.Activity
android.app.Activity$HostCallbacks
android.app.ActivityManager
android.app.ActivityManager$1
android.app.ActivityManager$RecentTaskInfo
android.app.ActivityManager$RecentTaskInfo$1
android.app.ActivityManager$RunningAppProcessInfo
android.app.ActivityManager$RunningAppProcessInfo$1
android.app.ActivityManager$RunningServiceInfo
android.app.ActivityManager$RunningServiceInfo$1
android.app.ActivityManager$RunningTaskInfo
android.app.ActivityManager$RunningTaskInfo$1
android.app.ActivityManager$StackId
android.app.ActivityManager$TaskDescription
android.app.ActivityManager$TaskDescription$1
android.app.ActivityOptions
android.app.ActivityThread
android.app.ActivityThread$1
android.app.ActivityThread$2
android.app.ActivityThread$ActivityClientRecord
android.app.ActivityThread$ActivityConfigChangeData
android.app.ActivityThread$AppBindData
android.app.ActivityThread$ApplicationThread
android.app.ActivityThread$BindServiceData
android.app.ActivityThread$ContextCleanupInfo
android.app.ActivityThread$CreateServiceData
android.app.ActivityThread$DropBoxReporter
android.app.ActivityThread$EventLoggingReporter
android.app.ActivityThread$GcIdler
android.app.ActivityThread$H
...
可以发现这些全类名路径就是我们在 app 开发中使用的四大组件 Activity、Fragment、常用控件 TextView 等。
所以我们 app 运行的时候,字体库、资源、系统类就是从这里来的,因为 Zygote 启动时已经提前预先加载好了。
在 Zygote 预先加载这些资源的好处是,不需要每个 app 都去加载这些资源,而是使用提前预先加载好的这些类和资源,可以直接使用。
需要注意的是,因为 preoload() 是在主进程调用的,而且会比较耗时,如果要对系统启动速度做优化,也可以从这个方法入手。
首先我们要明白,什么是 fork?fork 可以理解为就是复制,所以 Zygote fork 进程其实就是在 Zygote 基础上复制一个进程作为子进程,子进程拥有 Zygote 已经处理好的资源。
Zygote 其中的一个职责是负责 fork 子进程的创建,比如要接收 AMS 通过 socket 通信告知创建 app 进程,此时 AMS 是客户端,Zygote 作为服务端要接收 socket 消息,就需要创建 ServerSocket 服务器循环等待。
class ZygoteServer {
private LocalServerSocket mServerSocket;
void registerServerSocket(String socketName) {
if (mServerSocket == null) {
...
try {
FileDescriptor fd = new FileDescriptor();
fd.setInt$(fileDesc);
// 创建 ServerSocket
mServerSocket = new LocalServerSocket(fd);
} catch (IOException ex) {
...
}
}
}
void runSelectLoop(String abiList) throws Zygote.MethodAndArgsCaller {
...
// 循环等待 socket 消息通知 fork 进程
while (true) {
...
try {
// 没有消息休眠等待
Os.poll(pollFds, -1);
} catch (ErrnoException ex) {
...
}
for (int i = pollFds.length - 1; i >= 0; --i) {
...
boolean done = peers.get(i).runOnce(this);
...
}
}
}
}
ZygoteConnection.java
boolean runOnce(ZygoteServer zygoteServer) throws Zygote.MethodAndArgsCaller {
...
// fork 子进程
pid = Zygote.forkAndSpecialize(...);
...
}
Zygote.java
public static int forkAndSpecialize(...) {
...
int pid = nativeForkAndSpecialize(...);
...
return pid;
}
native private static int nativeForkAndSpecialize(...);
frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(...) {
...
return ForkAndSpecializeCommon(...);
}
static pid_t ForkAndSpecializeCommon(...) {
...
// 调用 Linux 的 fork() 创建进程
pid_t pid = fork();
...
}
通过源码可以分析到,ZygoteServer 其实就是创建了一个 ServerSocket,在 ZygoteInit 调用 runSelectLoop() 作为服务端等待客户端 socket 通信告知 fork 进程,fork 进程是转到 native 层最终调用 Linux 标准函数 fork()。
在 ZygoteInit 会创建 SystemServer 进程,SystemServer 是 Zygote 创建的第一个子进程:
ZygoteInit.java
private static boolean startSystemServer(...) {
...
pid = Zygote.forkSystemServer(...);
...
return true;
}
关于如何 fork 在上一小节已经介绍,forkSystemServer() 只是创建了 SystemServer 进程,那么 SystemServer 是什么时候运行的呢?接着往下分析源码:
ZygoteInit.java
private static boolean startSystemServer(...) {
...
pid = Zygote.forkSystemServer(...);
...
if (pid == 0) {
...
handleSystemServerProcess(parsedArgs);
}
return true;
}
private static void handleSystemServerProcess(...) {
...
ZygoteInit.zygoteInit(...);
}
public static final void zygoteInit(...) {
...
// 初始化运行环境
RuntimeInit.commonInit();
// 打开 Binder 驱动,初始化 Binder
ZygoteInit.nativeZygoteInit();
// 反射调用 main() 入口函数
RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}
RuntimeInit.java
protected static void applicationInit(...) {
...
// Remaining arguments are passed to the start class's static main
invokeStaticMain(args.startClass, args.startArgs, classLoader);
}
private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader) throws Zygote.MethodAndArgsCaller {
Class> cl;
try {
cl = Class.forName(className, true, classLoader);
} catch (ClassNotFoundException ex) {
...
}
Method m;
try {
// 反射调用 main() 方法
m = cl.getMethod("main", new Class[] { String[].class });
} catch (NoSuchMethodException ex) {
...
}
...
}
SystemServer 进程的创建最终是通过反射 main() 函数执行。
SystemServer 是干嘛用的?继续分析 SystemServer 的源码。
SystemServer.java
public static void main(String[] args) {
new SystemServer().run();
}
private void run() {
...
// system_server 进程启动服务管理类
mSystemServiceManager = new SystemServiceManager(mSystemContext);
try {
// 启动引导服务
startBootstrapServices();
// 启动核心服务
startCoreServices();
// 启动其他服务
startOtherServices();
...
}
...
}
private void startBootstrapServices() {
...
// 启动 AMS 服务,在高版本是 ATMS
mActivityManagerService = mSystemServiceManager.startService(
ActivityManagerService.Lifecycle.class).getService();
mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
mActivityManagerService.setInstaller(installer);
...
// 启动 PMS
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
mFirstBoot = mPackageManagerService.isFirstBoot();
mPackageManager = mSystemContext.getPackageManager();
...
}
private void startCoreServices() {
// 为了能让 SystemServiceManager 统一的方式管理服务,通过 SystemService 代理这些服务
mSystemServiceManager.startService(DropBoxManagerService.class);
mSystemServiceManager.startService(BatteryService.class);
mSystemServiceManager.startService(UsageStatsService.class);
mActivityManagerService.setUsageStatsManager(
LocalServices.getService(UsageStatsManagerInternal.class));
mWebViewUpdateService = mSystemServiceManager.startService(WebViewUpdateService.class);
}
private void startOtherServices() {
...
// 各种系统信息的管理,例如字体、系统设置、开发者选项等
mActivityManagerService.installSystemProviders();
...
}
SystemServer 其实是启动引导服务、核心服务和其他服务的入口,可以发现这些服务并不是通过 Zygote fork,而是直接 new 创建出来的,所以 这些服务都在 system_server 进程。
因为启动的服务较多,所以 SystemServer 创建了 SystemServiceManager 管理这些服务。
为了能统一的方式处理,这些服务通过 SystemService 代理的方式提供给 SystemServiceManager 管理。
在应用层各个进程都需要用到这些服务,那么这些进程是怎么获取到这些服务的?
我们以电量服务 BatteryService 举例:
public abstract class SystemService {
...
public abstract void onStart();
...
protected final void publishBinderService(String name, IBinder service,
boolean allowIsolated, int dumpPriority) {
// 将服务注册到 ServiceManager
ServiceManager.addService(name, service, allowIsolated, dumpPriority);
}
}
// 服务通过 SystemService 代理
public final class BatteryService extends SystemService {
@Override
public void onStart() {
...
// 注册服务到 ServiceManager
mBinderService = new BinderService();
publishBinderService("battery", mBinderService);
...
}
}
public final class SystemServer {
private void startCoreServices() {
...
mSystemServiceManager.startService(BatteryService.class);
...
}
}
public class SystemServiceManager {
@SuppressWarnings("unchecked")
public T startService(Class serviceClass) {
try {
final String name = serviceClass.getName();
...
final T service;
try {
Constructor constructor = serviceClass.getConstructor(Context.class);
service = constructor.newInstance(mContext);
} catch (...) {
...
}
startService(service);
return service;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
}
public void startService(@NonNull final SystemService service) {
// Register it.
mServices.add(service);
// Start it.
long time = SystemClock.elapsedRealtime();
try {
service.onStart();
} catch (RuntimeException ex) {
throw new RuntimeException("Failed to start service " + service.getClass().getName()
+ ": onStart threw an exception", ex);
}
warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");
}
}
可以看到这些服务经过 SystemServiceManager 统一管理后,最终都会把服务注册到 ServiceManager,ServiceManager 记录着 key 为服务名称 value 为服务的 Binder 列表,应用层进程根据服务名称就可以很方便的拿到要通信的 Binder。
ServiceManager 是一个独立的进程,它和 Zygote 一样也是在 init.rc 脚本执行时启动的独立进程。
我们再简单梳理下 SystemServer 做了哪些事情:
创建 SystemServiceManager 用于统一管理服务
启动各种服务如 AMS、PMS 等
将启动的服务注册到 ServiceManager
SystemServer 流程图如下:
Zygote fork 子进程启动子进程时会初始化 Binder,比如打开 Binder 驱动,每个进程都有自己的 Binder,具体调用是在子进程的 main() 函数执行之前调用 nativeZygoteInit():
ZygoteInit.java
public static final void zygoteInit(...) {
...
// 创建 Binder
ZygoteInit.nativeZygoteInit();
...
}
private static final native void nativeZygoteInit();
frameworks/base/core/jni/AndroidRuntime.cpp
static void com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{
gCurRuntime->onZygoteInit();
}
int register_com_android_internal_os_ZygoteInit(JNIEnv* env)
{
const JNINativeMethod methods[] = {
{ "nativeZygoteInit", "()V",
(void*) com_android_internal_os_ZygoteInit_nativeZygoteInit },
};
return jniRegisterNativeMethods(env, "com/android/internal/os/ZygoteInit",
methods, NELEM(methods));
}
frameworks/base/cmds/app_process/app_main.cpp
virtual void onZygoteInit()
{
// 打开 Binder 驱动
sp proc = ProcessState::self();
ALOGV("App process: starting thread pool.\n");
// 启动 Binder 线程池
proc->startThreadPool();
}
frameworks/native/libs/binder/ProcessState.cpp
// Binder 通信数据大小 1M-8k
#define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)
// 最大 Binder 线程数量 15
#define DEFAULT_MAX_BINDER_THREADS 15
sp ProcessState::self()
{
Mutex::Autolock _l(gProcessMutex);
if (gProcess != NULL) {
return gProcess;
}
gProcess = new ProcessState("/dev/binder");
return gProcess;
}
static int open_driver(const char *driver)
{
// 打开 Binder 驱动
int fd = open(driver, O_RDWR | O_CLOEXEC);
if (fd >= 0) {
int vers = 0;
status_t result = ioctl(fd, BINDER_VERSION, &vers);
if (result == -1) {
ALOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
close(fd);
fd = -1;
}
if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
ALOGE("Binder driver protocol(%d) does not match user space protocol(%d)! ioctl() return value: %d",
vers, BINDER_CURRENT_PROTOCOL_VERSION, result);
close(fd);
fd = -1;
}
size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
if (result == -1) {
ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
}
} else {
ALOGW("Opening '%s' failed: %s\n", driver, strerror(errno));
}
return fd;
}
ProcessState::ProcessState(const char *driver)
: mDriverName(String8(driver))
, mDriverFD(open_driver(driver)) // 打开 binder 驱动
, mVMStart(MAP_FAILED)
, mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
, mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
, mExecutingThreadsCount(0)
, mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
, mStarvationStartTimeMs(0)
, mManagesContexts(false)
, mBinderContextCheckFunc(NULL)
, mBinderContextUserData(NULL)
, mThreadPoolStarted(false)
, mThreadPoolSeq(1)
{
if (mDriverFD >= 0) {
// mmap 内存映射
// mmap the binder, providing a chunk of virtual address space to receive transactions.
mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
if (mVMStart == MAP_FAILED) {
// *sigh*
ALOGE("Using /dev/binder failed: unable to mmap transaction memory.\n");
close(mDriverFD);
mDriverFD = -1;
mDriverName.clear();
}
}
LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened. Terminating.");
}
在这段代码我们能了解到很多 Binder 相关的东西:
AMS 使用 socket 通知 Zygote fork 进程也是走的这块流程。
我们从系统启动 init 进程开始分析到 Zygote 进程创建、SystemServer 进程创建,大致的将整体流程进行了梳理。
init 进程是系统内核启动后第二个启动的进程,该进程在用户空间。init 进程启动后会解析 init.rc 执行脚本启动 Zygote 进程和 ServiceManager 进程。
Zygote 因为是由 init 进程启动的,所以它也是在用户空间。Zygote 的业务处理横跨 native 层和 java 层。
Zygote 在 native 层处理的事情:
Zygote 在 java 层处理的事情:
Zygote 从创建到启动总体流程如下图:
Zygote fork 的第一个子进程是 SystemServer。
SystemServer 处理的事情:
SystemServer 流程图如下:
也简单说明了 Zygote fork 子进程时 Binder 的初始化过程,Binder 的初始化是在进程 fork 完成主入口 main() 方法执行之前处理。通过简单的流程分析能了解到 Binder 的一些信息:
系统启动整体流程如下图:
1、Zygote 进程最原始的进程是什么进程(或者 Zygote 的由来)?【Zygote 进程最开始的名字】
Zygote 最开始是 app_process,它是在 init 进程启动时被启动的,在 app_main.c 才被修改为 Zygote。
2、Zygote 是在内核空间还是在用户空间?
因为 init 进程的创建在用户空间,而 Zygote 是由 init 进程创建启动的,所以 Zygote 是在用户空间。
3、app 的进程启动,为什么是从 Zygote fork,而不是从 init 进程 fork?
Zygote 从创建到启动做了很多事情,比如创建虚拟机,注册 jni,预加载资源等等,fork 进程其实就是复制进程,如果不在 Zygote fork 进程,那么新创建 app 进程就要重新对以上流程再做一遍,而如果从 Zygote fork 子进程,app 进程创建运行就可以直接使用相关资源,不需要再处理。
而 init 进程主要做的事情是挂载文件(识别各类文件,相当于解析硬盘)、解析 init.rc、处理脚本(启动 Zygote、ServiceManager 进程等)。
4、Zygote 为什么用 socket 通信而不是 Binder?
目前网络上有两种说法:一种是会导致死锁,另一种是会导致读写错误。
(1)Zygote 用 binder 通信会导致死锁
假设 Zygote 使用 Binder 通信,因为 Binder 是支持多线程的,存在并发问题,而并发问题的解决方案就是加锁,如果进程 fork 是在多线程情况下运行,Binder 等待锁在锁机制下就可能会出现死锁。
为什么会出现死锁呢?我们可以用一个场景来分析。
假设是 AMS 使用 Binder 通信告知 Zygote fork 一个 app 进程,为了保证不会出现并发问题,AMS 和 Zygote 的通信会加锁,AMS 要和 Zygote 通信拿的 Binder 是属于 Zygote 的(获取的要通信方的 Binder 代理),此时 Zygote fork 了进程,会连带把 Binder 等待锁的状态也复制过去,那么子进程的 Binder 加了锁由谁来解锁?子进程没有解锁,就会出现死锁。
再从 fork 的原理上分析。
在内存区域里,静态变量 mutex 的内存会被拷贝到子进程里,而且父进程里即使存在多个线程,但它们也不会被继承到子进程里,fork 的这两个特征就是造成死锁的原因。
(2)Zygote 用 binder 通信会导致读写错误
根本原因在于要 new 一个 ProcessState 用于 Binder 通信时,需要 mmap 申请一片内存用以提供给内核进行数据交换使用。
而如果直接 fork 了的话,子进程在进行 binder 通信时,内核还是会继续使用父进程申请的地址写数据,而此时会触发子进程 COW(Copy on Write),从而导致地址空间已经重新映射,而子进程还尝试访问之前父进程 mmap 的地址,会导致 SIGSEGV、SEGV_MAPERR段错误。
可以自己写一个 demo 去尝试,提供一个JNI接口用来调用 fork,待 pid == 0 时,继续使用父进程已获取的binder对象进行binder调用,你就会获得这个段错误。
5、ServiceManager 和 SystemServiceManager 的关系?
ServiceManager 和 SystemServiceManager 没有关系。
ServiceManager 是一个独立进程,和 Zygote 一样通过 init.rc 执行脚本启动,在 SystemServer 启动的服务最终会注册到 ServiceManager 提供给上层使用。
SystemServiceManager 是在 SystemServer 创建的用于在 system_server 进程管理启动服务的管理类。
PMS(PackageManagerService)是 Android 提供的包管理系统服务,它用来管理所有的包信息,包括应用安装、卸载、更新以及解析 AndroidManifest.xml。通常情况下我们不会把 PMS 单独的拆分出来讲解,因为 PMS 最主要的是提供给 AMS(ActivityManagerService)服务。
你是否有考虑过为什么我们手机开启启动时会很慢?这是因为 在手机启动时 PMS 会在这段时间处理 apk 解析,至少有 70% 的启动时间耗费在 PMS 解析上,所以这也是为什么手机开机启动比较慢的原因之一。
从解析的角度上,可以理解为 PMS 保存了后续提供给 AMS 所需要的数据,它是具有保存应用数据的缓存。
当手机开机的时候,系统启动 PMS 后会去扫描两个目录,分别是存放用户安装的 apk 的目录 /data/app 以及系统安装的 apk 的目录 /system/app。
刚才有提到,PMS 是为了给 AMS 服务的,那 PMS 需要提供哪些数据呢?为什么需要 AndroidManifest.xml?
我们都知道 AndroidManifest.xml 定义了apk 中所有的四大组件、权限等等信息,它是一个定义文件。PMS 对 apk 的解析最主要的就是去扫描到 /data/app 和 /system/app 目录下的 apk 文件,找到 apk 包中的 AndroidManifest.xml,然后解析 AndroidManifest.xml 的信息保存到系统内存中,这样 AMS 在需要应用数据时,就能找到 PMS 快速的从内存中拿到相关信息。
如果没有 AndroidManifest.xml,PMS 的解析就是要保存每个 apk 中所有的类文件信息,这个数据量是庞大的,而且解析也会很慢,手机启动速度更慢。
在 Android 系统所有的核心服务都会经过 SystemServer 启动,PMS 也不例外,SystemServer 会在手机开机时启动运行。
SystemServer.java
public static void main(String[] args) {
new SystemServer().run();
}
private void run() {
...
try {
...
startBootstrapServices();
startCoreServices();
startOtherServices();
...
}
...
}
private void startBootstrapServices() {
...
// 启动 AMS
mActivityManagerService = mSystemServiceManager.startService(
ActivityManagerService.Lifecycle.class).getService();
mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
mActivityManagerService.setInstaller(installer);
...
// 启动 PMS
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
mFirstBoot = mPackageManagerService.isFirstBoot();
mPackageManager = mSystemContext.getPackageManager();
...
}
PackageManagerService.java
public static PackageManagerService main(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
// Self-check for initial settings.
PackageManagerServiceCompilerMapping.checkProperties();
// 创建自己的实例
PackageManagerService m = new PackageManagerService(context, installer,
factoryTest, onlyCore);
m.enableSystemUserPackages();
// 将 PMS 添加到 ServiceManager,AMS 找 PMS 拿数据时就是通过 ServiceManager 找到 PMS
ServiceManager.addService("package", m);
final PackageManagerNative pmn = m.new PackageManagerNative();
ServiceManager.addService("package_native", pmn);
return m;
}
当 SystemServer 被 Zygote 启动调用了 main() 方法时,执行了 SystemServer 的 run() 方法启动一些核心服务,例如先启动了 AMS 后再启动了 PMS,将 AMS 和 PMS 添加到 ServiceManager,由 ServiceManager 管理这些服务。
ServiceManager 只提供了 addService() 和 getService() 方法,当 app 进程需要获取到对应的系统服务,都会通过 ServiceManager 拿到相应服务的 Binder 代理,使用 Binder 通信获取数据:
例如在 Application、Activity 等地方调用 getPackageManager() 时:
ContextWrapper.java
@Override
public PackageManager getPackageManager() {
// mBase 是 ContextImpl
return mBase.getPackageManager();
}
ContextImpl.java
@Override
public PackageManager getPackageManager() {
if (mPackageManager != null) {
return mPackageManager;
}
IPackageManager pm = ActivityThread.getPackageManager();
if (pm != null) {
// Doesn't matter if we make more than one instance.
return (mPackageManager = new ApplicationPackageManager(this, pm));
}
return null;
}
ActivityThread.java
public static IPackageManager getPackageManager() {
if (sPackageManager != null) {
//Slog.v("PackageManager", "returning cur default = " + sPackageManager);
return sPackageManager;
}
// 通过 ServiceManager 拿到 PMS
IBinder b = ServiceManager.getService("package");
//Slog.v("PackageManager", "default service binder = " + b);
sPackageManager = IPackageManager.Stub.asInterface(b); // binder 通信
//Slog.v("PackageManager", "default service = " + sPackageManager);
return sPackageManager;
}
PMS 的处理流程简单理解就是手机开机时会去扫描两个目录 /data/app 和 /system/app,去解析这两个目录的 apk 文件的 AndroidManifest.xml 生成应用的摘要信息保存为 Java Bean 到内存。
PackageManagerService.java
// data/app 目录
private static final File sAppInstallDir =
new File(Environment.getDataDirectory(), "app");
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
...
// /system/app 目录
final File systemAppDir = new File(Environment.getRootDirectory(), "app");
// 扫描 /system/app 目录下的 apk 文件
scanDirTracedLI(systemAppDir,
mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM_DIR,
scanFlags
| SCAN_AS_SYSTEM,
0);
...
// 扫描 /data/app 目录下的 apk 文件
scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
...
}
private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags, long currentTime) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
try {
scanDirLI(scanDir, parseFlags, scanFlags, currentTime);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime) {
final File[] files = scanDir.listFiles();
...
try (ParallelPackageParser parallelPackageParser = new ParallelPackageParser(
mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir,
mParallelPackageParserCallback)) {
// Submit files for parsing in parallel
int fileCount = 0;
for (File file : files) {
// 判断是否是 .apk 后缀的文件
final boolean isPackage = (isApkFile(file) || file.isDirectory())
&& !PackageInstallerService.isStageName(file.getName());
if (!isPackage) {
// Ignore entries which are not packages
continue;
}
// 添加到子线程交给 PackageParser 解析 apk 文件
parallelPackageParser.submit(file, parseFlags);
fileCount++;
}
...
}
}
ParallelPackageParser.java
public void submit(File scanFile, int parseFlags) {
mService.submit(() -> {
ParseResult pr = new ParseResult();
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parallel parsePackage [" + scanFile + "]");
try {
PackageParser pp = new PackageParser();
pp.setSeparateProcesses(mSeparateProcesses);
pp.setOnlyCoreApps(mOnlyCore);
pp.setDisplayMetrics(mMetrics);
pp.setCacheDir(mCacheDir);
pp.setCallback(mPackageParserCallback);
pr.scanFile = scanFile; // 传入待解析的 apk 文件
// 交给 packageParser 解析 apk
pr.pkg = parsePackage(pp, scanFile, parseFlags);
} catch (Throwable e) {
pr.throwable = e;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
...
});
}
protected PackageParser.Package parsePackage(PackageParser packageParser, File scanFile,
int parseFlags) throws PackageParser.PackageParserException {
return packageParser.parsePackage(scanFile, parseFlags, true /* useCaches */);
}
PackageParser.java
public static final String APK_FILE_EXTENSION = ".apk";
public static final boolean isApkFile(File file) {
return isApkPath(file.getName());
}
public static boolean isApkPath(String path) {
return path.endsWith(APK_FILE_EXTENSION);
}
从源码可以看到,PMS 其实就是去扫描 /data/app/ 和 /system/app/ 两个目录下的 apk,判断目录下的文件是否是 apk 也只是简单的判断文件后缀是否是 .apk。然后通过 PackageParser 开始解析 apk。
需要注意的是,在不同的系统源码版本解析的方式也不相同,在 6.0、7.0、8.0 版本启动解析的方式还是直接解析的,但在 10.0 版本开始使用线程池放到子线程去解析,加快了手机启动速度。
根据上面的分析,apk 的解析最终是交给 PackageParser,继续查看是如何解析的:
PackageParser.java
public Package parsePackage(File packageFile, int flags, boolean useCaches)
throws PackageParserException {
// 如果有缓存,直接返回解析后的信息
Package parsed = useCaches ? getCachedResult(packageFile, flags) : null;
if (parsed != null) {
return parsed;
}
...
// apk 文件不是目录,所以会走的 parseMonolithicPackage()
if (packageFile.isDirectory()) {
parsed = parseClusterPackage(packageFile, flags);
} else {
parsed = parseMonolithicPackage(packageFile, flags);
}
...
}
public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
...
final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags);
try {
// 解析 apk
final Package pkg = parseBaseApk(apkFile, assetLoader.getBaseAssetManager(), flags);
pkg.setCodePath(apkFile.getCanonicalPath());
pkg.setUse32bitAbi(lite.use32bitAbi);
return pkg;
} catch (IOException e) {
throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
"Failed to get path: " + apkFile, e);
} finally {
IoUtils.closeQuietly(assetLoader);
}
}
private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
throws PackageParserException {
final String apkPath = apkFile.getAbsolutePath();
...
// 开始 dom 解析 AndroidManifest.xml
XmlResourceParser parser = null;
try {
final int cookie = assets.findCookieForPath(apkPath);
...
// ANDROID_MANIFEST_FILENAME 就是 AndroidManifest.xml
parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
...
final Package pkg = parseBaseApk(apkPath, res, parser, flags, outError);
...
return pkg;
} catch (PackageParserException e) {
throw e;
} catch (Exception e) {
throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
"Failed to read manifest from " + apkPath, e);
} finally {
IoUtils.closeQuietly(parser);
}
}
private Package parseBaseApk(String apkPath, Resources res, XmlResourceParser parser, int flags,
String[] outError) throws XmlPullParserException, IOException {
final String splitName;
final String pkgName;
try {
Pair packageSplit = parsePackageSplitNames(parser, parser);
pkgName = packageSplit.first; // 拿到包名
splitName = packageSplit.second;
...
}
...
// 后续的流程就是将 xml 解析的信息如权限、四大组件等信息存到 Package
final Package pkg = new Package(pkgName);
...
return parseBaseApkCommon(pkg, null, res, parser, flags, outError);
}
public final static class Package implements Parcelable {
// 包名
public String packageName;
...
// 申请的权限
public final ArrayList permissions = new ArrayList(0);
public final ArrayList permissionGroups = new ArrayList(0);
// 四大组件
public final ArrayList activities = new ArrayList(0);
public final ArrayList receivers = new ArrayList(0);
public final ArrayList providers = new ArrayList(0);
public final ArrayList services = new ArrayList(0);
...
}
上面的源码其实很好理解,就是根据传过来的 apk 文件路径先拿到 AndroidManifest.xml,然后开始进行 dom 解析 xml 文件,将不同的标签数据信息存放在 Package 类的不同字段,例如 权限信息、四大组件信息等,将它们都解析好存放到内存中,方便后续 AMS 找到 PMS 拿数据。
在 9.0 版本开始解析结果默认会开启缓存,如果有缓存则直接返回解析后的结果信息,否则就解析每个 apk 文件的 AndroidManifest.xml:
ParallelPackageParser.java
protected PackageParser.Package parsePackage(PackageParser packageParser, File scanFile,
int parseFlags) throws PackageParser.PackageParserException {
// 开启缓存
return packageParser.parsePackage(scanFile, parseFlags, true /* useCaches */);
}
PackageParser.java
public Package parsePackage(File packageFile, int flags, boolean useCaches)
throws PackageParserException {
// 如果有缓存,直接返回
Package parsed = useCaches ? getCachedResult(packageFile, flags) : null;
if (parsed != null) {
return parsed;
}
...
}
以上就是 PMS 的 apk 解析流程,简单说就是提前将 AMS 要用的数据信息先解析存到内存,方便能快速定位到 Activity 等信息。
当我们在应用商店下载安装应用或使用 adb install 时也是走的上述的解析过程。
再简单总结下 PMS 的 apk 解析流程:
了解了 PMS 解析 apk 的流程,我们可以根据原理 hook 实现动态装载的功能,使用 PackageParser 将网络下载的一个 apk 文件自己手动解析,然后通过反射添加到 PMS 的内存,实现动态装载功能。
下面的 demo 实现了一个简单的动态加载功能,将一个外部 apk 文件的广播添加到 PMS 的缓存中。
首先准备需要动态添加的广播,该广播放在外部 apk 文件 hook-debug.apk:
public class HookReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.i("HookReceiver", "hook receiver receive message");
// 给宿主广播发消息
Intent sendIntent = new Intent();
sendIntent.setAction("com.example.demo.main");
context.sendBroadcast(sendIntent);
}
}
将外部 apk 打包出来后,为了方便演示,demo 是将 apk 导入到 cache 目录。接下来是动态解析:
public class HookPackageParser {
public void parse(Context context, File apkFile) throws Exception {
Class> packageParserClazz = Class.forName("android.content.pm.PackageParser");
Method parsePackageMethod = packageParserClazz.getDeclaredMethod("parsePackage", File.class, int.class);
parsePackageMethod.setAccessible(true);
Object packageParserObj = packageParserClazz.newInstance();
// 调用 PackageParser.parsePackage() 获取到解析后的 Package
Object packageObj = parsePackageMethod.invoke(packageParserObj, apkFile, PackageManager.GET_RECEIVERS);
// 获取 receivers 成员变量
Field receiversField = packageObj.getClass().getDeclaredField("receivers");
List receivers = (List) receiversField.get(packageObj);
DexClassLoader dexClassLoader = new DexClassLoader(
apkFile.getAbsolutePath(),
context.getDir("plugin", Context.MODE_PRIVATE).getAbsolutePath(),
null,
context.getClassLoader());
Class> componentClazz = Class.forName("android.content.pm.PackageParser$Component");
Field intentsField = componentClazz.getDeclaredField("intents");
for (Object receiverObj : receivers) {
String name = (String) receiverObj.getClass().getField("className").get(receiverObj);
try {
BroadcastReceiver hookReceiver = (BroadcastReceiver) dexClassLoader.loadClass(name).newInstance();
List extends IntentFilter> filters = (List extends IntentFilter>) intentsField.get(receiverObj);
for (IntentFilter filter : filters) {
context.registerReceiver(hookReceiver, filter);
}
} catch (Exception e) {
// ignore
}
}
}
}
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
checkPermission(this);
// 注册一个用于接收 hook 广播发送的消息验证是否动态装载了外部 apk 的广播
IntentFilter filter = new IntentFilter();
filter.addAction("com.example.demo.main");
registerReceiver(new MainReceiver(), filter);
}
private boolean checkPermission(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && activity.checkSelfPermission(
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
activity.requestPermissions(new String[]{
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
}, 1);
}
return false;
}
// 先 hook 外部 apk 的 HookReceiver
public void hookReceiver(View view) {
HookPackageParser packageParser = new HookPackageParser();
File directory = getCacheDir();
String path = directory.getAbsolutePath() + "/hook-debug.apk";
File file = new File(path);
if (!file.exists()) {
throw new RuntimeException("hook apk no exist");
}
try {
packageParser.parse(this, file);
} catch (Exception e) {
e.printStackTrace();
}
}
// hook 后尝试发送广播看是否生效
public void sendBroadcast(View view) {
Intent intent = new Intent();
intent.setAction("com.example.demo.hook");
sendBroadcast(intent);
}
private static class MainReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.i("MainReceiver", "receive hook receiver message");
}
}
}
PackageParser 需要通过反射获取,再反射调用它的 parsePackage() 传入 apk 路径完成解析获取到 Package 对象,再反射 PMS 的 activities、providers、receivers、services 变量,将我们解析的数据添加进去,这样就实现了动态加载。
AMS(ActivityManagerService)主要负责系统中四大组件的启动、切换、调度及应用进程的管理和调度等工作。通常情况下我们不会把 AMS 单独的拆分出来讲解,因为 AMS 需要通过 PMS(PackageManagerService)获取信息。
下面的节点在讲解 AMS 时会穿插 PMS(PackageManagerService) 相关的内容。
在 Android PMS 原理 可以了解到,PMS 在手机开机的时候会运行解析所有 apk 的 AndroidManifest.xml,将每个 apk 信息存到内存中,并提供查询接口,可以认为 PMS 充当着包信息缓存的作用。
而 AMS 其中一个职责是管理调度 Activity,需要启动某个 Activity 时都会先找 PMS 查询要跳转的 Activity 信息再处理后续一系列的操作。
我们可以思考一个问题:为什么 Android 要提供 AMS 和 PMS?如果没有 AMS 和 PMS 会发生什么?
假设现在要启动某个进程的 Activity,简单梳理下会经历五个步骤:
如果每次进程调度都要这么处理,可以想象效率是很低的。
为了能快速的定位到要跳转的 Activity,前面的三个步骤将会交由 PMS,PMS 提前在开机启动时先解析完成存到内存,这样当 AMS 需要跳转某个 Activity 时,直接从 PMS 存储到内存的数据去提取信息,就能更快的完成操作。
AMS 从 PMS 拿到创建 Activity 的信息创建出来后,就会需要考虑 Activity 的生命周期,总不能 Activity 一退出就销毁,所以 AMS 就需要管理创建出来的 Activity 的生命周期。每个应用每个进程都有自己的 ActivityThread,所以 AMS 也需要一个缓存中心管理 Activity 的生命周期,就是由 ActivityThread 充当这个角色(更具体说是 ActivityThread 下的 mActivities 变量)。
ActivityThread.java
final ArrayMap mActivities = new ArrayMap<>();
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
Activity activity = null;
try {
// 创建 Activity
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
...
} catch (Exception e) {
...
}
...
try {
...
if (activity != null) {
...
r.activity = activity; // ActivityClientRecord 记录 Activity
}
mActivities.put(r.token, r); // 将创建的 Activity 存储到 map
} catch (SuperNotCalledException e) {
...
}
...
return activity;
}
public static final class ActivityClientRecord {
...
Activity activity; // 持有 Activity
...
}
可以看到 ActivityThread 的源码中有一个 mActivities 的成员变量,ActivityClientRecord 是持有 Activity 的引用。在后续的 performXxxActivity() 等处理生命周期的方法中都会用 mActivities 管理。
在 Android 无论是启动一个应用还是启动应用内的 Activity,都是调用的 startActivity() 方法。总体会经历三个步骤:
接下来我们具体通过源码(API 28)分析 startActivity() 的整个过程。
Activity.java
@Override
public void startActivity(Intent intent) {
this.startActivity(intent, null);
}
@Override
public void startActivity(Intent intent, @Nullable Bundle options) {
if (options != null) {
startActivityForResult(intent, -1, options);
} else {
// Note we want to go through this call for compatibility with
// applications that may have overridden the method.
startActivityForResult(intent, -1);
}
}
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
if (mParent == null) {
...
// 委托给 Instrumentation
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
....
}
...
}
当我们调用 startActivity() 时,最终都会调用到 startActivityForResult(),应用上层对接 Android 核心服务会委托给 Instrumentation。Instrumentation 是专门负责 Application 和 Activity 的相关所有活动处理,就是和 AMS 通信会委托给 Instrumentation。
Instrumentation.java
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
...
try {
...
// 找到 AMS 告知要启动 Activity
int result = ActivityManager.getService()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
...
}
...
}
Instrumentation 会告知 AMS 要启动一个 Activity。
需要注意的是,在这里不同系统版本的源码处理也不一样,在 9.0 之前是使用 AMS,9.0 之后是使用 ATMS(ActivityTaskManagerService):
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
...
try {
...
// 9.0 之后会通过 ATMS 告知要启动 Activity
int result = ActivityTaskManager.getService().startActivity(whoThread,
who.getBasePackageName(), who.getAttributionTag(), intent,
intent.resolveTypeIfNeeded(tho.getContentResolver()), token,
target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);
...
}
...
}
目前源码是以 API 28 分析,所以我们回到 API 28 的源码分析。
ActivityManager.getService().startActivity() 这句代码可以拆分成两部分:ActivityManager.getService() 和 startActivity()。
我们先看 ActivityManager.getService():
ActivityManager.java
public static IActivityManager getService() {
return IActivityManagerSingleton.get();
}
private static final Singleton IActivityManagerSingleton =
new Singleton() {
@Override
protected IActivityManager create() {
// 通过 ServiceManager 获取 AMS 服务
// IActivityManager 是 binder 代理
final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
final IActivityManager am = IActivityManager.Stub.asInterface(b);
return am;
}
};
public abstract class Singleton {
private T mInstance;
protected abstract T create();
public final T get() {
synchronized (this) {
if (mInstance == null) {
mInstance = create();
}
return mInstance;
}
}
}
ActivityManager.getService() 会获取 IActivityManager,它是一个 binder 代理对象。从代码可以看出,当使用 ActivityManager.getService() 对象调用方法时,实际上已经在做跨进程通信,由 binder 代理对象和 AMS 通信,通信所在的进程是 system_server。同时这里也是一个很好的 hook 点。
到这一步为止已经完成了告知 AMS 要启动 Activity 的第一个步骤。
我们继续分析源码。
ActivityManagerService.java
@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
// 有多个 startActivityAsUser() 重载方法,为了方便查看省略了多个方法调用
return startActivityAsUser(...);
}
public final int startActivityAsUser(...) {
...
// mActivityStartController.obtainStarter 返回 ActivityStarter 对象
return mActivityStartController.obtainStarter(intent, "startActivityAsUser")
.setCaller(caller)
.setCallingPackage(callingPackage)
.setResolvedType(resolvedType)
.setResultTo(resultTo)
.setResultWho(resultWho)
.setRequestCode(requestCode)
.setStartFlags(startFlags)
.setProfilerInfo(profilerInfo)
.setActivityOptions(bOptions)
.setMayWait(userId)
.execute();
}
使用 AMS 调用 startActivity() 方法,主要是找到 mActivityStartController.obtainStarter() 获取到 ActivityStarter 对象,很明显使用了构建者模式配置相关参数,重点在 execute() 方法。
按照我们一开始设定的步骤,第二步是 AMS 要找到 PMS 获取跳转 Activity 相关的信息,那么 AMS 是怎么和 PMS 通信的?
ActivityStarter.java
int execute() {
try {
if (mRequest.mayWait) {
return startActivityMayWait(...);
} else {
return startActivity(...);
}
} finally {
...
}
}
private int startActivityMayWait(...) {
...
// AMS 和 PMS 产生关联,从 PMS 获取信息
ResolveInfo rInfo = mSupervisor.resolveIntent(...);
...
return res;
}
ActivityStackSupervisor.java
ResolveInfo resolveIntent(...) {
// mService 是 AMS
synchronized (mService) {
...
try {
// mService.getPackageManagerInternalLocked() 返回 PackageManagerInternalImpl
return mService.getPackageManagerInternalLocked().resolveIntent(...);
} finally {
....
}
}
...
}
ActivityManagerService.java
PackageManagerInternal getPackageManagerInternalLocked() {
if (mPackageManagerInt == null) {
mPackageManagerInt = LocalServices.getService(PackageManagerInternal.class);
}
return mPackageManagerInt;
}
PackageManagerService.java
// PackageManagerInternalImpl 的作用是,它作为内部类能拿到外部类的引用
// 所以可以充当 AMS 和 PMS 的桥梁,让 AMS 能获取到 PMS
private class PackageManagerInternalImpl extends PackageManagerInternal {
...
@Override
public ResolveInfo resolveIntent(Intent intent, String resolvedType,
int flags, int userId, boolean resolveForStart, int filterCallingUid) {
// 作为桥梁外部调用相关方法时都转发给 PMS
// ResolveInfo 持有 ActivityInfo、serviceInfo 等信息
return resolveIntentInternal(
intent, resolvedType, flags, userId, resolveForStart, filterCallingUid);
}
...
}
ResolveInfo.java
public class ResolveInfo implements Parcelable {
public ActivityInfo activityInfo;
public ServiceInfo serviceInfo;
public ProviderInfo providerInfo;
...
}
AMS 和 PMS 通信获取的是 ResolveInfo 包装对象,它可以存储 ActivityInfo、ServiceInfo 等信息,不直接返回 ActivityInfo 的原因应该是要启动 Service 等其他组件时可以复用同一套逻辑,因为获取的方式基本是相同的。
AMS 和 PMS 的通信也不是直接通信,而是通过 PMS 的 PackageManagerInternalImpl 内部类作为桥梁,内部类持有外部类的引用,所以 PackageManagerInternalImpl 可以直接访问 PMS。这样的做法既能实现功能,又能降低 AMS 和 PMS 之间的耦合,限制公开的 api 访问。
到这里已经完成第二步从 PMS 获取到要启动的 Activity 信息,就可以开始第三步启动 Activity。
ActivityStarter.java
private int startActivityMayWait(...) {
...
// AMS 和 PMS 产生关联,从 PMS 获取信息
ResolveInfo rInfo = mSupervisor.resolveIntent(...);
...
// 从封装的 ResolveInfo 获取到要跳转的 ActivityInfo 信息
ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);
...
// 开始启动 Activity
int res = startActivity(...);
...
return res;
}
private int startActivity(...) {
int result = START_CANCELED;
try {
...
result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
startFlags, doResume, options, inTask, outActivity);
} finally {
...
}
...
}
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
ActivityRecord[] outActivity) {
...
mSuperVisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
mOptions);
...
}
ActivityStackSupervisor.java
boolean resumeFocusedStackTopActivityLocked(
ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
if (!readyToResume()) {
return false;
}
if (targetStack != null && isFocusedStack(targetStack)) {
return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
}
final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
if (r == null || !r.isState(RESUMED)) {
mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
} else if (r.isState(RESUMED)) {
// Kick off any lingering app transitions form the MoveTaskToFront operation.
mFocusedStack.executeAppTransition(targetOptions);
}
return false;
}
ActivityStack.java
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
...
try {
...
result = resumeTopActivityInnerLocked(prev, options);
...
}
}
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
...
mStackSupervisor.startSpecificActivityLocked(next, true, false);
...
}
void startSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
...
// 先判断要启动的 Activity 进程是否已经存在
if (app != null && app.thread != null) {
try {
...
// 进程已经存在,启动 Activity
realStartActivityLocked(r, app, andResume, checkConfig);
return;
} catch (RemoteException e) {
...
}
}
// 如果进程不存在,AMS 通知 zygote 启动进程,最终反射调用 ActivityThread.main()
// 有多个 startProcessLocked() 重载方法,为了方便查看省略了多个方法调用
mService.startProcessLocked(...);
}
ActivityManagerService.java
private boolean startProcessLocked(...) {
...
// 其中一个 startProcessLocked() 提供了要启动的进程为 ActivityThread
final String entryPoint = "android.app.ActivityThread";
... // 省略其他 startProcessLocked() 调用
if (mConstants.FLAG_PROCESS_START_ASYNC) {
...
// 传入要启动的进程
final ProcessStartResult startResult = startProcess(app.hostingType, entryPoint, ...)
}
...
}
private ProcessStartResult startProcess(String entryPoint, ...) {
try {
...
startResult = Process.start(entryPoint, ...);
...
} finally {
...
}
}
Process.java
public static final ProcessStartResult start(final String processClass, ...) {
return zygoteProcess.start(processClass, ...);
}
按上面源码的分析,启动 Activity 前其实还需要再细分拆成两个处理:
要启动的 Activity 所在进程如果没有创建,AMS 会通知 Zygote fork 进程,最终会反射调用 ActivityThread 的 main() 方法,再走后续的 Activity 创建及后续生命周期流程
进程已经创建,realStartActivityLocked() 创建 Activity 及后续生命周期流程
Activity 的启动涉及到了生命周期,AMS 既然是管理调度 Activity 的服务,那就需要能和启动的 Activity 有所关联。AMS 是用什么方式管理 Activity 的生命周期的?
ActivityThread.java
final ApplicationThread mAppThread = new ApplicationThread();
public static void main(String[] args) {
...
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
...
}
private void attach(boolean system, long startSeq) {
...
if (!system) {
...
final IActivityManager mgr = ActivityManager.getService();
try {
// 将 ApplicationThread 给到 AMS 作为句柄管理
mgr.attachApplication(mAppThread, startSeq);
} catch (RemoteException ex) {
...
}
...
}
...
}
private class ApplicationThread extends IApplicationThread.Stub {
// AMS 下发管理四大组件,将处理转发给变量名为 mH 的 Handler
...
@Override
public void scheduleTransaction(ClientTransaction transaction) {
ActivityThread.this.scheduleTransaction(transaction);
}
}
class H extends Handler {
// Activity 生命周期等消息的处理
...
}
在 ActivityThread 的 main() 方法,可以从源码看到创建了一个 ApplicationThread,然后将这个对象给到了 AMS,Activity 生命周期其实就是使用的 ApplicationThread 作为句柄交给 AMS,AMS 就可以通过这个句柄下发管理 Activity 的生命周期;同样的 AMS 也通过 ApplicationThread 管理四大组件和进程的其他处理,在 ApplicationThread 由 Handler 转发消息驱动处理。
启动 Activity 之前,还需要先启动创建 Application。AMS 获取 ApplicationThread 调用了 attachApplication():
ActivityManagerService.java
public class ActivityManagerService extends IActivityManager.Stub
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
@Override
public final void attachApplication(IApplicationThread thread, long startSeq) {
synchronized (this) {
...
attachApplicationLocked(thread, callingPid, callingUid, startSeq);
...
}
}
@GuardedBy("this")
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid, int callingUid, long startSeq) {
...
if (app.isolatedEntryPoint != null) {
...
} else if (app.instr != null) {
// 通过 ApplicationThread 和 App 进程通信
thread.bindApplication(processName, appInfo, providers,
app.instr.mClass,
profilerInfo, app.instr.mArguments,
app.instr.mWatcher,
app.instr.mUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(getGlobalConfiguration()), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, isAutofillCompatEnabled);
} else {
...
}
...
if (normalMode) {
try {
// 创建完 Application 后走 Activity 生命周期流程
if (mStackSupervisor.attachApplicationLocked(app)) {
didSomething = true;
}
} catch (Exception e) {
Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
badApp = true;
}
}
}
}
ActivityThread.java
private class ApplicationThread extends IApplicationThread.Stub {
public final void bindApplication(...) {
...
// 在 ActivityThread 也是获取的 AMS 数据创建 application
AppBindData data = new AppBindData();
data.processName = processName;
data.appInfo = appInfo;
data.providers = providers;
data.instrumentationName = instrumentationName;
data.instrumentationArgs = instrumentationArgs;
data.instrumentationWatcher = instrumentationWatcher;
data.instrumentationUiAutomationConnection = instrumentationUiConnection;
data.debugMode = debugMode;
data.enableBinderTracking = enableBinderTracking;
data.trackAllocation = trackAllocation;
data.restrictedBackupMode = isRestrictedBackupMode;
data.persistent = persistent;
data.config = config;
data.compatInfo = compatInfo;
data.initProfilerInfo = profilerInfo;
data.buildSerial = buildSerial;
data.autofillCompatibilityEnabled = autofillCompatibilityEnabled;
sendMessage(H.BIND_APPLICATION, data); // 消息驱动发消息给到 Handler
}
}
class H extends Handler {
public static final int BIND_APPLICATION = 110;
...
public void handleMessage(Message msg) {
switch (mssg.what) {
case BIND_APPLICATION:
AppBindData data = (AppBindData) msg.obj;
handleBindApplication(data);
break;
...
}
}
}
private void handleBindApplication(AppBindData data) {
...
// 反射创建 Instrumentation 负责管理 application 和 activity 相关所有活动处理
try {
final ClassLoader cl = instrContext.getClassLoader();
mInstrumentation = (Instrumentation)
cl.loadClass(data.instrumentationName.getClassName()).newInstance();
} catch (Exception e) {
...
}
...
try {
// info 是 LoadedApk,反射创建 application
app = data.info.makeApplication(data.restrictedBackupMode, null);
...
}
...
}
public final class LoadedApk {
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
...
// 创建 application
Application app = null;
try {
ClassLoader cl = getClassLoader();
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
} catch (Exception e) {
...
}
...
if (instrumentation != null) {
try {
// 调用 application.onCreate()
instrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
...
}
}
...
}
}
attachApplication() 实际上做了三件事情:
在上面我们有提到,Activity 的创建和后续生命周期流程是从 realStartActivityLocked() 方法开始的。让我们继续分析 Activity 的创建过程。
ActivityManagerService.java
public class ActivityManagerService extends IActivityManager.Stub
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
final ActivityStackSupervisor mStackSupervisor;
@Override
public final void attachApplication(IApplicationThread thread, long startSeq) {
synchronized (this) {
...
attachApplicationLocked(thread, callingPid, callingUid, startSeq);
...
}
}
@GuardedBy("this")
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid, int callingUid, long startSeq) {
...
if (mStackSupervisor.attachApplicationLocked(app)) {
}
...
}
}
ActivityStackSupervisor.java
public class ActivityStackSupervisor extends ConfigurationContainer implements DisplayListener,
RecentTasks.Callbacks {
boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
...
if (realStartActivityLocked(activity, app, top == activity) {
}
...
}
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
boolean andResume, boolean checkConfig) throws RemoteException {
...
// app.thread 是 ApplicationThread
// Create activity launch transaction.
final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread,
r.appToken);
clientTransaction.addCallback(LaunchActivityItem.obtain(...));
final ActivityLifecycleItem lifecycleItem;
if (andResume) {
lifecycleItem = ResumeActivityItem.obtain(mService.isNextTransitionForward());
} else {
lifecycleItem = PauseActivityItem.obtain();
}
// 执行完 LaunchActivityItem 事务后要处在的生命周期状态
clientTransaction.setLifecycleStateRequest(lifecycleItem);
// mService 是 AMS
// Schedule transaction.
mService.getLifecycleManager().scheduleTransaction(clientTransaction);
...
}
}
ClientTransaction 是客户端事务管理类,通过不同的状态 LaunchActivityItem、ResumeActivityItem、PauseActivityItem 等,分别代表不同的 Activity 生命周期,以状态的方式加以管理。
在上面有提到 AMS 管理 Activity 的生命周期是通过 ApplicationThread 句柄,在创建 ClientTransaction.obtain() 也能看到是传入了 ApplicationThread 下发的生命周期处理:
ClientTransaction.java
public class ClientTransaction implements Parcelable, ObjectPoolItem {
private IApplicationThread mClient;
// 记录事务结束后要处在的生命周期状态,后面会用到
public void setLifecycleStateRequest(ActivityLifecycleItem stateRequest) {
mLifecycleStateRequest = stateRequest;
}
public void schedule() throws RemoteException {
mClient.scheduleTransaction(this);
}
public static ClientTransaction obtain(IApplicationThread client, IBinder activityToken) {
ClientTransaction instance = ObjectPool.obtain(ClientTransaction.class);
if (instance == null) {
instance = new ClientTransaction();
}
instance.mClient = client; // 存储的 ApplicationThread
instance.mActivityToken = activityToken;
return instance;
}
}
继续分析 mService.getLifecycleManager().scheduleTransaction(clientTransaction) 做了什么事情:
ActivityManagerService.java
public class ActivityManagerService extends IActivityManager.Stub
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
ClientLifecycleManager getLifecycleManager() { return mLifecycleManager; }
}
class ClientLifecycleManager {
void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
final IApplicationThread client = transaction.getClient();
transaction.schedule();
...
}
}
ClientTransaction.java
public class ClientTransaction implements Parcelable, ObjectPoolItem {
private IApplicationThread mClient;
public void schedule() throws RemoteException {
mClient.scheduleTransaction(this); // 拿着 ApplicationThread 下发通知
}
}
ActivityThread.java
private class ApplicationThread extends IApplicationThread.Stub {
@Override
public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
// 在 ActivityThread 是找不到 scheduleTransaction 方法的
// 而是在 ActivityThread 的父类 ClientTransactionHandler 调用
ActivityThread.this.scheduleTransaction(transaction);
}
}
AMS 就是拿着 ApplicationThread 句柄告知 ActivityThread 要创建 Activity,在 ActivityThread 的源码中你会发现 ActivityThread.this.scheduleTransaction() 代码没有找到,实际上它是放在了 ActivityThread 继承的父类 ClientTransactionHandler。
ClientTransactionHandler.java
public abstract class ClientTransactionHandler {
void scheduleTransaction(ClientTransaction transaction) {
transaction.preExecute(this);
// 通过 Handler 发了一条消息
sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}
}
public final class ActivityThread extends ClientTransactionHandler {
// TransactionExecutor的构造传入的 ActivityThread
private final TransactionExecutor mTransactionExecutor = new TransactionExecutor(this);
class H extends Handler {
public static final int EXECUTE_TRANSACTION = 159;
public void handleMessage(Message msg) {
switch (msg.what) {
case EXECUTE_TRANSACTION:
final ClientTransaction transaction = (ClientTransaction) msg.obj;
mTransactionExecutor.execute(transaction);
break;
}
}
}
}
TransactionExecutor.java
public class TransactionExecutor {
// ActivityThread
private ClientTransactionHandler mTransactionHandler;
public TransactionExecutor(ClientTransactionHandler clientTransactionHandler) {
mTransactionHandler = clientTransactionHandler;
}
public void execute(ClientTransaction transaction) {
...
executeCallbacks(transaction);
executeLifecycleState(transaction);
...
}
public void executeCallbacks(ClientTransaction transaction) {
final List callbacks = transaction.getCallbacks();
...
final int size = callbacks.size();
for (int i = 0; i < size; ++i) {
final ClientTransactionItem item = callbacks.get(i);
...
// 执行事务,这里是设置了 LaunchActivityItem
item.execute(mTransactionHandler, token, mPendingActions);
...
}
}
private void executeLifecycleState(ClientTransaction transaction) {
final ActivityLifecycleItem lifecycleItem = transaction.getLifecycleStateRequest();
...
// 执行完事务后处在的生命周期状态,这里是 ResumeActivityItem
lifecycleItem.execute(mTransactionHandler, token, mPendingActions);
}
}
在 Handler 接收到消息后启动事务的处理,处理事物交由 TransactionExecutor 负责,主要看两个函数:
LaunchActivityItem.java
public class LaunchActivityItem extends ClientTransactionItem {
@Override
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
mPendingResults, mPendingNewIntents, mIsForward,
mProfilerInfo, client);
// 最终到 ActivityThread 开始创建 Activity
client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
}
}
ActivityThread.java
public final class ActivityThread extends ClientTransactionHandler {
@Override
public Activity handleLaunchActivity(ActivityClientRecord r,
PendingTransactionActions pendingActions, Intent customIntent) {
...
final Activity a = performLaunchActivity(r, customIntent);
...
}
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
// 通过 Instrumentation 反射创建 Activity
ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;
try {
ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
...
}
...
// 调用 Activity 生命周期 onCreate()
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
}
}
简单总结下 realStartActivityLocked() 做了什么事情:
创建了 ClientTransaction 处理生命周期的执行事务,可以认为它是 AMS 具体处理 Activity 生命周期的执行类。不同的生命周期用不同的状态表示, LaunchActivityItem 表示的 onCreate() 的生命周期,还有 ResumeActivityItem 表示的 onResume() 的生命周期,事务具体执行最终都会下发到对应的 ActivityLifecycleItem,由这些状态类执行回调 Activity 的生命周期。
至此,App 的启动流程就分析到这里。
总结下整体 App 的启动过程:
具体流程如下:
有关 AMS 的源码已经分析完毕,那么知道 AMS 的源码有哪些应用场景呢?
我们经常会在业务中遇到一种场景,如果用户未登陆就跳转到登陆界面,已登陆就跳转到其他界面,所以也就会出现类似这种写法:
if (isLogin) {
startActivity(new Intent(context, LoginActivity.class);
} else {
startActivity(new Intent(context, OtherActivity.class);
}
当项目有大量的地方需要判断登陆再跳转界面,后续如果有业务改动,比如跳转的登陆界面修改,这种硬编码的方式侵入性高,要修改的范围很广,并不利于维护。
或许你会说:我用隐式意图在 AndroidManifest.xml 定义 action,然后用常量类提供 action 统一管理不就行了:
AndroidManifest.xml
public class Constants {
public static final String ACTION_LOGIN = "android.intent.action.login";
}
if (isLogin) {
startActivity(new Intent(context, Constants.ACTION_LOGIN);
} else {
startActivity(new Intent(context, OtherActivity.class);
}
那我再加一个条件:我想不在 AndroidManifest.xml 注册登陆界面想正常启动,能做到吗?
正常情况是不行的,但我们在熟悉了 AMS 和 PMS 的源码后,就能通过 hook 绕过系统检测正常启动一个 Activity。
hook 简单来说就是绕过系统处理,自己用不同的方式实现同样的效果,但这个过程还是要用到系统创建的一些信息帮助我们完成处理。
但是要使用 hook 一般有三个前提条件:
根据一开始提到的每次跳转都要鉴权的案例,我们尝试用 hook 实现只在代码写具体业务跳转,自动完成没有登陆就跳转登陆界面,否则就跳转具体业务界面。demo 将在 API 28 的源码上实现。
要实现这个效果有两大难点:
不在 AndroidManifest.xml 注册界面,在文章最开始有提到 AMS 的原理分析是离不开 PMS的,因为 AMS 在启动 Activity 过程中会找 PMS 拿 Activity 的信息,所以这个问题更具体说是如何绕过 PMS 的检查。
为了实现这个效果,hook 能做的就是将 startActivity() 拦截下来,替换掉携带着目标 Activity 的 Intent 信息,在原始数据保留的情况下增加额外的信息到 Intent。这样也就能在 PMS 的检查下流程正常执行。
那么合适的 hook 在哪里呢?Instrumentation 有一个和 AMS 通信的处理,我们要拿到 AMS 的 binder 代理,这里重新将源码贴出来:
ActivityManager.java
// 已经创建好的 IActivityManager,更具体说要拿到 mInstance,是一个很好的 hook 点
public static IActivityManager getService() {
return IActivityManagerSingleton.get();
}
private static final Singleton IActivityManagerSingleton =
new Singleton() {
@Override
protected IActivityManager create() {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
final IActivityManager am = IActivityManager.Stub.asInterface(b);
return am;
}
};
public abstract class Singleton {
private T mInstance;
protected abstract T create();
public final T get() {
synchronized (this) {
if (mInstance == null) {
mInstance = create();
}
return mInstance;
}
}
}
hook 并不是完全要自己创建信息,而是要利用系统 api 或提前创建好的信息加以利用,mInstance 即 IActivityManager 是我们要用到的对象,要拦截它调用 startActivity() 时的处理,替换我们的 Intent,这需要用到动态代理。代码如下:
public class Hooker {
public void hook() throws Exception {
hookAms();
}
public void hookAms() throws Exception {
if (proxyActivity == null) {
throw new NullPointerException("proxyActivity is null");
}
Class ActivityManagerClz = Class.forName("android.app.ActivityManager");
Field IActivityManagerSingletonField = ActivityManagerClz.getDeclaredField("IActivityManagerSingleton");
IActivityManagerSingletonField.setAccessible(true);
// 获取到 ActivityManager 的 IActivityManagerSingleton 内部静态成员变量
Object IActivityManagerSingletonObj = IActivityManagerSingletonField.get(null);
Class SingletonClz = Class.forName("android.util.Singleton");
Field mInstanceField = SingletonClz.getDeclaredField("mInstance");
mInstanceField.setAccessible(true);
// 拿到 ActivityManagerService 的 binder 代理
// 做这一步是为了绕过 AMS 的鉴权,因为要设置的 LoginActivity 也是没有在 AndroidManifest.xml 注册,也就是要绕过 PMS
Object IActivityManagerObj = mInstanceField.get(IActivityManagerSingletonObj);
Class IActivityManagerClz = Class.forName("android.app.IActivityManager");
Object proxyIActivityManager = Proxy.newProxyInstance(
Thread.currentThread().getContextClassLoader(),
new Class[] {IActivityManagerClz}, new AmsInvocationHandler(IActivityManagerObj));
// 将 IActivityManagerSingleton 的 mInstance 成员替换为我们自己的代理对象
// 将 mInstance 的调用都跑我们的代理
mInstanceField.set(IActivityManagerSingletonObj, proxyIActivityManager);
}
private class AmsInvocationHandler implements InvocationHandler {
private final Object iActivityManagerObject;
public AmsInvocationHandler(Object iActivityManagerObject) {
this.iActivityManagerObject = iActivityManagerObject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 系统使用 mInstance 的调用都会走到代理
if ("startActivity".contains(method.getName())) {
Intent intent = null;
int index = 0;
for (int i = 0; i < args.length; i++) {
Object arg = args[i];
if (arg instanceof Intent) {
intent = (Intent) args[i];
index = i;
break;
}
}
if (intent != null) {
Intent proxyIntent = new Intent();
ComponentName componentName = new ComponentName(context, proxyActivity);
proxyIntent.setComponent(componentName);
proxyIntent.putExtra("oldIntent", intent);
args[index] = proxyIntent; // 替换真实意图
}
}
return method.invoke(iActivityManagerObject, args);
}
}
}
绕过 PMS 的问题已经解决,接下来是第二个问题:怎么正常启动 Activity?
Activity 的创建和生命周期流程都是在 Handler 消息驱动下完成的,定位到具体源码是 ActivityThread 的 mH 成员变量:
ActivityThread.java
final H mH = new H();
class H extends Handler {
public static final int EXECUTE_TRANSACTION = 159;
public void handleMessage(Message msg) {
switch (msg.what) {
case EXECUTE_TRANSACTION:
final ClientTransaction transaction = (ClientTransaction) msg.obj;
mTransactionExecutor.execute(transaction);
break;
}
}
}
很遗憾的是,不能在 ActivityThread 将 handleMessage() 的消息拦截下来。
实际上 Handler 已经为我们提供了 hook 点:
Handler.java
final Callback mCallback;
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
// 如果 mCallback 不为空,先处理 mCallback 的 handleMessage()
// 如果 mCallback 的 handleMessage() 返回 false,调用兜底的 handleMessage()
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
可以设置我们自己的 mCallback,这样就能在兜底的 handleMessage() 之前,提前将消息拦截处理,需要拦截的消息返回 true 不再传递,否则返回 false 按正常走不影响启动流程。
完整代码如下:
public class Hooker {
private final Context context;
private Class> proxyActivity;
public Hooker(@NonNull Context context) {
this.context = context;
}
public void setProxyActivity(@NonNull Class> proxyActivity) {
this.proxyActivity = proxyActivity;
}
public void hook() throws Exception {
hookAms();
hookSystemHandler();
}
public void hookAms() throws Exception {
if (proxyActivity == null) {
throw new NullPointerException("proxyActivity is null");
}
Class ActivityManagerClz = Class.forName("android.app.ActivityManager");
Field IActivityManagerSingletonField = ActivityManagerClz.getDeclaredField("IActivityManagerSingleton");
IActivityManagerSingletonField.setAccessible(true);
// 获取到 ActivityManager 的 IActivityManagerSingleton 内部静态成员变量
Object IActivityManagerSingletonObj = IActivityManagerSingletonField.get(null);
Class SingletonClz = Class.forName("android.util.Singleton");
Field mInstanceField = SingletonClz.getDeclaredField("mInstance");
mInstanceField.setAccessible(true);
// 拿到 ActivityManagerService 的 binder 代理
// 做这一步是为了绕过 AMS 的鉴权,因为要设置的 LoginActivity 也是没有在 AndroidManifest.xml 注册,也就是要绕过 PMS
Object IActivityManagerObj = mInstanceField.get(IActivityManagerSingletonObj);
Class IActivityManagerClz = Class.forName("android.app.IActivityManager");
Object proxyIActivityManager = Proxy.newProxyInstance(
Thread.currentThread().getContextClassLoader(),
new Class[] {IActivityManagerClz}, new AmsInvocationHandler(IActivityManagerObj));
// 将 IActivityManagerSingleton 的 mInstance 成员替换为我们自己的代理对象
// 将 mInstance 的调用都跑我们的代理
mInstanceField.set(IActivityManagerSingletonObj, proxyIActivityManager);
}
public void hookSystemHandler() throws Exception {
Class ActivityThreadClz = Class.forName("android.app.ActivityThread");
Field field = ActivityThreadClz.getDeclaredField("sCurrentActivityThread");
field.setAccessible(true);
Object ActivityThreadObj = field.get(null);
Field mHField = ActivityThreadClz.getDeclaredField("mH");
mHField.setAccessible(true);
Handler mHObj = (Handler) mHField.get(ActivityThreadObj);
Field mCallbackField = Handler.class.getDeclaredField("mCallback");
mCallbackField.setAccessible(true);
ProxyHandlerCallback proxyCallback = new ProxyHandlerCallback();
mCallbackField.set(mHObj, proxyCallback);
}
private class ProxyHandlerCallback implements Handler.Callback {
public static final int EXECUTE_TRANSACTION = 159;
@Override
public boolean handleMessage(Message msg) {
if (msg.what == EXECUTE_TRANSACTION) {
try {
Class> ClientTransactionClz = Class.forName("android.app.servertransaction.ClientTransaction");
if (!ClientTransactionClz.isInstance(msg.obj)) {
return false;
}
Class> LaunchActivityItemClz = Class.forName("android.app.servertransaction.LaunchActivityItem");
Field mActivityCallbacksField = ClientTransactionClz.getDeclaredField("mActivityCallbacks");
mActivityCallbacksField.setAccessible(true);
Object mActivityCallbacksObj = mActivityCallbacksField.get(msg.obj);
List list = (List) mActivityCallbacksObj;
if (list.size() == 0) {
return false;
}
Object LaunchActivityItemObj = list.get(0);
if (!LaunchActivityItemClz.isInstance(LaunchActivityItemObj)) {
return false;
}
Field mIntentField = LaunchActivityItemClz.getDeclaredField("mIntent");
mIntentField.setAccessible(true);
Intent mIntent = (Intent) mIntentField.get(LaunchActivityItemObj);
Intent realIntent = mIntent.getParcelableExtra("oldIntent");
if (realIntent != null) {
SharedPreferences sp = context.getSharedPreferences("name", MODE_PRIVATE);
boolean isLogin = sp.getBoolean("isLogin", false);
if (isLogin) {
mIntent.setComponent(realIntent.getComponent());
} else {
ComponentName componentName = new ComponentName(context, LoginActivity.class);
mIntent.putExtra("extraIntent", realIntent.getComponent().getClassName()); // 提供给登陆界面登陆成功后跳转到哪个目标页面
mIntent.setComponent(componentName);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
return false; // 返回 false 不影响系统的执行
}
}
private class AmsInvocationHandler implements InvocationHandler {
private final Object iActivityManagerObject;
public AmsInvocationHandler(Object iActivityManagerObject) {
this.iActivityManagerObject = iActivityManagerObject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 系统使用 mInstance 的调用都会走到代理
if ("startActivity".contains(method.getName())) {
Intent intent = null;
int index = 0;
for (int i = 0; i < args.length; i++) {
Object arg = args[i];
if (arg instanceof Intent) {
intent = (Intent) args[i];
index = i;
break;
}
}
if (intent != null) {
Intent proxyIntent = new Intent();
ComponentName componentName = new ComponentName(context, proxyActivity);
proxyIntent.setComponent(componentName);
proxyIntent.putExtra("oldIntent", intent);
args[index] = proxyIntent; // 替换真实意图
}
}
return method.invoke(iActivityManagerObject, args);
}
}
}
这样就能完成我们的效果了,写个 demo 测试下:
public class MainActivity extends AppCompatActivity {
private Hooker hooker;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
hooker = new Hooker(this);
}
public void logout(View view) {
SharedPreferences sp = getSharedPreferences("name", MODE_PRIVATE);
sp.edit().putBoolean("isLogin", false).apply();
}
public void startPage1(View view) {
hooker.setProxyActivity(Page1Activity.class);
try {
hooker.hook();
} catch (Exception e) {
e.printStackTrace();
}
startActivity(new Intent(this, Page1Activity.class));
}
public void startPage2(View view) {
hooker.setProxyActivity(Page2Activity.class);
try {
hooker.hook();
} catch (Exception e) {
e.printStackTrace();
}
startActivity(new Intent(this, Page2Activity.class));
}
}
public class LoginActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
}
public void login(View view) throws ClassNotFoundException {
SharedPreferences sp = getSharedPreferences("name", MODE_PRIVATE);
sp.edit().putBoolean("isLogin", true).apply();
String className = getIntent().getStringExtra("extraIntent");
if (!TextUtils.isEmpty(className)) {
startActivity(new Intent(this, Class.forName(className)));
finish();
}
}
}