Android源码之Application与Activity创建时机分析

news2024/10/6 5:55:26

前言

我们知道App进程是由SystemServer启动的Android启动流程
那App对应的Application以及第一个Activity又是如何创建的呢?

源码分析(API 30为例)

我们从ActivityThread.main函数入手;

 public static void main(String[] args) {
   		...
        ActivityThread thread = new ActivityThread();
        thread.attach(false, startSeq);
		...

    }

首先会创建一个ActivityThread对象并调用attach方法;

 // ActivityThread.attach方法
     private void attach(boolean system, long startSeq) {
        sCurrentActivityThread = this;
        mSystemThread = system;
        if (!system) {
     
            final IActivityManager mgr = ActivityManager.getService();
            try {
                mgr.attachApplication(mAppThread, startSeq);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }

        } else {
          	...
        }
		...
    }

由于传入的system参数为false,我们只看if (!system) 里的代码执行逻辑:

 final IActivityManager mgr = ActivityManager.getService();
            try {
                mgr.attachApplication(mAppThread, startSeq);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }

我们知道IActivityManager是AMS的代理,因此attachApplication方法具体实现在ActivityManagerService中;

	// ActivityManagerService.attachApplication
    public final void attachApplication(IApplicationThread thread, long startSeq) {
        if (thread == null) {
            throw new SecurityException("Invalid application interface");
        }
        synchronized (this) {
            int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            attachApplicationLocked(thread, callingPid, callingUid, startSeq);
            Binder.restoreCallingIdentity(origId);
        }
    }

attachApplication会调用attachApplicationLocked方法;

// ActivityManagerService.attachApplicationLocked
   private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
            int pid, int callingUid, long startSeq) {
           ...
			//1.获取ActiveInstrumentation对象
          final ActiveInstrumentation instr = app.getActiveInstrumentation();
            if (instr != null) {
            	//通过PMS获取ApplicationInfo信息
                notifyPackageUse(instr.mClass.getPackageName(),
                                 PackageManager.NOTIFY_PACKAGE_USE_INSTRUMENTATION);
            }
            ApplicationInfo appInfo = instr != null ? instr.mTargetInfo : app.info;
          	
            if (app.isolatedEntryPoint != null) {
               	...//这里没有isolatedEntryPoint赋值的地方,因此不会走
            } else if (instr2 != null) {
            	//2.此处thread即为ApplicationThread对象,因此会回调ApplicationThread.bindApplication方法
                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);
            } else {
       			...
            }
     		...
        if (normalMode) {
            try {
            	// 3.这里会做Activity启动
                didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
            } catch (Exception e) {
                Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
                badApp = true;
            }
        }

       ...
    }

可以看到attachApplicationLocked方法主要做了以下几件事:

  • PMS通信,获取ApplicationInfo对象信息,即PMS解析APP包时缓存的应用信息;【详细流程可以参考浅谈Android PMS解析APP信息流程】
  • 回调ApplicationThread.bindApplication方法,实际上就是启动Application;
  • 执行mAtmInternal.attachApplication方法,实际上就是启动Activity;

我们首先看下thread.bindApplication方法:

    public final void bindApplication(String processName, ApplicationInfo appInfo,
                ProviderInfoList providerList, ComponentName instrumentationName,
                ProfilerInfo profilerInfo, Bundle instrumentationArgs,
                IInstrumentationWatcher instrumentationWatcher,
                IUiAutomationConnection instrumentationUiConnection, int debugMode,
                boolean enableBinderTracking, boolean trackAllocation,
                boolean isRestrictedBackupMode, boolean persistent, Configuration config,
                CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
                String buildSerial, AutofillOptions autofillOptions,
                ContentCaptureOptions contentCaptureOptions, long[] disabledCompatChanges) {
			...
            AppBindData data = new AppBindData();
            data.processName = processName;
            data.appInfo = appInfo;
            data.providers = providerList.getList();
            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.autofillOptions = autofillOptions;
            data.contentCaptureOptions = contentCaptureOptions;
            data.disabledCompatChanges = disabledCompatChanges;
            sendMessage(H.BIND_APPLICATION, data);
        }

就是构造AppBindData对象,把拿到的app数据保存起来,然后调用HandlerH发送BIND_APPLICATION消息;

 public void handleMessage(Message msg) {
            switch (msg.what) {
                case BIND_APPLICATION:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
                    AppBindData data = (AppBindData)msg.obj;
                    handleBindApplication(data);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                    ...
                  }

紧接着会调用handleBindApplication方法;

   private void handleBindApplication(AppBindData data) {
			...
            app = data.info.makeApplication(data.restrictedBackupMode, null);
       		...
    
    }

handleBindApplication会调用data.info.makeApplication方法

		//LoadedApk.makeApplication
    public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
		...
		//1.mInstrumentation.newApplication
       	mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
            appContext.setOuterContext(app);
        } catch (Exception e) {
			...
        }
        mActivityThread.mAllApplications.add(app);
        mApplication = app;

        if (instrumentation != null) {
            try {
            	//2. instrumentation.callApplicationOnCreate
                instrumentation.callApplicationOnCreate(app);
            } catch (Exception e) {
               	...
            }
        }

    
        return app;
    }

LoadedApk.makeApplication方法中,我们主要关注以下两个方法:

  1. mActivityThread.mInstrumentation.newApplication( cl, appClass, appContext);首先会通过反射创建出Application对象,然后调用attachBaseContext方法,因此attachBaseContext方法是Application中调用的最早的方法;

  2. instrumentation.callApplicationOnCreate(app)中会调用Application.onCreate方法;

至此,Application就完成创建以及onCreate方法的调用;

Application创建时序图Application创建时序图

Activity启动

Application创建并启动完毕,我们再回到ActivityManagerService.attachApplicationLocked方法中,
重点关注下

 mAtmInternal.attachApplication(app.getWindowProcessController());

会调用ActivityTaskManagerInternal.attachApplication方法,如下:

	//ActivityTaskManagerInternal.attachApplication
	 public abstract boolean attachApplication(WindowProcessController wpc);

很明显是抽象方法,对应的实现类为ActivityTaskManagerService

//ActivityTaskManagerService.attachApplication
  public boolean attachApplication(WindowProcessController wpc) throws RemoteException {
            synchronized (mGlobalLockWithoutBoost) {
              	...
                }
                try {
                    return mRootWindowContainer.attachApplication(wpc);
                } finally {
                    Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
                }
            }
        }

会调用mRootWindowContainer.attachApplication方法;

	//RootWindowContainer.attachApplication
  boolean attachApplication(WindowProcessController app) throws RemoteException {
        final String processName = app.mName;
        boolean didSomething = false;
        for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
         ...
         RootWindowContainer::startActivityForAttachedApplicationIfNeeded, this,
                    PooledLambda.__(ActivityRecord.class), app, stack.topRunningActivity());
            stack.forAllActivities(c);
            c.recycle();
          	...
        return didSomething;
    }

接着调用startActivityForAttachedApplicationIfNeeded方法

 private boolean startActivityForAttachedApplicationIfNeeded(ActivityRecord r,
            WindowProcessController app, ActivityRecord top) {
 		...
        try {
            if (mStackSupervisor.realStartActivityLocked(r, app, top == r 
              	...
            }
        } catch (RemoteException e) {
            Slog.w(TAG, "Exception in new application when starting activity "
                    + top.intent.getComponent().flattenToShortString(), e);
            mTmpRemoteException = e;
            return true;
        }
        return false;
    }

mStackSupervisor.realStartActivityLocked这句代码是不是很熟悉,我们对照之前分析Activity的启动时序图:
Activity启动时序图
这里就对应时序图中的第14步骤,后续层层调用,最终还是交由ActivityThread调用handleLaunchActivityperformLaunchActivity完成Activity的启动!

结语

如果以上文章对您有一点点帮助,希望您不要吝啬的点个赞加个关注,您每一次小小的举动都是我坚持写作的不懈动力!ღ( ´・ᴗ・` )

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/530175.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第八章结构型模式—装饰者模式

文章目录 装饰者模式解决的问题概念结构 案例使用装配者进行改进 使用场景JDK源码分析 静态代理和装饰者的区别 结构型模式描述如何将类或对象按某种布局组成更大的结构,有以下两种: 类结构型模式:采用继承机制来组织接口和类。对象结构型模式…

【Linux】volatile | SIGCHLD | 多线程概念

文章目录 1. volatile编译器优化 2.SIGCHLD信号验证SIGCHLD的存在 3. 多线程多线程概念理解概念什么是多线程调度成本低局部性原理 什么叫做进程 1. volatile 在vscode中,创建signal.c文件 故意在while中没有写代码块,让编译器认为在main中,…

爬虫+可视化 | 动态展示2020东京奥运会奖牌世界分布

文章目录 前言1. 导入模块2. 数据爬取3. 地图展示 3.1 2020东京奥运会奖牌数世界分布3.2 2020东京奥运会金牌世界分布3.3 2020东京奥运会金、银、铜世界分布 前言 2020东京奥运会已落下帷幕,中国军团共获得88枚奖牌,其中38枚金牌、32枚银牌、18枚铜牌…

基于RV1126平台检测模型全流程部署(附工程)

基于RV1126平台检测模型全流程部署 模型训练ONNX导出ONNX模型简化Python部署C部署 本工程地址:https://github.com/liuyuan000/Rv1126_YOLOv5-Lite 模型训练 这次选用的是方便部署的YOLOv5 Lite模型,是一种更轻更快易于部署的YOLOv5,主要摘…

嵌入式通信协议【Modbus】modbus RTU的帧格式

modbus的帧格式 设备地址功能代码数据格式CRC校验LCRC校验H8bit8bitN*8bit8bit8bit 1 主机对从机单个寄存器写数据操作(0x06) 从机地址功能代码数据格式(数据地址)数据格式(数据)CRC校验LCRC校验H010600…

动态规划:万变不离其宗,带你吃透股票系列问题

前言: 对于买卖股票问题而言,最关键的是我们对问题的处理方式(对于每一天而言,我们应该描述当天买入卖出还是只描述每天股票的只有或者不持有的状态呢?)我们应该描述每天股票是否持有的状态,因…

中科院发布多模态 ChatGPT,图片、语言、视频都可以 Chat ?中文多模态大模型力作

作者 | 小戏、ZenMoore 在 GPT-4 的发布报道上,GPT-4 的多模态能力让人印象深刻,它可以理解图片内容给出图片描述,甚至能在图片内容的基础上理解其中的隐喻或推断下一时刻的发展。无疑,面向所谓的 AGI(通用人工智能&am…

数据结构初阶(1)(一些学习数据结构所需掌握的先导知识:包装类、装箱与拆箱、泛型、List简介)

包装类 基本数据类型和包装类是Java中处理数据的两种不同方式。 基本数据类型(Primitive Types): Java的基本数据类型是直接存储数据的原始类型,包括以下8种类型: byte:1字节,用于表示整数 …

IEEE编写LaTeX时在作者后添加ORCID标志及链接(简单方案,一行代码)

IEEE的一些论文,如Trans系列惯例是要在作者后添加ORCID标志及链接,但是其How to里面没有相关latex代码案例。 1. 可以用但复杂的方案 CSDN中不少博主也给出了挺漂亮但是比较复杂的方案,如这个的一大串: \documentclass[letters…

Linux文本之awk编译器

一、awk介绍 1)awk概述 AWK 是一种用于处理文本的编程语言工具。AWK 在很多方面类似于 shell 编程语言,尽管 AWK 具有完全属于其本身的语法。它的设计思想来源于 SNOBOL4 、sed 、Marc Rochkind设计的有效性语言、语言工具 yacc 和 lex ,当…

尚硅谷大数据技术NiFi教程-笔记02【NiFi(使用案例,同步文件、离线同步mysql数据到hdfs、实时监控kafka数据到hdfs)】

尚硅谷大数据技术-教程学习路线-笔记汇总表【课程资料下载】 视频地址:尚硅谷大数据NiFi教程(从部署到开发)_哔哩哔哩_bilibili 尚硅谷大数据技术NiFi教程-笔记01【NiFi(基本概念、安装、使用)】尚硅谷大数据技术NiFi教…

探索古文明,玛雅文明衰落的原因

说起玛雅文明,大家在各种小说或者电影中或多或少的都有听说过,那么这个文明到底是怎么一回事呢?今天老铁就带大家好好的了解下。 玛雅文明存在的时间大致是在公元前2000年至公元1500年之间,这个文明见证了中美洲地区的一段辉煌的…

Cefsharp109.1.110(winfrom)最新支持H264-MP3-MP4功能体验,导出pdf和下载方法有变调整

最新版的支持H264版本(109.1.11,109.1.18)5154分支,也是win7/8/8.1最后一个支持版本 此贴仅分项版本变化和注意事项,本篇文章不提供dll编译文件,有需要单独联系,仅供学习参考 109版本体验测试(音频和视频功能),版本较100.0.230变化提醒及注意变更的内容。 上视频支…

C++每日一练:难题-大数加法

文章目录 前言一、题目二、代码及思路总结 前言 这题好像是指定了C,那就用C来做嘛,确实在C/C中一不小心就超出范围了,说实在的,C这个语言有时候真的很让人无语。很显然这是要用字符串来计算了。这题坑比较多,笔者这也…

数据库使用自增ID好还是UUID好?为什么?

数据库使用自增ID好还是UUID好?为什么? 答: 自增ID 优点: 数字类型,占用空间小数据库自动增量排序,对检索有利,读写速度快(聚簇索引的优势)系统编码过程中&#xff0…

知识推理学习笔记

OWL本体语言 基于RDF语法,最规范,最严谨,表达能力最强 一 语法 三元组 二 逻辑基础 描述逻辑:基于对象的知识表示的形式化,是一阶谓词逻辑的一个可判定子集 三 描述逻辑系统 一个描述逻辑包含4个基本组成部分 …

【Python数据存储】零基础也能轻松掌握的学习路线与参考资料

Python是一种高级编程语言,被广泛应用于数据科学中。数据存储是数据科学中至关重要的一环,因为人们需要将收集到的数据保存在一些地方。Python中的数据存储有很多种,因此在学习过程中需要明确自己的需求,掌握不同数据存储方式的优…

深入理解 python 虚拟机:多继承与 mro

深入理解 python 虚拟机:多继承与 mro 在本篇文章当中将主要给大家介绍 python 当中的多继承和 mro,通过介绍在多继承当中存在的问题就能够理解在 cpython 当中引入 c3 算法的原因了,从而能够帮助大家更好的了理解 mro 。 python 继承的问题…

【Linux】shell编程之—函数

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一、概述二、函数的查看和删除1.查看 declare2.删除 declare 三、函数的返回值1.return 返回值2.echo 返回值 四、函数的参数传入与变量范围五、函数的应用1.阶乘2.…

十五、Gateway网关

目录 Zuul网关和gateway网关的区别: Gateway路由配置 1、新建服务网关项目,并在项目pom文件中引入gateway网关依赖 2、在application.yml配置gateway 3、如果不用配置的方式配置gateway路由,还可以通过代码的形式配置 4、启动网关服务&…