Android Application启动流程

news2024/12/26 10:45:56

详细流程分析

从 ActivityThread.java 的main方法开始看;

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

进入attach方法;

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

非系统应用流程,根据 getSeervice和捕获的RemoteException可以断定,此处在使用Binder进行远程接口调用。 转身看下mAppThread是什么?

final ApplicationThread mAppThread = new ApplicationThread();
​
private class ApplicationThread extends IApplicationThread.Stub {
    //批量的schedule*接口,比如scheduleReceiver、scheduleCreateService等
    public final void schedule*
    
    //TODO 关键方法
    public final void bindApplication(some args){}//1
    
    //一堆dump方法,比如dumpMemory、dumpActivity等
    
}

可以看到,ApplicationThread是一个实现了远程接口的Binder客户端,内部封装实现了很多远程接口。不过这个客户端什么时候连接的服务器还未可知,没有找到bindService关键字,反正此时应该已经连接上对应的Service了。应该是在RuntimeInit.java类中进行应用进程启动时启动的。

回来看下前一步服务的实例IActivityManager.attachApplication()内部的实现。

先获取AMS的实例,此处获取AMS实例代码跟Activity启动流程中一致

public static IActivityManager getService() {
    return IActivityManagerSingleton.get();
}
private static final Singleton<IActivityManager> IActivityManagerSingleton =
        new Singleton<IActivitywww.cppcns.comManager>() {
            @Override
            protected IActivityManager create() {
                final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                final IActivityManager am = IActivityManager.Stub.asInterface(b);
                return am;
            }
        };

…获取到AMS的Binder后,继续查看ActivityManagerService.java中的attachApplication方法

public final void attachApplication(IApplicationThread thread, long startSeq) {
    
    synchronized (this) {
        int callingPid = Binder.getCallingPid();
        final int callingUid = Binder.getCallingUid();
        final long origId = Binder.clearCallingIdentity();
        attachApplicationLocked(thread, callingPid, callingUid, startSeq); //1
        Binder.restoreCallingIdentity(origId);
    }
}

单例获取AMS实例,AMS服务在系统启动就已经注册到ServiceManager了,此处直接去获取Binder实例就行,ServiceManager以Binder池的方式管理注册的Server。

AMS的attachApplication方法中进入到attachApplicationLocked方法,捡能看懂的代码看,跟着thread参数查看代码。

private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
            int pid, int callingUid, long startSeq) {
​
    try {
        AppDeathRecipient adr = new AppDeathRecipient(
                app, pid, thread);
        thread.asBinder().linkToDeath(adr, 0);//1
        app.deathRecipient = adr;
    } catch (RemoteException e) {
        app.resetPackageList(mProcessStats);
        mProcessList.startProcessLocked(app,
                new HostingRecord("link fail", processName),
                ZYGOTE_POLICY_FLAG_EMPTY);
        return false;
    }
​
    final ActiveInstrumentation instr2 = app.getActiveInstrumentation();
​
    if (instr2 != null) {//2
        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 {
        thread.bindApplic

先给ApplicationThread这个Binder上个死亡代理,根据这个死亡代理应该可以找到对应的Service是如何重新启动的,感兴趣可以继续深入,咱们继续往下走。 此处调用到thread.bindApplication接口,前面咱们查看ApplicationThread时有看到,直接切入。

private class ApplicationThread extends IApplicationThread.Stub {
    //批量的schedule*接口,比如scheduleReceiver、scheduleCreateService等
    public final void schedule*
     
    //TODO 关键方法
    public final void bindApplication(some args){
        AppBindData data = new AppBindData();
        ...一堆参数
        sendMessage(H.BIND_APPLICATION, data);//1
    }
     
    //一堆dump方法,比如dumpMemory、dumpActivity等
     
}

到达咱们Android开发工程师比较熟悉的点了,封装了一堆参数后,通过H这个Handler对象发了一条BIND_APPLICATION消息,咱们看看这条消息去哪了,直接跟进BIND_APPLICATION这个消息的捕捉位置。

//消息分发
class H extends Handler{
    public void handleMessage(Message msg){
        swich(msg.what){
            case BIND_APPLICATION: 
                AppBindData data = (AppBindData)msg.obj;
                handleBindApplication(data);//1
                break;
            ...省略
        }
    }
}

进入消息分发处理方法,这个方法比较长,注意阅读能看懂的代码,不求甚解,跟踪data的处理。

private void handleBindApplication(AppBindData data) {
    //各种初始化,比如进程名,应用名,AsyncTask线程池的配置,时区,网络发现
     
    //Context的初始化
    final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
     
    try {
        final ClassLoader cl = instrContext.getClassLoader();
        mInstrumentation = (Instrumentation)//1
            cl.loadClass(data.instrumentationName.getClassName()).newInstance();
    } catch (Exception e) {
        throw new RuntimeException(
            "Unable to instantiate instrumentation "
            + data.instrumentationName + ": " + e.toString(), e);
    }
     
    final ComponentName component = new ComponentName(ii.packageName, ii.name);
    mInstrumentation.init(this, instrContext, appContext, component,//1
            data.instrumentationWatcher, data.instrumentationUiAutomationConnection);
             
    ...
    Application app;
    app = data.info.makeApplication(data.restrictedBackupMode, null);//2
 
    mInstrumentation.onCreate(data.instrumentationArgs);
    mInstrumentation.callApplicationOnCreate(app);//3
}

通过反射实例化mInstrumentation对象,该对象为Android系统组件的管家,目前看可以控制Application和Activity的生命周期。

创建Application对象,进去看下创建的代码

//LoadApk.java #makeApplication
public Application makeApplication(boolean forceDefaultAppClass,
    Instrumentation instrumentation){
    ...
    app = mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext);//1
    appContext.setOuterContext(app);
    ...
}
 
//Instrumentation.java #newApplication
public Application newApplication(ClassLoader cl, String className, Context context)
        throws InstantiationException, IllegalAccessException, 
        ClassNotFoundException {
    Application app = getFactory(context.getPackageName())
            .instantiateApplication(cl, className);//2
    app.attach(context);//首先回调attachBaseContext方法
    return app;
}
 
//AppComponentFactory #instantiateApplication
public @NonNull Application instantiateApplication(@NonNull ClassLoader cl,
        @NonNull String className)
        throws InstantiationException, IllegalAccessException, ClassNotFoundException {
    return (Application) cl.loadClass(className).newInstance();//3
}

可以看出最后还是通过反射初始化了Application。

以上就是Android中Application的启动流程解析;更多有关Android的核心技术,可参考《Android核心技术手册》点击查看类目。

最后通过mInstrumentation对象完成Application类的onCreate方法的调用。

mInstrumentation.callApplicationOnCreate(app);//1
 
//Instrumentation.java #callApplicationOnCreate
public void callApplicationOnCreate(Application app) {
    app.onCreate();
}

总结

  • 获取applicationThread,AMS这两个Binder2.attach时,将获取applicationThread对象也传递到AMS进程,请求远程调用通知AMS应用进程想要创建Application,此时AMS为服务端
  • AMS收到消息,请求调用applicationThread的远程接口,此时AMS为客户端
  • applicationThread收到AMS的请求,通过Handler发起创建Application的处理任务,后面就没有远程接口调用了
  • 通过反射创建Application的实例,通过Instrumentation启动Application的onCreate方法

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

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

相关文章

flask配置https协议

感谢https://blog.csdn.net/qq_33934427/article/details/127456673&#xff0c;文中多有参考再实践一、要用https协议需要有ca证书&#xff0c;在windows10先下载windows版本openssl&#xff0c;地址如下https://share.weiyun.com/vfjVrMAb我是64位的选择下载完毕安装后配置环…

vmvare NAT模式设置

一、前言 这里为什么会写关于设置vmvare NAT模式的笔记呢&#xff0c;以前使用linux虚拟机都是使用桥接模式获取IP地址。最近出差仙林医院&#xff0c;发现使用无线网络&#xff0c;虚拟机桥接获取不到IP地址&#xff0c;所以使用NAT模式。 二、设置步骤 1.设置网络适配器 …

hudi系列-文件布局(file layout)

概念 hudi的文件布局是能实现增量查询、数据更新等特性的基础&#xff0c;每个hudi表有一个固定的目录&#xff0c;存放元数据(.hoodie)以及数据文件&#xff0c;其中数据文件可以以分区方式进行划分&#xff0c;每个分区有多个数据文件(基础文件和日志文件)&#xff0c;这些数…

数据处理时代,有关数据的这些事

数据处理对于现在的企业来说已经是很平常的事&#xff0c;这主要是因为对数据的认识随时间的推移不断增加&#xff0c;企业用到数据的地方也越来越多。不过企业真正大规模利用的其实是数据资产&#xff0c;而非企业活动产生的所有数据&#xff0c;这两者并不互相统一。海量复杂…

WSH:一款功能强大的Web Shell生成器和命令行接口工具

关于WSH WSH是一款功能强大的Web Shell生成器和命令行接口工具。我们考虑到只用一个HTTP客户端来跟Webshell交互其实是一件很痛苦的事&#xff0c;我们需要在表格中输入命令&#xff0c;然后再点各种按钮。因此&#xff0c;我们开发出了WSH&#xff0c;我们可以轻松将其嵌入到…

代码随想录【Day16】| 104. 二叉树的最大深度、111. 二叉树的最小深度、222. 完全二叉树的节点个数

104. 二叉树的最大深度 题目链接 题目描述&#xff1a; 给定一个二叉树&#xff0c;找出其最大深度。 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。 说明: 叶子节点是指没有子节点的节点。 示例&#xff1a; 给定二叉树 [3,9,20,null,null,15,7]&#xff0c…

在vscode中使用Typescript并运行

首先呢&#xff0c;我们在学习ts之前&#xff0c;需要先安装ts 1、安装 typescript npm install -g typescript //检查是否安装tsc -v ​ 2、生成配置文件&#xff0c;cd进入该文件夹&#xff0c;在控制台输 tsc --init ​ 此时我们就可以看到在ts文件夹下面出现了 一个tsco…

搞清品牌策划第一性原理

【班门弄斧】一个科技男的妄想~~ ………搞懂品牌营销的深层逻辑 马斯克说&#xff0c;搞清第一性原理 国内有学科理论支撑的品牌营销大咖 趣讲大白话&#xff1a;我读书多&#xff0c;别骗我 *********** 【国内品牌营销大咖们的理论支撑】 1、王志纲 -中国智慧&#xff08;时…

C++——类和对象3

目录 1. 运算符重载 1.1 "" 的重载 1.2 前置 "" 和后置 "" 重载 1.3 流插入 "<<" 和流提取 ">>" 重载 1.4 运算符重载注意事项 2. const成员和static成员 2.1 const成员 2.2 static成员 3. 友元 …

C++递推基础知识

文章目录一、递推的概念二、递推和递归的区别三、递推的实例1、最基础的&#xff1a;斐波那契数列2、变形版斐波那契数列3、较复杂的递推式求解&#xff1a;昆虫繁殖4、经典逆推问题&#xff1a;题目数量一、递推的概念 1、什么是递推算法&#xff1f; 递推算法&#xff1a;是…

剑指 Offer 60. n个骰子的点数

题目 把n个骰子扔在地上&#xff0c;所有骰子朝上一面的点数之和为s。输入n&#xff0c;打印出s的所有可能的值出现的概率。 你需要用一个浮点数数组返回答案&#xff0c;其中第 i 个元素代表这 n 个骰子所能掷出的点数集合中第 i 小的那个的概率。 思路 动态规划&#xff1…

九龙证券|“股神”也做短线?巴菲特减仓逾八成台积电

美东时间2月14日盘后&#xff0c;“股神”巴菲特旗下公司伯克希尔哈撒韦&#xff08;下称“伯克希尔”&#xff09;发表的13F陈述引发商场热议。13F陈述被誉为“股市风向标”&#xff0c;出资者可藉此得以一窥华尔街大佬的最新出资思路。 根据美国证券交易委员会&#xff08;SE…

Vulnhub 渗透练习(三)—— Bulldog

环境搭建 下载链接 在 virtuallBox 中打开靶机。 virtuallBox 网络连接方式设置为仅主机。 vmware 设置桥接模式的网卡为 VirtualBox Host-Only Ethernet Adapter。 kail 网络适配设置为 NAT 和 桥接。 来自&#xff1a;https://blog.csdn.net/LYJ20010728/article/details/1…

JavaEE|文件操作·上

文章目录一、认识文件文件的概念文件的管理相关概念相对路径写法♋文件的分类Java中文件的操作二、File类的使用构造方法获得文件元信息判断的相关方法删除的方法与目录有关的方法修改名字三、流对象的使用什么是流文件内容操作涉及内容字节流对象InputStreamOutputStream字符流…

Bug bounty学习笔记20230213-0216(searching for Target)

www.bugcrowd.com Bug bounty program website 寻找email address Hunter.io Phonebook.cz www.voilanorbert.com – clearbit connect 在chrome里使用 Tools.verifyemailaddress.io Email-checker.net/validate 确定邮箱地址是不是真的 Dehashed.com Search for personal …

ChatGPT 最好的替代品

前两天我们邀请了微软工程师为我们揭秘 ChatGPT&#xff0c;直播期间有个读者问到&#xff1a;有了 ChatGPT&#xff0c;BERT 未来还有发展前途吗&#xff1f;我想起来最近读过的一篇博客“最好的 ChatGPT 替代品”。 不过聊到这俩模型&#xff0c;就不得不提到 Transformer。 …

夭寿啦!我的网站被攻击了了735200次还没崩

记得有一个看到鱼皮的网站被攻击&#xff0c;那时候我只是一个小小号&#xff0c;还在调侃&#xff0c;没想到我居然也有那么一天&#xff01; 突袭 一个风和日丽中午&#xff0c;我正在和同事吃饭&#xff0c;一个内存oom&#xff0c;我的小破站崩溃了。 虽然天天被攻击吧&a…

Linux - iostat 命令详解(监视磁盘 I/O)

iostat 是最常用的磁盘 I/O 性能观测工具&#xff0c;它提供了每个磁盘的使用率、IOPS、吞吐量等各种常见的性能指标&#xff0c;这些指标实际上来自 /proc/diskstats。 使用方式说明 [rootizwz98ahlvpkv3l7551ud2z ~]# iostat -help 用法:iostat [ 选项 ] [ <时间间隔>…

QML Gradient(渐变)

在Rectangle中简单的介绍了渐变&#xff0c;但只介绍了一种&#xff0c;下面还会介绍几种。 注意&#xff1a;渐变&#xff08;Gradient&#xff09;的优先级大于普通颜色&#xff08;color&#xff09; 线性渐变&#xff1a; 默认&#xff08;从上到下&#xff09;垂直渐变&…

C++【map和set的基本使用】

文章目录1、关联式容器2、键值对3、树形结构的关联式容器3-1、set3-1-1、set的使用3-1-3、set的使用样例3-2、map3-2-1、map的使用3-2-2、map的使用样例3-3、multiset3-4、multimap4、总结1、关联式容器 在初阶阶段&#xff0c;我们已经接触过STL中的部分容器&#xff0c;比如…