1-APP启动源码分析-1

2023-11-02

桌面app也就是我们认识的launcher app,点击app icon启动到app内部的过程分为2种情况,一种是冷启动,一种叫热启动。

冷启动:系统没有创建过app的进程,也就是后台没有此app进程,所以冷启动系统会创建一个新的进程分配给app,再创建application类,最终再创建根activity并显示UI。

热启动:之前进行过冷启动但最终退出了该app,此时app的进程还在后台,在app进程存在的情况下启动app为热启动,此时不需创建application,只需创建根acticity即可。

分析App的启动,冷启动的过程的步骤是多于热启动,热启动少了创建application的步骤,所以我们先从冷启动开始分析。

1,桌面点击app图片,触发app启动流程

Launcher.java
public boolean startActivitySafely(View v,Intent intent,ItemInfo item){
...
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//你懂的,activity要在新的任务栈中启动
...
startActivity(itent,optsBundle);//此时还在Launcher app的进程中,此时的代码和普通activity间的跳转已经大体一样了
                                //不一样在于普通activity的startActivity是在app自己的进程中,冷启动是在Launcher进程中
}

2,activity的startActivity(Intent)分析

1,Activity.java

@Override
    public void startActivity(Intent intent, @Nullable Bundle options) {
        ...
        if (options != null) {
            startActivityForResult(intent, -1, options);
        } else {
            // Note we want to go through this call for compatibility with
            // applications that may have overridden the method.
            startActivityForResult(intent, -1);
        }
    }

2,看下startActivityForResult()
 Activity.java

     public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {
        if (mParent == null) {//此时根activity还没创建,此时肯定为null
            options = transferSpringboardActivityOptions(options);
            Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity( //关键代码,mInstrumentation号称Android中一些列控制方法的集合,可以在正常生命周期之外控制Android控件的运行
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
            if (ar != null) {
                mMainThread.sendActivityResult(
                    mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                    ar.getResultData());
            }
           ...
        } else {
           ...
        }
    }

3,mInstrumentation.execStartActivity()
public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
        ...
        try {
            intent.migrateExtraStreamToClipData(who);
            intent.prepareToLeaveProcess(who);
            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);
            checkStartActivityResult(result, intent);
        } catch (RemoteException e) {
            throw new RuntimeException("Failure from system", e);
        }
        return null;
    }
分析:ActivityTaskManager.getService()得到的是IActivityTaskManager,也就是AMS的代理对象,接着调用它的startActivity

4,看下ActivityTaskManager
    public static IActivityTaskManager getService() {
        return IActivityTaskManagerSingleton.get();
    }

    @UnsupportedAppUsage(trackingBug = 129726065)
    private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton =
            new Singleton<IActivityTaskManager>() {
                @Override
                protected IActivityTaskManager create() {
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);//得到AMS的引用
                    final IActivityManager am = IActivityManager.Stub.asInterface(b);//返回IActivityManager的对象,使用AIDL,要实现进程间通信,只要AMS实现IActivityManager即可
                    return am;
                }
            };


总结:经过上面的多层中转,实现了请求从Launcher进程过渡到AMS中

下面看下AMS在收到Launcher的Binder指令后做了什么操作

1,为了实现进程间通信,AMS是继承自IActivityManager.Stub的
public class ActivityManagerService extends IActivityManager.Stub{
...
}

2,实际的startActivity
ActivityManagerService.java

 public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId,
            boolean validateIncomingUser) {
        enforceNotIsolatedCaller("startActivity");

        userId = mActivityStartController.checkTargetUser(userId, validateIncomingUser,
                Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");

        // TODO: Switch to user app stacks here.
        return mActivityStartController.obtainStarter(intent, "startActivityAsUser")  //obtainStarter()返回ActivityStarter
                .setCaller(caller)
                .setCallingPackage(callingPackage)
                .setResolvedType(resolvedType)
                .setResultTo(resultTo)
                .setResultWho(resultWho)
                .setRequestCode(requestCode)
                .setStartFlags(startFlags)
                .setProfilerInfo(profilerInfo)
                .setActivityOptions(bOptions)
                .setMayWait(userId)
                .execute();

    }

3,ActivityStarter类,见名知义,负责activity的启动操作,关键跳转到startActivityMayWait()
    ActivityStarter.java

 private int startActivityMayWait(IApplicationThread caller, int callingUid,
            String callingPackage, Intent intent, String resolvedType,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode, int startFlags,
            ProfilerInfo profilerInfo, WaitResult outResult,
            Configuration globalConfig, SafeActivityOptions options, boolean ignoreTargetSecurity,
            int userId, TaskRecord inTask, String reason,
            boolean allowPendingRemoteAnimationRegistryLookup) {
        ...
        //获取ResolveInfo信息 有的时候隐式跳转可以有多个Intent可选,会在此时弹出选择框
        ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId,
                0 /* matchFlags */,
                        computeResolveFilterUid(
                                callingUid, realCallingUid, mRequest.filterCallingUid));
        ...
        //获取目标activity的信息
        ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);

        synchronized (mService) {
          //启动activity
            final ActivityRecord[] outRecord = new ActivityRecord[1];
            int res = startActivity(caller, intent, ephemeralIntent, resolvedType, aInfo, rInfo,
                    voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid,
                    callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options,
                    ignoreTargetSecurity, componentSpecified, outRecord, inTask, reason,
                    allowPendingRemoteAnimationRegistryLookup);


            mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(res, outRecord[0]);
            return res;
        }
    }    

4,startActivity()中实际执行方法
    private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
            ActivityRecord[] outActivity) {
        ...
        computeLaunchingTaskFlags();//计算启动的Activity的Flag值
        ...
        mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition,mOptions);//处理task和activity的进出栈操作
        ...
          mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,mOptions);//启动栈顶activity
        ...     
    return START_SUCCESS;
    }


5,最终一路跳转,创建启动activity事务,交给AMS启动Activity 这一系列涉及process相关的方法其实是通过zygote创建进程
ActivityStackSupervisor.java

void startSpecificActivityLocked(ActivityRecord r,
            boolean andResume, boolean checkConfig) {
        // Is this activity's application already running?
        ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid, true);
        if (app != null && app.thread != null) {
            try {
               realStartActivityLocked(r, app, andResume, checkConfig);//启动activity事务
                return;
            } catch (RemoteException e) {
            }
        }
        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);//执行activity启动
    }


 final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
            boolean andResume, boolean checkConfig) throws RemoteException {  
                // Create activity launch transaction.创建activity启动事务
                final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread,//传入app的线程,也就是ApplicationThread
                        r.appToken);
                clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
                        System.identityHashCode(r), r.info,
                        // TODO: Have this take the merged configuration instead of separate global
                        // and override configs.
                        mergedConfiguration.getGlobalConfiguration(),
                        mergedConfiguration.getOverrideConfiguration(), r.compat,
                        r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
                        r.persistentState, results, newIntents, mService.isNextTransitionForward(),
                        profilerInfo));

                // Set desired final state.
                final ActivityLifecycleItem lifecycleItem;
                if (andResume) {
                    lifecycleItem = ResumeActivityItem.obtain(mService.isNextTransitionForward());
                } else {
                    lifecycleItem = PauseActivityItem.obtain();
                }
                clientTransaction.setLifecycleStateRequest(lifecycleItem);

                // Schedule transaction.
                mService.getLifecycleManager().scheduleTransaction(clientTransaction);//执行启动事务



        return true;
    }

而startProcessLocked()跳转的最终方法是startProcess()

 private ProcessStartResult startProcess(String hostingType, String entryPoint,
            ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
            String seInfo, String requiredAbi, String instructionSet, String invokeWith,
            long startTime) {
        try {
            ...
            final ProcessStartResult startResult;
            if (hostingType.equals("webview_service")) {
                startResult = startWebView(entryPoint,
                        app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                        app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                        app.info.dataDir, null,
                        new String[] {PROC_START_SEQ_IDENT + app.startSeq});
            } else {
                startResult = Process.start(entryPoint,
                        app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                        app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                        app.info.dataDir, invokeWith,
                        new String[] {PROC_START_SEQ_IDENT + app.startSeq});//明确了新开启进程的所有的信息,使用Procee.start()开始zygote的fork进程操作
            }
            checkTime(startTime, "startProcess: returned from zygote!");
            return startResult;
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        }
    }



6,Process.java 开始zygote的孵化之旅
 public static final ProcessStartResult start(final String processClass,
                                  final String niceName,
                                  int uid, int gid, int[] gids,
                                  int runtimeFlags, int mountExternal,
                                  int targetSdkVersion,
                                  String seInfo,
                                  String abi,
                                  String instructionSet,
                                  String appDataDir,
                                  String invokeWith,
                                  String[] zygoteArgs) {
        return zygoteProcess.start(processClass, niceName, uid, gid, gids,
                    runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
    }


小结:这样,我们就从AMS 交给zygote去孵化新的进程,至于zygote如何fork创建进程,暂不展开讨论,后续新的进程开启走了main(),就是后面的过程了。    

下面就是App正式启动main方法的时候了,这之前的源码看来,跟开车一样,先插钥匙,再打火,下一步就是挂档加油门出发了。

小小总结一下:

1,在Launcher进程触发App的跳转,最终通过Binder进程间机制通知给了ActivityManagerService(AMS)

2,AMS通过Zygote.fork()创建一个新的进程,用来启动App的ActivityThread实例

3,App开启main(),进行一系列App真正启动的操作,留给后面再写了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

1-APP启动源码分析-1 的相关文章

  • 在 Android 上将视频设置为壁纸

    我想知道如何将视频设置为壁纸 否则不可能 我可以将图像设置为壁纸 并且可以构建动态壁纸 但无法将视频设置为壁纸 所以有人知道我该怎么做吗 提前致谢 我认为唯一可以做到的方法是将其合并到 动态壁纸 中 缺点是正如其他人提到的那样 这会严重影响
  • 带身份验证的 MediaPlayer RTSP 视频流

    我能够在未经授权的情况下从网络摄像机流式传输视频 但现在我需要在授权的情况下执行此操作 我发现很少有信息表明 Android 不支持 RTSP 身份验证 但我发现另一条信息表明 通过使用该方法添加标头 可以在 API 级别 14 中实现身份
  • 在解决依赖关系之前运行 gradle 任务

    我想运行一个 gradle 任务 在 gradle 尝试解决依赖关系之前获取其他源并设置它们 在 build gradle 中有一个任务 用于获取子项目的源代码 该任务需要在 Gradle 尝试解决依赖关系之前运行 因为子项目是依赖关系的一
  • getItemAtPosition() 未在列表视图中返回值

    我创建了一个自定义基本适配器类 用图像和文本填充列表视图 类的代码如下 public class ViewAdapter extends BaseAdapter private Activity activity private Strin
  • 检测正在插入的设备

    我希望能够检测设备是否已插入 我希望能够像查询连接状态一样进行查询 这可能吗 或者我是否需要创建一个监听电池事件的广播接收器 显然是ACTION BATTERY CHANGED http developer android com refe
  • Android:动态更改Listview中的图像

    我有一个由以下 xml 定义的列表视图 我需要切换图像当用户单击任何行时 在运行时会出现在列表中 我怎样才能实现这个目标 非常感谢任何帮助 谢谢 list item xml
  • 是否仍然建议使用 AsyncTask 在后台加载 listView 项目?

    背景 我听说有一些在后台加载数据的新解决方案比 AsyncTask 更值得推荐 例如loaders http developer android com reference android content Loader html 问题 As
  • 强制关闭导致HTTP实体可能不为空

    这里是发送数据 Http 的完整代码 asynctask private class MyAsyncTaskPupuk extends AsyncTask
  • 收到“提供的 API 密钥已过期”。使用 Places API 时出错

    我已经从 Google 控制台为 Places API 密钥生成了服务器密钥 但每当我访问该服务时 我都会收到 提供的 API 密钥已过期 错误 我已尝试重新生成密钥 但仍然出现相同的错误 我遇到了同样的问题 但终于解决了 Google 地
  • Android/java:从 ProGuard 过渡/迁移到 R8?

    我想知道如何从ProGuard to R8 我是否应该从 Gradle 文件中删除与 Proguard 相关的行并添加android enableR8 true线代替 Thanks Proguard 由 GuardSquare 开发和维护
  • 按钮上方带有文本的单选按钮

    我是 Android 新手 我需要在我的活动中添加单选按钮 但我需要将文本放在项目符号按钮的顶部 请提供任何帮助 我发现了以下内容 尽管我不明白 drawable in 选择器和 style Tab 样式是什么 顶部带有文本的单选按钮 ht
  • 在应用程序之间共享自定义帐户验证器

    我有一个为使用自定义 AccountAuthenticator 的客户端构建的应用程序 它工作得非常好 并且满足了客户的需求 但是 这只是将使用相同身份验证管理器的应用程序集合中的第一个应用程序 这就是我不确定如何继续的地方 我无法知道任何
  • Android/三星 Galaxy S 模拟器

    有没有办法在三星银河模拟器或类似的东西上尝试我的项目 我的项目在 HTC Legend 上运行 但在该设备上崩溃了 我如何在 android eclipse 上设置三星 Galaxy s 我设置了 W800 854 2 2 AVD 但它可以
  • 无法在 Android Studio 中运行项目

    当我尝试在 Android Studio 中运行我的项目时 我收到以下错误消息 Execution failed for task CricHQ dexDebug gt com android ide common internal Log
  • 测试应用内结算:“发布者无法购买此商品”

    我的应用程序似乎已准备好在我的设备上进行应用内购买程序的 现实生活 测试 但是 我在 Play 商店中收到 发布商无法购买此商品 的错误消息 现在 我应该如何测试这个 我不想通过仅用于测试的虚拟帐户重新安装手机来丢失手机的配置 在开发者控制
  • Android RxJava 2 JUnit 测试 - android.os.Looper 中的 getMainLooper 未模拟 RuntimeException

    我在尝试为正在使用的演示者运行 JUnit 测试时遇到 RuntimeExceptionobserveOn AndroidSchedulers mainThread 由于它们是纯 JUnit 测试而不是 Android 仪器测试 因此它们无
  • 如何在jetpack compose中删除文本基线下方的空间?

    目前我得到这个 但我想要这样的东西 而且 50 和 min 中的文本也应该与顶部对齐 My code Row verticalAlignment Alignment Bottom Text text 18 color MaterialThe
  • 如何在 Android 应用程序退出之前进行一些清理?

    当我的 Android 应用程序终止时 是否有某种 onTerminate 方法可以进行一些清理 我想清除一些 SharedPreferences 我有一个活动 它保持几个数字的运行平均值 并将其存储在 SharedPreference 中
  • Android 使用不同的签名密钥更新市场应用程序

    开发人员使用他的个人密钥库签署了应用程序 但它应该是公司的密钥库 现在是否可以使用公司的密钥库更新市场中的应用程序 并且仍然可以简化对用户的更新 这有什么后果吗 不可以 您必须将该应用程序作为新应用程序发布到市场上 这次是用公司的key签名
  • 带有包含布局的导航抽屉布局

    我认为我的问题实际上很简单 但我不知道如何解决 有一个工作导航抽屉 代码如下

随机推荐

  • Nginx访问二级目录后/(反斜杠)无法访问问题的解决办法

    Nginx访问二级目录的时候不加 反斜杠 无法访问 现在给出解决办法 我用的是正则表达式自动加 反斜杠 if d request filename rewrite http host 1 2 permanent
  • PCB设计_Via过孔和PAD焊盘

    PCB的四周一般会设计增加机械孔用于固定PCB板 增加整体结构的稳定 但是机械孔的设计往往在新手的设计中会出现许多问题 而且DFM检查还不一定可以检查出来 那么针对机械孔 金属化和非金属化 两种的设计 下面将会讨论 1 金属化机械孔 这里不
  • Vue刷新浏览器后重定向到首页或者某一个页面

    记录一下项目需要的一些小优化 刷新浏览器时回到首页 一般来说vue项目刷新浏览器之后还会继续跳动刷新之前的页面 我们只需要要App vue中的created方法中添加相关判断即可 这里的 index可以换成具体需要跳转的页面 具体代码如下
  • [深度学习] Relu层作用

    为什么引入非线性激励函数 如果不用激励函数 在这种情况下你每一层输出都是上层输入的线性函数 很容易验证 无论你有多少层神经网络 输出的都是输入的线性组合 激活函数是用来加入非线性因素的 因为线性模型的表达能力不够 以下 同种颜色为同类数据
  • 如何删除 MySQL ⽤户

    1 登录MySQL数据库 登录MySQL数据库 可以使 以下命令 mysql u 户名 p 2 查看当前 户 使 以下命令查看当前所有 户 ysql user 3 删除 户 在MySQL数据库中 删除 户需要使 DROP USER命令 以下
  • Python快速搭建HTTP服务

    欢迎关注 无量测试之道 公众号 回复 领取资源 Python编程学习资源干货 Python Appium框架APP的UI自动化 Python Selenium框架Web的UI自动化 Python Unittest框架API自动化 资源和代码
  • Tomcat 启动时,/logs/catalina.out: No such file or directory

    如果报这个错请查看是不是Tomcat包下载错了 注意 要下载Core 中的tar gz 如果Tomcat包正确请继续往下看解决方案 解决方案 touch cannot touch opt apache tomcat 7 0 93 src l
  • android动态设置maxheight,android - 如何在TextInputLayout上设置maxHeight - 堆栈内存溢出...

    我不想限制行数 我想限制TextInputLayout最大高度 这样 如果它太长 它将变为垂直滚动 我很好的代码解决方案 当前maxHeight属性对TextInputLayout或EditText无效 这是我的布局 xmlns app h
  • GB28181 对接海康平台,解决音视频卡顿问题

    GB28181 对接海康平台 解决音视频卡顿问题 一 概述 二 问题分析 1 设备对比分析 2 抓包对比分析 3 验证分析结果 三 总结 四 讨论 一 概述 设备使用GB28181协议对接海康平台时 发现音频和视频存在卡顿现象 不是一直卡顿
  • 程序分层领域模型规约中各种实体类命名(DO、BO、DTO、VO)的意义

    仅做参考 DO Data Object 与数据库表结构一一对应 通过DAO层向上传输数据源对象 DTO Data Transfer Object 数据传输对象 Service或Manager向外传输的对象 BO Business Objec
  • 期货开户一心一意坚持到底

    只有真正了解了自己的性格 那么离寻觅到适合自己性格的交易法则也就不远了 只有专注 一心一意的做某件事情 才能做到无困无惑 如果三心二心 那么最终只会一事无成 大道至简 坦然面对自己人性的弱点 才能做到交易简单 生活快乐 其实一时的坚持非感觉
  • npm run build:prod报错:events.js:291 throw er; // Unhandled ‘error‘ event处理办法

    解决办法 1 CTRL R输入cmd 2 在命令行输入 netstat ano findstr 8080 3 找到占用的PID号 进行查找 tasklist findstr 16504 4 CTRL SHIFT DELETE打开任务管理器
  • Qt: error: C2001: 常量中有换行符

    这里简单记录在使用Qt Creator时遇到的一个问题 如下一行代码 没有任何问题 但编译运行时会报错 label gt setText label 我是一个窗口 当使用中文时 可能会习惯性的使用QObject tr 函数 label gt
  • 文件查重FindDupFile

    finddupfile是网上用的比较多的一款绿色查重软件 具体步骤请参考以下 1 下载软件 可从网上下载该软件 或者从以下地址进行下载 本软件从网上可自行下载 下载链接 https pan baidu com s 1KDJ9U4U 8HQa
  • 数学分析闭区间套定理_什么是区间套定理?

    什么是闭区间 数轴上任意两点和这两点间所有点组成的线段为一个闭区间 闭区间套定理 有无穷个闭区间 第二个闭区间被包含在第一个区间内部 第三个被包含在第二个内部 以此类推 后一个线段会被包含在前一个线段里面 这些区间的长度组成一个无穷数列 如
  • FineReportV10.0入门

    第三章 报表属性设计基础 第三课层次坐标 常用公式
  • gitlab CI/CD自动化部署

    文章目录 1 gitlab Runner 1 1 安装gitlab Runner 1 2 注册runner 2 gitlab ci yml的书写 3 部署 3 1 docker方式部署 3 2 OSS部署 CI CD 是一种持续开发软件的方
  • 针对QT——“在程序文件中(*ui,*cpp,*h)更改之后编译运行的程序结果无法更新”——解决方案

    本篇文章主要介绍在QT中 对程序文件 ui cpp h 更改之后编译运行的程序结果却无法更新的解决方案 问题描述 在设计QT的GUI用户界面时 我们需要不断对程序文件进行修改以优化用户体验 因此需要更新程序的生成文件 实际经历 笔者最近在一
  • IntelliJ Spring Configuration Check

    用IntelliJ 导入现有工程时 如果原来的工程中有spring 每次打开工程就会提示 Spring Configuration Check 开始不知道怎么回事 但工程不影响 首先到工程设置界面 工程设置 Project Structur
  • 1-APP启动源码分析-1

    桌面app也就是我们认识的launcher app 点击app icon启动到app内部的过程分为2种情况 一种是冷启动 一种叫热启动 冷启动 系统没有创建过app的进程 也就是后台没有此app进程 所以冷启动系统会创建一个新的进程分配给a