文章目录
- APP启动优化概述
- APP启动流程
- 点击图片启动APP的过程
- 启动触发
- Zygote 与应用进程创建
- Zygote
- 进程的创建
- 应用进程初始化
- Application
- Activity 启动与显示
- 优化启动时黑白屏现象
- 可优化的阶段
- Application阶段
- 相关优化
- Activity阶段
- 数据加载阶段
- Framework学习系列文章
APP启动优化概述
-
优化方向
-
启动优化流程
APP启动流程
点击图片启动APP的过程
这张图展示了 Android 系统中应用程序(App)启动的完整流程,涉及多个关键组件及其交互
启动触发
- Launcher:用户在手机桌面点击应用图标,Launcher(桌面启动器)响应点击事件。通过Binder机制向service_manager查询ActivityTaskManagerService(ATMS,活动管理服务)服务。
- service_manager 和 Binder:service_manager是系统中管理服务的组件,通过Binder这种进程间通信机制,Launcher获取到AMS服务的相关信息。Binder是 Android 系统中实现进程间通信的重要机制,提供高效稳定的通信能力。
- system_server:system_server进程是 Android 系统核心进程,包含ActivityManagerService和WindowManagerService等重要服务。AMS负责管理应用程序的生命周期、Activity 的启动与切换等;WindowManagerService负责窗口的管理和显示等。
具体代码如下:
- Launcher调用Activity.startActivity启动Activity
Activity.java
@Override
public void startActivity(Intent intent, @Nullable Bundle options) {
...
if (options != null) {
startActivityForResult(intent, -1, options);
} else {
startActivityForResult(intent, -1);
}
}
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
...
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken,this,intent, requestCode, options);
...
}
- Instrumentation.execStartActivity调用
Instrumentation.java
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
...
// ActivityTaskManagerService
int result = ActivityTaskManager.getService().startActivity(whoThread,who.getBasePackageName(),
who.getAttributionTag(),intent,intent.resolveTypeIfNeeded(who.getContentResolver()),
token,target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);
...
}
- ActivityTaskManagerService.startActivityAsUser
ActivityTaskManagerService::startActivity调用startActivityAsUser
ActivityTaskManager.getService()其实返回的是ATMS的binder
final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);
return IActivityTaskManager.Stub.asInterface(b);
至此,startActivity 的工作重心成功地从 应用进程(app) 转移到了系统进程(system_service) 的 ATMS 中。
private int startActivityAsUser(IApplicationThread caller, String callingPackage,
@Nullable String callingFeatureId, Intent intent, String resolvedType,
IBinder resultTo, String resultWho, int requestCode, int startFlags,
ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) {
assertPackageMatchesCallingUid(callingPackage);
enforceNotIsolatedCaller("startActivityAsUser");
userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");
// getActivityStartController().obtainStarter是ActivityStarter
return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
.setCaller(caller)
.setCallingPackage(callingPackage)
.setCallingFeatureId(callingFeatureId)
.setResolvedType(resolvedType)
.setResultTo(resultTo)
.setResultWho(resultWho)
.setRequestCode(requestCode)
.setStartFlags(startFlags)
.setProfilerInfo(profilerInfo)
.setActivityOptions(bOptions)
.setUserId(userId)
.execute();
}
- ActivityStarter.execute
ActivityStarter.java
int execute() {
...
res = executeRequest(mRequest);
...
}
private int executeRequest(Request request) {
...
ActivityRecord sourceRecord = null;
ActivityRecord resultRecord = null;
...
mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
request.voiceInteractor, startFlags, true /* doResume */, checkedOptions, inTask,
restrictedBgActivity, intentGrants);
...
return mLastStartActivityResult;
}
- ActivityStarter.startActivityUnchecked
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, Task inTask,
boolean restrictedBgActivity, NeededUriGrants intentGrants) {
....
try {
...
result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
startFlags, doResume, options, inTask, restrictedBgActivity, intentGrants);
} finally {
...
}
postStartActivityProcessing(r, result, startedActivityRootTask);
return result;
}
- ActivityStarter.startActivityInner
int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, Task inTask,
boolean restrictedBgActivity, NeededUriGrants intentGrants) {
setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
voiceInteractor, restrictedBgActivity);
...
// RootWindowContainer
mRootWindowContainer.resumeFocusedTasksTopActivities(
mTargetRootTask, mStartActivity, mOptions, mTransientLaunch);
...
return START_SUCCESS;
}
- RootWindowContainer.resumeFocusedTasksTopActivities
boolean resumeFocusedTasksTopActivities(
Task targetRootTask, ActivityRecord target, ActivityOptions targetOptions,
boolean deferPause) {
...
boolean result = false;
if (targetRootTask != null && (targetRootTask.isTopRootTaskInDisplayArea()
|| getTopDisplayFocusedRootTask() == targetRootTask)) {
// Task
result = targetRootTask.resumeTopActivityUncheckedLocked(target, targetOptions,
deferPause);
}
...
return result;
}
- Task.resumeTopActivityInnerLocked
Task.java
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
...
if (mResumedActivity != null) {
pausing |= startPausingLocked(userLeaving, false , next); // 这里会调用Launcher的pause
}
...
// ActivityTaskSupervisor
mStackSupervisor.startSpecificActivity(next, true, false);
...
}
- ActivityStackSupervisor::startSpecificActivity
ActivityStackSupervisor会判断进程是否存在,存在则调用realStartActivityLocked,不存在则调用startProcessAsync创建其实是通过Zygote来fork创建进程,进程创建后还是会调用realStartActivityLocked的。
Zygote 与应用进程创建
Zygote
Zygote:AMS通过Zygote进程来创建新的应用程序进程(App)。Zygote 是 Android 系统中一个特殊的进程,是所有 Java 应用程序进程的孵化器,它在系统启动时就已启动并处于就绪状态。Zygote 通过fork系统调用创建新的应用进程,新进程会继承 Zygote 进程的一些初始化状态,提高应用启动效率。
进程的创建
来看看mService.startProcessAsync
- ActivityManagerInternal.startProcess()
/**
* Activity manager local system service interface.
*/
public abstract class ActivityManagerInternal {
/** Starts a given process. */
// 调用的是ActivityManagerService.LocalService.startProcess()--》ActivityManagerService.startProcessLocked
public abstract void startProcess(String processName, ApplicationInfo info,
boolean knownToBeDead, boolean isTop, String hostingType, ComponentName hostingName);
}
- ActivityManagerService.startProcessLocked
/**
* Process management.
*/
final ProcessList mProcessList;
@GuardedBy("this")
final ProcessRecord startProcessLocked(String processName,
ApplicationInfo info, boolean knownToBeDead, int intentFlags,
HostingRecord hostingRecord, int zygotePolicyFlags, boolean allowWhileBooting,
boolean isolated, boolean keepIfLarge) {
// ProcessList,最终调用的是ProcessList.startProcess()-->Process.start
return mProcessList.startProcessLocked(processName, info, knownToBeDead, intentFlags,
hostingRecord, zygotePolicyFlags, allowWhileBooting, isolated, 0 /* isolatedUid */,
keepIfLarge, null /* ABI override */, null /* entryPoint */,
null /* entryPointArgs */, null /* crashHandler */);
}
- Process.start
/**
* State associated with the zygote process.
*/
public static final ZygoteProcess ZYGOTE_PROCESS = new ZygoteProcess();
public static ProcessStartResult start(@NonNull final String processClass,
@Nullable final String niceName,
int uid, int gid, @Nullable int[] gids,
int runtimeFlags,
int mountExternal,
int targetSdkVersion,
@Nullable String seInfo,
@NonNull String abi,
@Nullable String instructionSet,
@Nullable String appDataDir,
@Nullable String invokeWith,
@Nullable String packageName,
int zygotePolicyFlags,
boolean isTopApp,
@Nullable long[] disabledCompatChanges,
@Nullable Map<String, Pair<String, Long>>
pkgDataInfoMap,
@Nullable Map<String, Pair<String, Long>>
whitelistedDataInfoMap,
boolean bindMountAppsData,
boolean bindMountAppStorageDirs,
@Nullable String[] zygoteArgs) {
return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, packageName,
zygotePolicyFlags, isTopApp, disabledCompatChanges,
pkgDataInfoMap, whitelistedDataInfoMap, bindMountAppsData,
bindMountAppStorageDirs, zygoteArgs);
}
- ZygoteProcess.start
ZygoteProcess 最核心的作用是借助与 Zygote 进程的通信,创建新的应用进程
public final Process.ProcessStartResult start(...) {
return startViaZygote(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/ false,
packageName, zygotePolicyFlags, isTopApp, disabledCompatChanges,
pkgDataInfoMap, allowlistedDataInfoList, bindMountAppsData,
bindMountAppStorageDirs, zygoteArgs);
}
会通过LocalSocket与Zygote建立socket连接,沟通Zygote fork进程
- ZygoteConnection.forkAndSpecialize
这个时候还是在.cpp中执行,fork子进程,native方法,内部实现就是c语言的fork函数调用。
- ZygoteConnection.handleChildProc
ZygoteConnection.java这个时候跑到java,这里是子进程的代码了,
在这个函数中会调用ZygoteInit
- ZygoteInit.ZygoteInit
ZygoteInit.java
- nativeZygoteInit
AndroidRuntime.cpp
- ProcessState构造创建Binder
ProcessState.cpp
构造ProcessState时就会调用open_driver(“/dev/binder”),打开binder驱动设备,然后通过mmap向binder驱动申请空间。
mmap时,会申请BINDER_VM_SIZE大小的空间,不到1M,1M减2个内存页的大小。
然后接着onZygoteInit会调用proc->processThreadPool()启动binder线程池,默认最大线程数为15。 - RuntimeInit.findStaticMain
与Zygote通过socket通信时,会传参数"android.app.ActivityThread"过来,通过findStaticMain定位到ActivityThread.main。
这样fork进程后会跳转到新进程的main入口,就是ActivityThread.main函数。
应用进程初始化
- ActivityThread:应用进程创建后,首先执行ActivityThread.main()方法,这是应用程序主线程(UI 线程)的入口。接着依次调用AT.attach()和AT.bindApplication()方法,完成主线程与系统的绑定以及应用程序的初始化相关操作 。
ActivityThread.java
public static void main(String[] args) {
...
Looper.prepareMainLooper();
...
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
...
Looper.loop();
...
}
private void attach(boolean system, long startSeq) {
final IActivityManager mgr = ActivityManager.getService();
try {
mgr.attachApplication(mAppThread, startSeq);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
ActivityManagerService.java
private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
int pid, int callingUid, long startSeq) {
...
// 发送MH.BIND_APPLICATION的Message,在Handler中调用了Application的onCreate
thread.bindApplication(processName, appInfo, providerList,
instr2.mClass,
profilerInfo, instr2.mArguments,
instr2.mWatcher,
instr2.mUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.isPersistent(),
new Configuration(app.getWindowProcessController().getConfiguration()),
app.compat, getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, autofillOptions, contentCaptureOptions,
app.mDisabledCompatChanges);
...
// 这里会最终调用到ActivityStackSupervisor.realStartActivityLocked
didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
...
}
- realStartActivityLocked会调用到ActivityThread.performLaunchActivity()
进程创建后,开始启动Activity
ActivityThread.java
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
// 创建Context,Context:初始化过程中会构建Context(上下文),它是应用程序环境的抽象类,提供了应用程序运行所需的各种信息和操作接口,如资源访问、系统服务获取等。
ContextImpl appContext = createBaseContextForActivity(r);
...
//反射创建Activity
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
...
// AMS通过反射创建APP的Application对象,调用Application的attach函数,这个其实是Application.attachBaseContent(),然后才是调用Application.onCreate()方法,Application是应用程序全局的一个基类,可用于在应用生命周期内保存全局状态和进行一些初始化操作
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
...
// 调用Activity.attach
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback,
r.assistToken);
...
activity.setTheme(theme);
...
// 调用Activity.onCreate
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
}
Application
如图:
createApplContext创建Context,
newApplication是通过反射创建Application对象app并会调用attachBaseContext,
callApplicationOnCreate则是调用onCreate,
如图:
newApplication中是调用的反射创建Application,然后调用attachBaseContext
ApplicationThread.scheduleTransaction,调用ActivityThread.handleLaunchActivity
Activity 启动与显示
- Activity 启动:ActivityThread中performLaunchActivity()方法先创建Application后再启动Activity。先调用Activity.onCreate()方法创建Activity实例,完成Activity的初始化工作,如设置布局等。
- 设置布局与关联窗口:通过Activity.setContentView()设置Activity的布局文件。然后调用Activity.onResume()方法,此时AMS将Activity与WindowManagerService进行关联,完成窗口的创建和显示相关操作,最终将应用界面展示给用户。
优化启动时黑白屏现象
从启动到显示应用APP的首页过程经历如下过程:
这过程默认是显示黑白屏或是背景图的。
可优化的阶段
Application阶段
上面的阶段中,从attachBaseContent开始都是可以优化的阶段。
注意Provider是在onCreate之后,如下图:
makeApplication中会调用Application的onCreate的,然后installContentProviders才会调用。
相关优化
- 4.x 之前的 multidex 加载优化:在早期 Android 版本(4.x 之前),应用如果包含多个 dex 文件(multidex),需要特殊的加载优化策略,因为当时系统对多 dex 支持不完善。
- 加固热修复导致延迟:应用经过加固和热修复处理后,在执行 attachBaseContext 时可能会出现延迟情况,这是因为加固和热修复操作增加了额外的代码加载和处理逻辑。
- 开源库中的 Provider 初始化:很多开源库会使用 Content Provider 来提供数据共享等功能,这里需要对其进行初始化。
- 自己项目的 provider 初始化:项目中自定义的 Content Provider 也需要在此步骤进行初始化,确保其能够正常工作。
- Application::onCreate:优化最大的部分为异步、按需加载、懒加载优化。通过异步加载和按需、懒加载机制,可以避免在应用启动时一次性加载过多资源,从而加快应用启动速度,提升用户体验。
Activity阶段
- Activity::onCreate
- XML 文件解析,反射:Android 通过解析布局的 XML 文件来创建 View,这个过程会用到反射机制实例化 XML 中定义的 View 对象。
- 异步并发构建 Viewtree:为加快构建速度,可采用异步并发方式构建 View 树,避免主线程阻塞,提升用户体验。
- View构建
- 将 Inflate 过程最大异步化:布局填充(Inflate)是将 XML 布局文件转化为 View 对象的过程,将其异步化,能减少主线程负载,防止 ANR(应用无响应)。
- 利用 X2C 解决加载速度:X2C(XML to Java Class)技术可将 XML 布局转换为 Java 代码,减少解析 XML 的开销,加快 View 的加载速度。
- View显示
- View 的度量布局和显示:通过正确的测量(Measure)、布局(Layout)和绘制(Draw)流程,确保 View 能正确显示在屏幕上。
- 层级优化:减少 View 层级嵌套,避免过度复杂的布局结构,降低绘制和渲染成本。
- 布局优化:精简布局,合理使用布局容器,如用 ConstraintLayout 替代嵌套的 LinearLayout 等,提升布局渲染效率。
数据加载阶段
- 数据预加载:在用户触发数据展示操作前,提前加载数据。比如在应用启动时或进入某个页面之前,提前加载该页面可能用到的数据,减少用户等待时间,提升响应速度。
- 数据缓存机制:将已加载的数据存储在缓存中(如内存缓存、磁盘缓存 ),当再次需要相同数据时,优先从缓存读取,避免重复从原始数据源获取,降低网络请求或磁盘读取开销,加快数据展示速度。
- 显示数据加载优先级调度:根据 UI 界面中不同数据展示区域的重要性,设置数据加载优先级。例如,先加载屏幕可见区域的数据,后加载不可见区域的数据;或者优先加载用户更关注的关键信息数据,确保重要数据优先展示,提升用户体验。
Framework学习系列文章
Android Framework学习一:系统框架、启动过程
Android Framework学习二:Activity创建及View绘制流程
Android Framework学习三:zygote
Android Framework学习四:APP速度优化
Android Framework学习五:APP启动过程原理及速度优化
作者:帅得不敢出门