AndroidFramework 之启动 ServiceManager
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AndroidFramework 之启动 ServiceManager相关的知识,希望对你有一定的参考价值。
参考技术A本文源码基于 android 10 ,涉及相关源码如下。
ServiceManagaer 是 Binder 的守护进程,在 Binder 机制中起着重要的作用。本文将从源码的角度对其进行分析,整体流程如下:
时序图如下。
先来看看 ServiceManager 是如何启动的:
在 Zygote 一文中说过, init 进程启动的第二阶段会解析 init.rc 文件。
在这之后会触发 trigger init 。
结合 init.rc 看看 action init 做了什么。
当触发 trigger init 后,会启动 servicemanager 服务,其声明如下。
对应的执行文件为 /system/bin/servicemanager ,在编译前位于 frameworks/native/cmds/servicemanager 下,来看看 Android.bp 。
其对应的源码为 service_manager.c 和 binder.c ,入口函数 main() 位于 servicemanager.c 。
启动完 ServiceManager 后会打开 Binder 驱动。
在 main() 中首先调用 binder_open() 。
binder_open() 主要做了如下事情:
给结构体 binder_state 分配内存。
系统调用 open() 打开 /dev/binder ,如果打开驱动失败,则执行 fail_open 释放内存。
简单的解释一下什么是系统调用?
由于需要限制不同的程序之间的访问能力,防止程序获取别的程序的内存数据, CPU 划分出两个权限等级, 用户态 和 内核态 。
所有的用户程序都是运行在用户态,但有时需要做一些内核态的事情,而唯一可以做这些事情的就是操作系统,所以程序需要向操作系统发起请求,以程序的名字来执行这些操作。这时就需要一个从用户态切换到内核态但不能控制内核态中执行的机制,这种机制就是 系统调用 。
系统调用 ioctl() 传入 BINDER_VERSION 命令获取 Binder 驱动版本,对比版本是否一致,不一致则执行 fail_open 释放内存。
系统调用 mmap() 映射 128kb 的内存空间,即把 Binder 驱动文件的 128kb 映射到内存空间供 ServiceManager 使用,内存映射失败则执行 fail_map ,关闭 fd 并释放内存。
ServiceManager 进程 mmap 的内存大小可以通过 adb shell 命令查看。
可以看到内存映射地址为 0xf10f8000 ~ 0xf1118000 ,差为 0x20000 即十进制的 128kb 。
打开 Binder 驱动后会将 ServiceManager 设置为上下文管理者。
调用 binder_become_context_manager() 。
android 10 新增 BINDER_SET_CONTEXT_MGR_EXT 命令来设置安全的上下文管理者,如果设置失败,则使用原有的 BINDER_SET_CONTEXT_MGR 命令来设置上下文管理者,两者区别在于是否携带参数。
最后会进入循环,从 Binder 驱动读取和解析数据。
调用 binder_loop() 进入循环,不断地通过系统调用 ioctl() 从 Binder 驱动读取数据,并通过 binder_parse() 进行数据解析。
注意这里调用 binder_loop() 传入的 svcmgr_handler() ,后面会使用到。
binder_write() 会封装 struct binder_write_read ,并通过系统调用 ioctl() 将对应的命令传递给 Binder 驱动。
binder_parse() 用来解析从 Binder 驱动读取到的数据,然后根据不同的命令执行对应的操作。
因为 cmd 命令可能有多个,所以通过 while 循环每次处理一个 cmd 命令,多 cmd 的结构大致如下图所示。
这里重点看下 BR_TRANSACTION 命令。
BR_TRANSACTION 是 Binder 驱动向 Server 端发送请求数据。
binder_transaction_data 的结构如下,其表明了 transcation 传输的具体语义,语义码记录在 code 中,不同语义码携带的数据是不同的,这些数据由 data 指定。
在解析完 binder_transaction_data 的具体语义后,会调用前面传给 binder_loop() 的 svcmgr_handler() ,其实就是 switch case 语义码做不同的事情。
ServiceManager 的功能其实很简单:
至此 ServiceManager 就分析完了。
Android笔记 - Android启动之Launcher启动
Android 启动的第三阶段是 Launcher 的启动,也就是最终会看到的 Android 桌面的启动。在之前第二阶段 Android启动之Android Framework启动中, Zygote, ServiceManager, ActivityManagerService 和 PackageManagerService 等系统服务已经启动起来,接下来的 Launcher 启动过程就会看到它们的身影。由于 Launcher 也是应用程序,因此其他应用程序的启动过程基本类似。
ActivityManagerService 在完成服务注册等一系列初始化过程后,其 main 方法中会调用 systemReady 方法,开始以下过程:
ActivityStackSupervisor::resumeTopActivitiesLocked()
ActivityStackSupervisor::resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target, Bundle targetOptions)
ActivityStack::resumeTopActivityLocked(ActivityRecord prev, Bundle options)
ActivityStackSupervisor::resumeHomeActivity(ActivityRecord prev)
ActivityManagerService::startHomeActivityLocked(int userId)
需要注意的是 Launcher 启动过程中, resumeTopActivityLocked 方法会进入两次,第一次由于任务栈中还没有 ActivityRecord,所以会调用 resumeHomeActivity 方法。
经历以上5个方法调用,最后进入 ActivityManagerService 的 startHomeActivityLocked 方法开始 Launcher 启动历程。首先通过 getHomeIntent 方法获得启动 Launcher 的 intent 信息,然后调用 resolveActivityInfo 方法通过 PackageManagerService 获得 Launcher 的 Activity 描述信息 aInfo。如下所示:
代码路径:frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
boolean startHomeActivityLocked(int userId)
......
Intent intent = getHomeIntent();
ActivityInfo aInfo =
resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
if (aInfo != null)
intent.setComponent(new ComponentName(
aInfo.applicationInfo.packageName, aInfo.name));
// Don't do this if the home app is currently being
// instrumented.
aInfo = new ActivityInfo(aInfo);
aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);
ProcessRecord app = getProcessRecordLocked(aInfo.processName,
aInfo.applicationInfo.uid, true);
if (app == null || app.instrumentationClass == null)
intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
mStackSupervisor.startHomeActivity(intent, aInfo);
return true;
Intent getHomeIntent()
Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
intent.setComponent(mTopComponent);
if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL)
intent.addCategory(Intent.CATEGORY_HOME);
return intent;
从 getHomeIntent 方法的实现可知,理论上通过在应用程序的 AndroidManifest.xml 文件中添加 Intent.CATEGORY_HOME 的 Category 属性,应用就可以作为 Launcher 来启动。
获得参数 intent 和 aInfo 后,接下来调用 ActivityStackSupervisor 的 startHomeActivity 方法开始以下历程:
ActivityStackSupervisor::startHomeActivity(Intent intent, ActivityInfo aInfo)
ActivityStackSupervisor::startActivityLocked(...)
ActivityStackSupervisor::startActivityUncheckedLocked(...)
ActivityStack::startActivityLocked(...)
ActivityStackSupervisor::resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target, Bundle targetOptions)
ActivityStack::resumeTopActivityLocked(ActivityRecord prev, Bundle options)
ActivityStackSupervisor::startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig)
因为在上述步骤2中将会生成 Launcher 的 ActivityRecord 并添加到任务栈中,所以第二次进入 resumeTopActivityLocked 时,会调用 startSpecificActivityLocked 方法来启动 Launcher 的 Activity。由于 Launcher 是第一次运行,因此还没有创建好 Launcher 进程。在启动 Launcher 之前还需要创建一个新的进程,如下所示:
Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, null);
通过 Process 的 start 方法请求 Zygote 创建进程后,在新进程中开始执行 ActivityThread 的 main 方法。
代码路径:frameworks/base/core/java/android/app/ActivityThread.java
public static void main(String[] args)
......
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null)
sMainThreadHandler = thread.getHandler();
AsyncTask.init();
if (false)
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
main 方法中有很多值得说的知识点,但和 Launcher 启动有关的是执行 ActivityThread 的 attach 方法,该方法会调用代理类 ActivityManagerProxy 的 attachApplication 方法通知 ActivityManagerService 新进程已经启动成功,可以开始执行应用程序。传入的参数 mAppThread 是一个 ApplicationThread 类的 Binder 对象,用于之后进程间的通信。
Launcher 运行在新创建的进程,而 ActivityManagerService 运行在 system_server 进程,它们之间需要使用 Binder 来进行通信。
通过 Binder 进程间通信机制,ActivityManagerService 收到消息后,其 attachApplication 方法会被调用,接下来执行以下流程:
ActivityManagerService::attachApplicationLocked(IApplicationThread thread, int pid)
ApplicationThreadProxy::bindApplication(...)
通过之前传过来的 mAppThread 对象,调用代理类 ApplicationThreadProxy 的 bindApplication 方法。通过 Binder 通信,在 Launcher 进程中加载 Application 类并执行 onCreate 方法。这也说明,每个虚拟机进程中都会有一个 Application 实例。
接下来继续启动 Activity:
ActivityStackSupervisor::attachApplicationLocked(ProcessRecord app, boolean headless)
ActivityStackSupervisor::realStartActivityLocked(ActivityRecord r, ProcessRecord app, boolean andResume, boolean checkConfig)
ApplicationThreadProxy::scheduleLaunchActivity(...)
通过之前传过来的 mAppThread 对象,调用代理类 ApplicationThreadProxy 的 scheduleLaunchActivity 方法。通过 Binder 通信,最终会执行 ActivityThread 中的 handleLaunchActivity 方法,如下所示:
代码路径:frameworks/base/core/java/android/app/ActivityThread.java
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent)
......
Activity a = performLaunchActivity(r, customIntent);
if (a != null)
r.createdConfig = new Configuration(mConfiguration);
Bundle oldState = r.state;
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed);
......
handleLaunchActivity 中会加载 Launcher 应用程序的 class 文件,并调用 Activity 的 onCreate, onStart, onResume 等生命周期回调方法。
Launcher Activity 的 onCreate 方法中会初始化一个 Load 线程,用于加载所有的 workspace 数据以及应用程序图标。过程如下所示:
LauncherModel::startLoader(boolean isLaunching, int synchronousBindPage, int loadFlags)
LoaderTask::run()
LauncherModel::loadAndBindWorkspace()
LauncherModel::loadAndBindAllApps()
loadAndBindWorkspace 主要可分为 load 和 bind 两个阶段,load 阶段由 loadWorkspace 方法完成,主要是遍历数据库,生成 FolderInfo, LauncherAppWidgetInfo, ShortcutInfo 对象。bind 阶段由 bindWorkspace 方法完成,主要将之前得到的对象与 workspace 进行绑定。
loadAndBindAllApps 也分为 load 和 bind 两个阶段,load 阶段主要通过 PackageManagerService 提供的服务查询所有应用程序的 AppInfo 数据,bind 阶段则根据 AppInfo 在桌面显示应用程序。
至此,Android 启动流程梳理完毕。由于篇幅原因,中间有些内容点到为止,后续文章再继续完善。
参考资料:
1. Android系统默认Home应用程序(Launcher)的启动过程源代码分析
2. Launcher3的启动流程(一)
3. Launcher3的启动流程(二)
以上是关于AndroidFramework 之启动 ServiceManager的主要内容,如果未能解决你的问题,请参考以下文章
Android Framework学习视频-BootAnimation开机动画启动流程源码分析
Android笔记 - Android启动之Linux内核启动