原文链接:http://harttle.com/2014/05/27/android-appstartup.html
通过分析和修改Android 源码,分析 Android App 启动过程的时间消耗及性能瓶颈。
本文包括源码编译与运行、源码修改与调试、数据收集与分析。分析了 App 启动过程中, Activity Manager Service
、Binder
、Launcher
和MainActivity
扮演的角色以及消耗的时间。
源码编译与运行
环境配置
环境要求可以在从 文档 查询得到。以下在Arch Linux中进行Android Source Building的环境配置。
安装依赖
# x86
yaourt -S --needed gcc git gnupg flex bison gperf sdl wxgtk squashfs-tools curl ncurses zlib schedtool perl-switch zip unzip libxslt
# x64
yaourt -S --needed gcc-multilib lib32-zlib lib32-ncurses lib32-readline
# Android 工具
yaourt -S android-sdk android-sdk-platform-tools android-sdk-build-tools android-studio
增加交换空间,加 RAM 应达到 16G (另外,还需要 30G 的大小写敏感文件系统可用空间)
su
swapoff /swapfile && rm /swapfile
dd if=/dev/zero of=/swapfile bs=512M count=8
mkswap /swapfile && swapon /swapfile
环境降级
# make 3.81-3.82
yaourt -S make-3.81
# python2
cd /usr/bin && sudo ln -sf python python2
# java SE 1.6
yaourt -S jdk6-compat
环境配置
#!/bin/bash
# file: env.sh
# cache
export USE_CCACHE=1
export CCACHE_DIR=~/.ccache
# output
export OUT_DIR_COMMON_BASE=~/code/androidcore/output
# alias
alias make='make-3.81'
# java6
export JAVA_HOME=/opt/java6
export PATH=/opt/java6/bin:$PATH
配置USB访问权限:
# file: /etc/udev/rules.d/51-android.rules
# adb protocol on passion (Nexus One)
SUBSYSTEM=="usb", ATTR{idVendor}=="18d1", ATTR{idProduct}=="4e12", MODE="0600", OWNER="<username>"
# fastboot protocol on passion (Nexus One)
SUBSYSTEM=="usb", ATTR{idVendor}=="0bb4", ATTR{idProduct}=="0fff", MODE="0600", OWNER="<username>"
# ...
最终环境
Linux acer 3.13.7-1-ARCH #1 SMP PREEMPT Mon Mar 24 20:06:08 CET 2014 x86_64 GNU/Linux
Python 2.7.6 (default, Feb 26 2014, 12:07:17)
gcc 版本 4.9.0 20140507 (prerelease) (GCC)
GNU Make 3.81
java SE 1.6
编译Android Source
参照 文档 ,下载Android4.2源码。
# 导入环境
. ../env.sh
. build/envsetup.sh
# 设置缓存大小
prebuilts/misc/linux-x86/ccache/ccache -M 50G
# 选择目标
lunch
# 并行编译
make -j4
启动Emulator
# 加载环境
lunch
# 启动
emulator
启动成功,Android版本为4.2.1:
源码修改与调试
考虑从Launcher启动应用程序时,ActivityManagerService
,Launcher
,MainActivity
之间的执行与通信序列如下图。在源码中相应的过程调用或进程通信处加入日志信息,用于分析启动时各部分的耗时。
Android源码修改
以下列出所有需要更改的源码。注释中给出了文件路径、类名、函数名,与添加的语句。添加日志输出(Level为Info,Tag为”PKU”)。
说明:文件ApplicationThreadNative
没有引入Log
类。添加import andriod.util.Log
会发生运行时错误,可能是因为该文件的在类层次中的特殊性。所以我们将在try catch
语句中指明命名空间并进行调用。我们关心的是整个系统启动后的 App启动过程,所以直接吞掉这个在早期才会产生的异常。
/////////////////////////////////////////////////////////////////////////
// file: packages/apps/Launcher2/src/com/android/launcher2/Launcher.java
// 0 Launcher.onClick
Log.i("PKU", "0 shortcut clicked");
/////////////////////////////////////////////////////////////////////////
// file: frameworks/base/core/java/android/app/ActivityManagerNative.java
// 1 ActivityManagerProxy.startActivity
Log.i("PKU","1 START_ACTIVITY_TRANSACTION begin");
Log.i("PKU","1 START_ACTIVITY_TRANSACTION end");
// 5 ActivityManagerProxy.activityPaused
Log.i("PKU","5 ACTIVITY_PAUSED_TRANSACTION begin");
Log.i("PKU","5 ACTIVITY_PAUSED_TRANSACTION end");
// 9 ActivityManagerProxy.attachApplication
Log.i("PKU","9 ATTACH_APPLICATION_TRANSACTION begin");
Log.i("PKU","9 ATTACH_APPLICATION_TRANSACTION end");
/////////////////////////////////////////////////////////////////////////
// file: frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
// 2 ActivityManagerService.startActivity
Log.i("PKU","2 on START_ACTIVITY_TRANSACTION");
// 6 ActivityManagerService.activityPaused
Log.i("PKU","6 on ACTIVITY_PAUSED_TRANSACTION");
// 7 ActivityManagerService.startProcessLocked
Log.i("PKU"<