Android之AMS原理分析

在学习android框架原理过程中,ams的原理非常重要,无论是在面试中还是在自己开发类库过程中都会接触到。

1 简述

ActivityManagerService是Android最核心的服务,负责管理四大组件的启动、切换、调度等工作。由于AMS的功能和重要性,它是运行在SystemServer进程,客户端不能直接访问。但是可以通过ActivityManager类的getService方法获取IActivityManager,然后与AMS通信。

2 AMS启动流程

init进程

Android系统总共分为4层,从上到下为,应用层、框架层、系统层、linux内核层。整个系统启动时,会先由各个厂商的引导程序拉起,加载一些资源,然后启动init进程,挂载分区,创建必要目录,初始化日志系统和安全策略。最后解析init.rc文件,去启动zygote进程。

zygote进程

通过init进程拉起zygote后,

service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygoteclass mainpriority -20user root                                 # 用户为rootgroup root readproc reserved_disksocket zygote stream 660 root systemsocket usap_pool_primary stream 660 root systemonrestart exec_background - system system -- /system/bin/vdc volume abort_fuseonrestart write /sys/power/state ononrestart restart audioserveronrestart restart cameraserveronrestart restart mediaonrestart restart media.tuneronrestart restart netdonrestart restart wificondtask_profiles ProcessCapacityHigh MaxPerformancecritical window=${zygote.critical_window.minute:-off} target=zygote-fatalservice zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preloadclass mainpriority -20user rootgroup root readproc reserved_disksocket zygote_secondary stream 660 root systemsocket usap_pool_secondary stream 660 root systemonrestart restart zygotetask_profiles ProcessCapacityHigh MaxPerformance

会创建JavaVM,并注册JNI
通过JNI调用ZygoteInit的main函数进入Zygote的Java框架层,创建服务端Socket,预加载类和资源,并通过runSelectLoop函数等待如ActivityManagerService等的请求。
调用forkSystemServer 来启动SystemServer进程,这样系统的关键服务也会由SystemServer进程启动起来。

SystemServer进程

/*** 进程的入口点*/
public static void main(String[] args) {new SystemServer().run();
}private void run() {...// 启动 AMS PowerManagerService PackageManagerService 等服务startBootstrapServices(t);// 启动了BatteryService UsageStatsService WebViewUpdateServicestartCoreServices(t);// CameraService AlarmManagerService VrManagerServicestartOtherServices(t);    ...}

Zygote启动后fork的第一个进程为SystemServer,这个进程就会去启动一系列的服务,AMS服务也是由这个进程启动。

AMS 启动

private void startBootstrapServices(@NonNull TimingsTraceAndSlog t) {t.traceBegin("startBootstrapServices");// ...// Activity manager runs the show.// 创建并运行AMSt.traceBegin("StartActivityManager");// TODO: Might need to move after migration to WM.ActivityTaskManagerService atm = mSystemServiceManager.startService(ActivityTaskManagerService.Lifecycle.class).getService();mActivityManagerService = ActivityManagerService.Lifecycle.startService(mSystemServiceManager, atm);mActivityManagerService.setSystemServiceManager(mSystemServiceManager);mActivityManagerService.setInstaller(installer);mWindowManagerGlobalLock = atm.getGlobalLock();t.traceEnd();// ...t.traceEnd(); // startBootstrapServices
}public static final class Lifecycle extends SystemService {private final ActivityManagerService mService;private static ActivityTaskManagerService sAtm;public Lifecycle(Context context) {super(context);mService = new ActivityManagerService(context, sAtm);}public static ActivityManagerService startService(SystemServiceManager ssm, ActivityTaskManagerService atm) {sAtm = atm;return ssm.startService(ActivityManagerService.Lifecycle.class).getService();}@Overridepublic void onStart() {mService.start();}@Overridepublic void onBootPhase(int phase) {mService.mBootPhase = phase;if (phase == PHASE_SYSTEM_SERVICES_READY) {mService.mBatteryStatsService.systemServicesReady();mService.mServices.systemServicesReady();} else if (phase == PHASE_ACTIVITY_MANAGER_READY) {mService.startBroadcastObservers();} else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {mService.mPackageWatchdog.onPackagesReady();}}@Overridepublic void onCleanupUser(int userId) {mService.mBatteryStatsService.onCleanupUser(userId);}public ActivityManagerService getService() {return mService;}
}public void startService(@NonNull final SystemService service) {// 注册服务mServices.add(service);// 开启服务long time = SystemClock.elapsedRealtime();try {service.onStart();} catch (RuntimeException ex) {throw new RuntimeException("Failed to start service " + service.getClass().getName()+ ": onStart threw an exception", ex);}warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");
}private void start() {// ...
}

从代码中可以看出在startBootstrapServices方法中,创建了ActivityManagerService服务对象,然后在startService方法中调用service.onStart(),也就是走Lifecycle中实现的方法,然后最终走到start(),启动服务。

3 AMS在启动App过程中的体现

fock新进程

我们手机上的App都是在Launcher(就是个Actviity)中显示的,点击图标会触发onClick收到点击事件,然后走startActivitySafely方法,继续往下走,会发现就是startActivity方法往后走的调用。

LauncherAppsService -> startActivityAsUser
ActivityTaskManagerService -> startActivityAsUser
ActivityStarter -> execute
ActivityStarter -> startActivityUnchecked
ActivityStarter -> startActivityInner
ActivityStack -> startActivityLocked
ActivityStack -> ensureActivitiesVisible
EnsureActivitiesVisibleHelper -> process
EnsureActivitiesVisibleHelper -> setActivityVisibilityState
ActivityRecord -> makeActiveIfNeeded
ActivityStack -> resumeTopActivityUncheckedLocked
ActivityStack -> resumeTopActivityInnerLocked
ActivityTaskManagerService -> startProcessAsync
ActivityManagerService -> startProcess
ActivityManagerService -> startProcessLocked
ProcessList -> startProcessLocked (指定启动进程后,走android.app.ActivityThread main方法 : final String entryPoint = "android.app.ActivityThread";)
ProcessList -> startProcess
ZygoteProcess -> start
ZygoteProcess -> startViaZygote
zygoteSendArgsAndGetResult
attemptZygoteSendArgsAndGetResultprivate Process.ProcessStartResult attemptZygoteSendArgsAndGetResult(ZygoteState zygoteState, String msgStr) throws ZygoteStartFailedEx {try {final BufferedWriter zygoteWriter = zygoteState.mZygoteOutputWriter;final DataInputStream zygoteInputStream = zygoteState.mZygoteInputStream;zygoteWriter.write(msgStr);zygoteWriter.flush();// Always read the entire result from the input stream to avoid leaving// bytes in the stream for future process starts to accidentally stumble// upon.Process.ProcessStartResult result = new Process.ProcessStartResult();result.pid = zygoteInputStream.readInt();result.usingWrapper = zygoteInputStream.readBoolean();if (result.pid < 0) {throw new ZygoteStartFailedEx("fork() failed");}return result;} catch (IOException ex) {zygoteState.close();Log.e(LOG_TAG, "IO Exception while communicating with Zygote - "+ ex.toString());throw new ZygoteStartFailedEx(ex);}
}

Launcher通知AMS启动APP的MainActivity,也就是清单文件设置启动的Activity
AMS记录要启动的Activity信息,并且通知Launcher进入pause状态
Launcher进入pause状态后,通知AMS已经paused了,可以启动app了
app未开启过,所以会通过socket发送消息给AMS
AMS在SystemServer进程,该进程在启动时,执行ZygoteInit.main()后便进入runSelectLoop()循环体内,当有客户端连接时便会执行ZygoteConnection.runOnce()方法,再经过层层调用后fork出新的应用进程(handleChildProc)
并且在新进程中创建ActivityThread对象,执行其中的main函数方法

ActivityThread

ActivityThread会做很多事,我们只分析和app启动与AMS相关的。

public static void main(String[] args) {// ...Looper.prepareMainLooper();ActivityThread thread = new ActivityThread();// 绑定Applicationthread.attach(false, startSeq);Looper.loop();// ...
}private void attach(boolean system) { sCurrentActivityThread = this;mSystemThread = system; // falseif (!system) { // true...// 获取 AMS,调用AMS的 attachApplicationfinal IActivityManager mgr = ActivityManager.getService();try {mgr.attachApplication(mAppThread);} catch (RemoteException ex) {throw ex.rethrowFromSystemServer();}// Watch for getting close to heap limit....} else { // 系统进程处理逻辑...}...
}

AMS 处理绑定Application

@Override
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);}
}private final boolean attachApplicationLocked(IApplicationThread thread,int pid) {ProcessRecord app;// 根据pid 获取 对应 ProcessRecord// 新进程的名字final String processName = app.processName;...thread.bindApplication(processName, appInfo, providerList, null, profilerInfo,null, null, null, testMode,mBinderTransactionTrackingEnabled, enableTrackAllocation,isRestrictedBackupMode || !normalMode, app.isPersistent(),new Configuration(app.getWindowProcessController().getConfiguration()),app.compat, getCommonServicesLocked(app.isolated),mCoreSettingsObserver.getCoreSettingsLocked(),buildSerial, autofillOptions, contentCaptureOptions,app.mDisabledCompatChanges);...//查找所有可运行在该进程中的服务//检查这个进程中是否有下一个广播接收者//检查这个进程中是否有下一个备份代理//上述操作如果出现异常就杀死进程...}

ActivityThread.bindApplication

@Override
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;...sendMessage(H.BIND_APPLICATION, data);
}private void handleBindApplication(AppBindData data) {...// application oncreatemInstrumentation.callApplicationOnCreate(app);
}

启动MainActivity

App启动时我们通过fork Zygote进程,创建了app进程,并做了一些application的绑定等等操作。
这些处理好后,就可以继续启动MainActivity。

ActivityStack -> resumeTopActivityInnerLocked
ActivityStackSupervisor -> startSpecificActivity
ActivityStackSupervisor -> realStartActivityLockedprivate boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {// ...// Since the start-process is asynchronous, if we already know the process of next// activity isn't running, we can start the process earlier to save the time to wait// for the current activity to be paused.final boolean isTop = this == taskDisplayArea.getFocusedStack();mAtmService.startProcessAsync(next, false /* knownToBeDead */, isTop,isTop ? "pre-top-activity" : "pre-activity");// ...mStackSupervisor.startSpecificActivity(next, true, true);}boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,boolean andResume, boolean checkConfig) throws RemoteException {mService.getLifecycleManager().scheduleTransaction(clientTransaction);
}// 通过aidl进入app所在进程
// 启动MainActivityActivityThread -> scheduleTransaction
...
ActivityThread -> handleLaunchActivity
ActivityThread -> performLaunchActivity

4 重要的类

ActvityRecord

用来存储activity的信息!

一个ActivityRecord对应一个Activity,一个Activity可能会有多个

ActivityRecord

因为Activity可以被多次启动,这个主要取决于其启动模式。

ActivityStack

则是用来管理ActivityRecord的,包含了多个ActivityRecord。

ActivityStack

用来存储activity,也就是我们常说的activity栈。
ActivityStackSupervisor
用来管理ActivityStack!
Instrumentation
负责调用Activity和Application生命周期。

5 总结

AMS负责四大组件的启动,调度等工作,因为在不同进程,所以通信会基于binder或者socket。1、AMS是什么时候被初始化的?在手机开机,SystemServer进程启动后,就会启动初始化AMS。2、AMS与Zygote进程是通过什么通信的?

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

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

相关文章

字符串输入(注意:cin遇到空白字符停止读入)

1.输入多个字符串时&#xff0c;又无法开二维数组&#xff1b; 可动态分配数组&#xff08;直接声明数组&#xff0c;指向的地址的不变的&#xff09; while (num--){char* arr (char*)malloc(10000 * sizeof(char));char ch 0;int k 0;while ((ch getchar()) ! \n){arr[k…

文心一言 VS 讯飞星火 VS chatgpt (118)-- 算法导论10.3 3题

三、用go语言&#xff0c;在ALLOCATE-OBJECT和 FREE-OBJECT过程的实现中&#xff0c;为什么不需要设置或重置对象的 prev 属性呢? 文心一言&#xff1a; 在 Go 语言中&#xff0c;ALLOCATE-OBJECT 和 FREE-OBJECT 过程的实现通常不需要显式地设置或重置对象的 prev 属性。这…

【简记】getprop, setprop 命令使用

getprop, setprop 命令使用 1、终端设置、读取系统属性 // 例 adb shell setprop "test" "1" adb shell getprop "test"2、安卓读取系统配置 部分属性需要通过反射 android.os.SystemProperties 的方法获取&#xff0c;参见 android 获取手机…

Java EE-使用Servlet搭建一个简单的前后端交互程序

上述前端和后端的代码如下&#xff1a; 前端&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"vie…

LuatOS-SOC接口文档(air780E)--lcd - lcd驱动模块

常量 常量 类型 解释 lcd.font_opposansm8 font 8号字体 lcd.font_unifont_t_symbols font 符号字体 lcd.font_open_iconic_weather_6x_t font 天气字体 lcd.font_opposansm10 font 10号字体 lcd.font_opposansm12 font 12号字体 lcd.font_opposansm16 font…

搭建网站七牛云CDN加速配置

打开七牛云后台&#xff1b;添加域名&#xff1b; 添加需要加速的域名&#xff0c;比如我添加的是motoshare.cn 源站配置&#xff0c;这里要用IP地址&#xff0c;访问的目录下面要有能访问测试的文件&#xff0c;尽量不要用源站域名&#xff0c;这个只能用加速二级域名&#x…

【试题039】 多个逻辑或例题

题目&#xff1a;设int n;,执行表达式(n0)||(n1)||(n2)||(n3)后,n的值是&#xff1f;代码分析&#xff1a; //设int n; , 执行表达式(n 0) || (n 1) ||(n 2) ||(n 3)后, n的值是?int n;printf("n%d\n", (n 0) || (n 1) || (n 2) || (n 3));//分析&#xff1…

树的重心学习

知识&#xff1a; 定义&#xff1a;重心是指树中的一个结点&#xff0c;如果将这个点删除后&#xff0c;剩余各个连通块中点数的最大值最小&#xff0c;那么这个节点被称为树的重心。 &#xff08;最大值的最小值&#xff09; 树的重心的性质&#xff1a; 1.一个树最多只有1个或…

STM32-LTC6804方案成熟BMS方案

方案下载链接&#xff01;&#xff01;https://mp.weixin.qq.com/s?__bizMzU2OTc4ODA4OA&mid2247549092&idx1&snc73855c4e3d5afddd8608d8528864f95&chksmfcfb1373cb8c9a65a4bd1f545a1a587af882f209e7ccbb8944f4d2514d241ca1d7fcc4615e10&token539106225&a…

vue 插槽 作用域插槽

vue 插槽 作用域插槽 **创建 工程&#xff1a; H:\java_work\java_springboot\vue_study ctrl按住不放 右键 悬着 powershell H:\java_work\java_springboot\js_study\Vue2_3入门到实战-配套资料\01-随堂代码素材\day05\准备代码\10-插槽-作用域插槽 vue --version vue crea…

01-JVM 内存结构

JVM 内存结构 Java 虚拟机的内存空间分为 5 个部分&#xff1a; 程序计数器Java 虚拟机栈本地方法栈堆方法区 JDK 1.8 同 JDK 1.7 比&#xff0c;最大的差别就是&#xff1a;元数据区取代了永久代。元空间的本质和永久代类似&#xff0c;都是对 JVM 规范中方法区的实现。不过…

【工具】利用ffmpeg将网页中的.m3u8视频文件转化为.mp4格式

目录 0.环境 1.背景 2.前提 3.详细描述 1&#xff09;在网站上找到你想下载的视频的.m3u8链接 2&#xff09;打开命令行&#xff0c;用ffmpeg命令进行转化 3&#xff09;过程&结果截图 0.环境 windows64 ffmpeg 1.背景 网页上有个.m3u8格式的视频文件&#xff0c;…

Redis 主从复制,哨兵,集群——(2)哨兵篇

目录 1. Redis 哨兵是什么&#xff1f; 2. Redis 哨兵有什么用&#xff1f; 2.1 主动监控 2.2 消息通知 2.3 故障转移 2.4 配置中心 3. Redis 哨兵数量配备要求 4. 哨兵配置文件详解 5. quorum 投票数详解 5.1 quorum 的含义 5.2 网络抖动导致主观下线 5.3 quorum …

一分钟带你了解网页升级访问原因

一分钟带你了解网页升级访问原因 相信大家肯定在日常浏览网页访问的时候会遇到页面紧急升级就是页面打不开的这种情况&#xff0c;其实就是暂时访问不了该网站的&#xff0c;很多小伙伴们搞不清楚网页升级访问是什么意思&#xff0c;也不知道网页升级访问原因?其实这种情况很常…

云计算与云服务

云计算与大数据 1、虚拟化简介1.1、什么是虚拟化1.2、虚拟化的分类 2、云计算与云服务2.1、云计算2.2、云服务2.3、云计算的特点 3、云服务模式&#xff08;IaaS、PaaS、SaaS和DaaS&#xff09;4、云计算分类&#xff08;公有云、私有云和混合云&#xff09; 1、虚拟化简介 当下…

单例模式(初学)

单例模式 1、概念 保证类只有一个实例&#xff0c;并提供一个全局访问点 2、方式 怎么样来保证只有一个类的实例呢 我们可以将类的构造器私有&#xff0c;让用户不能在new对象&#xff0c;让类自身负责保存它的唯一实例,并提供一个全局访问点。 3、代码 public class Singleto…

ToDoList全局事件总线学习笔记

全局事件总线 全局事件总线&#xff1a;任意组件间通信 安装全局事件总线 new Vue({……beforeCreate(){Vue.prototype.$busthis},…… })使用事件总线 接收数据&#xff1a;A组件想接收数据&#xff0c;则在A组件中给$bus绑定自定义事件&#xff0c;事件的回调留在A组件自…

react 学习 —— 16、使用 ref 操作 DOM

什么时候使用 ref 操作 DOM&#xff1f; 有时你可能需要访问由 React 管理的 DOM 元素 —— 例如&#xff0c;让一个节点获得焦点、滚动到它或测量它的尺寸和位置。在 React 中没有内置的方法来做这些事情&#xff0c;所以你需要一个指向 DOM 节点的 ref 来实现。 怎么使用 r…

vue3里面vant组件的标签页使用?

一、绑一个v-model事件 二、让activeName的初始为0也就是默认是显示第一个标签页的下标 三、给标签页下面的东西进行一个判断 想让哪个优先显示就把哪个判断作为初始值存入

【逆向】Base64编码解码及逆向识别

示例代码 注意&#xff1a;该示例代码仅为Base64编码实现的其中一种&#xff0c;实际分析样本的Base64编码实现并不一定与此代码相同&#xff0c;读者应重点理解其原理部分&#xff0c;而忽略其实现形式的不同。 View Code 逆向识别 1、编码识别 2、解码识别 总结 1、识别代…