首页 > 其他分享 >安卓应用启动流程

安卓应用启动流程

时间:2024-09-15 14:04:56浏览次数:1  
标签:调用 java 启动 安卓 源码 Activity 进程 流程

安卓应用启动流程

目录

1 冷启动热启动

Activity启动过程中,一般会牵涉到应用启动的流程。应用启动又分为冷启动热启动

  1. 冷启动:点击桌面图标,手机系统不存在该应用进程,这时系统会重新fork一个子进程来加载Application并启动Activity,这个启动方式就是冷启动。
  2. 热启动:应用的热启动比冷启动简单得多,开销也更低。在热启动中,因为系统里已有该应用的进程,所以系统的所有工作就是将您的 Activity 带到前台。 冷启动是应用完全从0开始启动,涉及到更多的内容,所以就应用冷启动的过程展开讨论。

作者:天才木木木木
链接:https://juejin.cn/post/6844904116561379341
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

2 zygote和SystemServer

在进入应用启动流程前,先简单回顾一下。

zygote是在系统启动后init进程fork出来的。

  • zygote有一个socket,用于接受消息,当有应用申请启动的时候,会通过socket通知zygote进程,其会fork自己来创建应用进程。
  • init过程中,zygoteforkSystemServer进程。

SystemServer是由zygote进程fork出来的第一个进程,其管理着很多重要服务,比如ActivityManagerServicePackageManagerServiceWindowManagerService

3 应用启动流程简述(记得补充)

从用户点击图标开始到应用创建再到第一个Activity启动

4 从点击图标到通知Zygote

4.1 Launcher

  • LauncherAndroid系统启动后,Activity Manager Service (AMS)加载的第一个应用程序
  • Launcher又被称为桌面程序,负责Android桌面的启动和管理
  • 用户使用的应用程序(App)都是通过Launcher来启动的

源码:/packages/apps/Launcher3/src/com/android/launcher3/Launcher.java

Launcher中有这么一段代码,创建桌面快捷方式

其中绑定了点击事件

跟进源码:/packages/apps/Launcher3/src/com/android/launcher3/touch/ItemClickHandler.java

对于App图标来说最终都是调用startAppShortcutOrInfoActivity方法。

而后最终会调用startActivitySafely,这里的launcherLauncher类,所以回到Launcher.java代码。

其中的startActivitySafely会继续往上调用

继承关系:LauncherStatefulActivityBaseDraggingActivityBaseActivityActivity

startActivitySafely是在BaseActivity中实现的AppLauncher的接口方法

源码:/packages/apps/Launcher3/src/com/android/launcher3/views/AppLauncher.java

于是乎流程进入到了Activity.java

4.2 Activity.java

Activity源码位于/frameworks/base/core/java/android/app/Activity.java

startActivity会调用startActivityForResult

startActivityForResult

以下是通义给出的解释:

这段代码是 startActivityForResult 方法的一部分,这个方法用于启动一个 Activity,并期望从该 Activity 获取返回的结果。当目标 Activity 完成后,它会回调当前 ActivityonActivityResult 方法,并附带请求码(requestCode)以及结果数据。

关键点包括:

  • intent 参数是一个 Intent 对象,它包含了要启动的目标 Activity 的信息。
  • requestCode 是一个整型值,当目标 Activity 结束时会通过 onActivityResult 回调传递回来。这有助于识别哪个 Activity 返回了结果。
  • options 参数是可选的 Bundle 对象,可以用来指定 Activity 启动的一些额外选项。

如果当前 Activity 没有父 Activity (mParent == null),则会调用 Instrumentation 类的 execStartActivity 方法来启动新的 Activity。如果 requestCode 大于等于 0,则标记 mStartedActivitytrue,这样可以避免在 Activity 初始化期间的闪烁现象,直到收到启动的 Activity 的结果为止。

如果当前 Activity 有一个父 Activity,则会调用父 Activity 的 startActivityFromChild 方法来启动新的 Activity,同时传递 requestCodeoptions

4.3 Instrumentation.java

源码:/frameworks/base/core/java/android/app/Instrumentation.java

Instrumentation.javaexecStartActivity有两种实现。execStartActivity (带 UserHandle 参数) 方法允许开发者显式地指定用于启动 Activity 的用户。而未带UserHandle参数的方法会使用默认用户启动Activity

public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, String resultWho,
            Intent intent, int requestCode, Bundle options,  UserHandle user )

public ActivityResult execStartActivity(
        Context who, IBinder contextThread, IBinder token, String target,
        Intent intent, int requestCode, Bundle options)

execStartActivity (不带 UserHandle 参数) 为例,红框处为关键代码。

进入到了ActivityTaskManager

4.4 ActivityTaskManager.java

源码:/frameworks/base/core/java/android/app/ActivityTaskManager.java

ActivityTaskManager.getService()能够获取到ActivityTaskManagerService的实例对象。

Singleton是单例模式的对象创建,也就是一个进程中只有一个该对象。

这里的ServiceManager应当对应的是当前进程的ServiceManager的单例,所以这里的调用是LauncherServiceManager单例。

当应用启动的时候AMS会将系统服务注册进进程的ServiceManager里。getService函数是直接从单例的数组中中获取的。

获取到的IBinder是对应Binder的引用信息,可以理解为所需要调用的(在这里为ActivityTaskManagerService)系统服务的引用信息。

而后返回系统服务所提供的服务接口。

为了能够流畅的理解启动流程,在这里不严谨地描述一下Binder机制的作用,具体的Binder机制会在后面的文章中学习。

之后的任务就交给了ActivityTaskManagerService

4.5 ActivityTaskManagerService.java

源码地址:/frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java

startActivityAsUser方法通过ActivityStartControllerobtainStarter方法获取了ActivityStarter对象实例,并调用ActivityStarterexecute方法

4.6 ActivityStarter.java

源码位置/frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java

ActivityStarter中最终会调用RootWindowContainerresumeFocusedTasksTopActivities方法

int execute() {
    //...
    
    res = executeRequest(mRequest);
    
    //...
}
 
private int executeRequest(Request request) {
    //...
  
    // 创建ActivityRecord对象
    final ActivityRecord r = new ActivityRecord.Builder(mService)
            .setCaller(callerApp)
            // ...构造参数
            .build();
    // 调用startActivityUnchecked方法
    mLastStartActivityResult = startActivityUnchecked(...);
    
    //...
}
 
private int startActivityUnchecked(...) {
    //...
    
    // 调用startActivityInner
    result = startActivityInner(...);
    
    //...
}
 
int startActivityInner(...) {
    //...
    
    // 调用RootWindowContainer的resumeFocusedTasksTopActivities方法
    mRootWindowContainer. resumeFocusedTasksTopActivities (...);
    
    //...
}

4.7 RootWindowContainer.java

RootWindowContainerWindowManagerService的主要组成部分之一,是一个管理窗口的容器。

resumeFocusedTasksTopActivities将会调用TaskTaskFragmentPause前台程序,为新的应用程序启动做准备。

源码位置:/frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java

Task.java中的resumeTopActivityUncheckedLocked

Task.java中的resumeTopActivityInnerLocked

TaskFragment.java中的resumeTopActivity

简单总结一下如图

startProcessAsync就将交回给ActivityTaskManagerService.java

4.8 回到ActivityTaskManagerService.java

处理完窗口容器数据以后(核心工作是将前台程序Pause),再次回到了ActivityTaskManagerService

源码地址/frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java

startProcessAsync使用调用ActivityManagerInternalstartProcess方法

这里传入的mAmInternal变量是通过类搜索得到的。

ActivityManagerInternal的实现类是ActivityManagerService,所以这里就相当于给ActivityManagerService发消息。

这里使用的Handler机制是安卓中线程之间的通信方式,两种Service就是在同一进程下的不同进程。

4.9 ActivityManagerService.java

源码地址:/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

startProcess

startProcessLocked

4.10 ProcessList.java

源码地址:/frameworks/base/services/core/java/com/android/server/am/ProcessList.java

由于代码实在太长,这里就摘要一下

startProcessLocked中定义了创建Activity完成后回调的入口点

最终会调用startProcess

startProcess代码主要做了以下事情

  1. 数据隔离:根据系统的配置,可能需要对应用的数据目录进行隔离处理。这涉及到文件系统的挂载操作。
  2. 选择合适的Zygote进程:根据应用的需求选择普通的Zygote进程、Webview Zygote进程或者是App Zygote进程来启动应用。这里是启动App,所以是App Zygote
  3. 启动应用进程:调用不同的方法来启动应用进程,这些方法会根据选择的Zygote类型有所不同。
  4. 异步准备存储目录:如果需要绑定挂载应用存储目录,则异步执行目录的准备工作,以避免阻塞应用启动过程。

4.11 ZygoteProcess.java

源码地址:/frameworks/base/core/java/android/os/ZygoteProcess.java

startViaZygote全是设置参数

然后到zygoteSendArgsAndGetResult

再到attemptZygoteSendArgsAndGetResult,与Zygote的通信就在这里面。

5 Zygote创建Activity进程

Zygote进程是在Android系统启动过程中创建的,创建完成后会通过ZygoteServer来监听消息

5.1 ZygoteServer.java

ZygoteServer监听消息的方法是runSelectLoop

源码地址:/frameworks/base/core/java/com/android/internal/os/ZygoteServer.java

runSelectLoop中会调用ZygoteConnectionprocessCommand

5.2 ZygoteConnection.java

这段代码是 Zygote 进程中的一个关键部分,用于处理来自客户端的命令,以启动新的应用程序进程。

源码地址:/frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java

  1. 调用 forkAndSpecializeforkSimpleApps
    pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid, ..., parsedArgs.mAppDataDir);
    ...
    Runnable result = Zygote.forkSimpleApps(argBuffer, zygoteServer.getZygoteSocketFileDescriptor(), ..., parsedArgs.mNiceName);
    
    调用 forkAndSpecializeforkSimpleApps 方法来创建新的进程,并对其进行配置。
  2. 处理子进程和父进程
    if (pid == 0) {
        // 在子进程中
        ...
        return  handleChildProc (parsedArgs, childPipeFd, parsedArgs.mStartChildZygote);
    } else {
        // 在父进程中
        ...
        handleParentProc(pid, serverPipeFd);
        return null;
    }
    
    根据 fork() 的返回值来区分父进程和子进程,并分别处理。

handleParentProc中,会将创建好的进程pid发回给请求方(ActivityManagerService)。

handleChildProc中会调用ZygoteInit.``zygoteInit来初始化应用程序

5.3 ZygoteInit.java

Zygote进程的初始化逻辑也是在ZygoteInit中,这里fork创建的进程也是一个Zygote进程,所以也要进行ZygoteInit

源码地址:/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

5.4 RuntimeInit.java

源码地址:/frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

进入到findStaticMain,这个方法中,将通过反射找到之前传入的entryPoint(android.app.ActivityThread),然后调用其main方法。

到这里Zygote进行fork子进程的流程已经结束了,接下来将交给ActivityThread进行app的实例创建。

6 初始化Application实例

6.1 ActivityThread.java

源码地址:/frameworks/base/core/java/android/app/ActivityThread.java

attach方法如下

这里的调用栈就不深入了,接下来会调用到bindApplication方法

这里的HActivityThread的一个内置类

最终调用handleBindApplication,进行app实例化。

在实例化中调用的是InstrumentationnewApplication方法。

每个Activity都持有一个Instrumentation,它是由ActivityThread创建出来的一个单例。 这个类就是完成对ApplicationActivity初始化和生命周期的工具类,ActivityThread要创建或执行Activity生命周期方法时,都需要通过Instrumentation来进行具体的操作。

调用OnCreate函数。

至此应用启动的流程就算基本结束了。

7 小结

实际上应用启动后续还需要加载第一个Activity并将其带到前台显示,但由于都是类似的流程,就不再过多赘述了。主要从应用启动流程的学习可以对ZygoteAMS有一些更深入的了解。在启动流程中遇到了BinderHandlerLooper等安卓重要的机制,甚至还涉及到了反射,对后面这些机制的学习也有很大的帮助。

8 引用

Android桌面Launcher源码浅析 - 博客园
Android应用启动流程分析 - 稀土掘金
Android应用程序启动源码浅析-(三万字长文慎点&Android14) - 博客园
Android Application 启动流程分析及其源码调用探究 - 稀土掘金
Android之ServiceManager服务 - 博客园

标签:调用,java,启动,安卓,源码,Activity,进程,流程
From: https://www.cnblogs.com/Joooook/p/18415200

相关文章

  • 安卓签名校验机制
    安卓签名校验机制目录1V1方案1.1V1方案的安全性2V2方案2.1摘要计算过程2.2防回滚绕过3V3方案4V4方案5签名实践5.1keytool生成密钥库5.2jarsigner5.3apksigner6引用安卓的签名校验机制共有三代。9.0以上的系统会判断apk是否使用到V3版本的签......
  • 基于微信小程序/安卓APP的饮食健康服务系统设计与实现
    ......
  • 基于微信小程序/安卓APP的计算机课程学习系统设计与实现
    ......
  • 安卓系统启动流程解析
    安卓系统启动流程目录1init阶段1.1FirstStage1.2SELinuxSetup1.3SecondStage2init.rc的配置3Zygote的启动3.1app_process3.2Zygoteinit.java4SystemServer5总结6引用光看分析文章还是不够的,还是要和实践结合。1init阶段init命令的入口是init......
  • 安卓架构
    安卓架构目录1Linux内核层2硬件抽象层HAL3NativeC/C++库&&AndroidRuntime4JavaFramework层5SystemApps层1Linux内核层Android平台的基础是Linux内核。例如,ART依靠Linux内核来执行底层功能。Linux内核的安全机制为Android提供了相应的保障,也......
  • Nacos下载和启动
    Nacos是什么?一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台下载https://github.com/alibaba/nacos/releases/tag/2.1.1启动将下载好的Nacos解压缩,然后到bin目录下打开cmd输入指令:startup.cmd-mstandalone出现下图,表示启动成功:访问Nacos输......
  • nginx 安装服务后,启动报:An attempt was made to access a socket in a way forbidden
    1、nginx1.18.0安装服务成功后,启动服务的时候,一闪直接报错:2、查看Nginx的日志error.log发现启动一次报一条错,并且都是一样的:2024/09/1414:42:18[emerg]6852#6280:bind()to0.0.0.0:80failed(10013:Anattemptwasmadetoaccessasocketinawayforbiddenbyit......
  • 在k8s中,客户端访问服务的链路流程,ingress--->service--->deployment--->pod--->container
                                                                图片来源:自己画的ingress是一个API资源。客户端访问ingress的不同urlingress给客户端返回不同的服务。就和nginx反向代理服务器一样。根据......
  • 拼多多商家电话采集软件操作流程分享
    以下是拼多多商家电话采集软件的一般操作流程:一、前期准备选择软件:从正规渠道选择可靠的拼多多商家电话采集软件。部分软件可能需要付费购买或获取授权,确保使用的软件来源合法、安全。了解软件要求:查看软件的系统要求,如操作系统版本、内存需求等,确保你的设备满足运行条件。同......
  • Activity启动流程
    启动一个Activity,通常有两种情况:第一种是不同进程的的根activity,比如laucnher启动app;第二种是同进程内部启动activity。这两种情况的启动流程类似,大致分为以下三个步骤:调用进程的activity收集好信息后,向system_server进程的ActivityTaskManagerSrvice服务发起请求。ATMS向PKMS寻找......