Service的启动流程源码跟踪
前言:
当我们在一个Activity里面startService的时候,具体的执行逻辑是怎么样的?需要我们一步步根据源码阅读。
当我们在一个Activity里面startService的时候,具体的执行逻辑是怎么样的?需要我们一步步根据源码阅读。
在阅读源码的时候,要关注思路,不要陷在具体的实现细节中,一步步整理代码的思路。
注:源码使用Api 25的
startService">1.起点:Activity-> startService
在Activity中没有找到startService的方法,
查看Activity的继承关系:
Context->ContextWrapper->ContextThemeWrapper->Activity
回溯到ContextWrapper中,找到了startService()的方法:
@Override
public ComponentName startService(Intent service) {
return mBase.startService(service);
}
从ContextWrapper的命名和方法的实现上,我们可以猜到其实ContextWrapper只是一个包装
真正实现startService逻辑的是调用mBase.startService(service);
其中
Context mBase;是一个成员变量
由于Context是一个抽象类,startService是它的抽象方法,所以一定存在一个Context的子类实现了Context的抽象方法。
其实就是ContextImpl类,所以Context的抽象方法的具体实现由ContextImpl负责,其他Context的子类只需要在自己的方法里面调用
ContextImpl的即可。
startService(Intent service)">2.ContextImpl ->startService(Intent service)
@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, mUser);
}
调用到startServiceCommon(service, mUser)
private ComponentName startServiceCommon(Intent service, UserHandle user) {
try {
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
ComponentName cn = ActivityManagerNative.getDefault().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), getOpPackageName(), user.getIdentifier());
//省略部分代码
}
return cn;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
可以看到是调用ActivityManagerNative的 ActivityManagerNative.getDefault().startService方法
ActivityManagerNative.getDefault().startService">3.ActivityManagerNative-> ActivityManagerNative.getDefault().startService
观察public abstract class ActivityManagerNative extends Binder implements IActivityManager的定义
可以猜测这是一个可以Binder进程IPC操作的类。
PS:如果你对Binder还很陌生推荐你先了解Binder,不需要深入到底层实现,不过Java层的基本用法需要了解
下面的博客都可以参考:
weishu的博客
Gityuan的博客
引用一个对Binder很精彩的描述:
Binder使得一个进程A有一个真身,它实现了具体的逻辑,然后其他进程获得的是Binder的影子(或者说是引用?句柄?)
然后其他进程通过Binder的影子调用就仿佛调用了A的真身的操作。
其实很多资料都告诉我们启动四大组件是IPC的操作,app进程必须通过IPC与另外的进程通信,完成四大组件的启动。
结合上面的描述,我们知道,那么app进程的是影子。我们找到它:
在ActivityManagerNative它有一个子类:
class ActivityManagerProxy implements IActivityManager{
//省略代码
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, String callingPackage, int userId) throws RemoteException
{
Parcel data = Parcel.obtain();//写入参数值
Parcel reply = Parcel.obtain();//保持返回值
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
service.writeToParcel(data, 0);
data.writeString(resolvedType);
data.writeString(callingPackage);
data.writeInt(userId);
mRemote.transact(START_SERVICE_TRANSACTION, data, reply, 0);//挂起,通过Binder驱动IPC
reply.readException();
ComponentName res = ComponentName.readFromParcel(reply);
data.recycle();
reply.recycle();
return res;
}
//省略代码
}
这就是影子,我们在App进程调用的startService最终会到达这里,然后经过Binder驱动的一系列操作到达另外一个进程的真身
所以:ActivityManagerNative.getDefault()这里获取的应该就是ActivityManagerProxy 的实例,我们看一下它的实现:
static public IActivityManager getDefault() {
return gDefault.get();
}
….
** gDefault **这是一个单例对象
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
protected IActivityManager create() {
IBinder b = ServiceManager.getService("activity");//注意这里,通过**ServiceManager**获取的字符串"activity"的IBinder
if (false) {
Log.v("ActivityManager", "default service binder = " + b);
}
IActivityManager am = asInterface(b);
if (false) {
Log.v("ActivityManager", "default service = " + am);
}
return am;
}
};
}
我们可以看到最终获取的是:IActivityManager am = asInterface(b);
asInterface的代码:
/**
* Cast a Binder object into an activity manager interface, generating
* a proxy if needed.
*/
static public IActivityManager asInterface(IBinder obj) {
if (obj == null) {
return null;
}
//如果是不是IPC调用执行下面的代码:
IActivityManager in =
(IActivityManager)obj.queryLocalInterface(descriptor);
if (in != null) {
return in;
}
//如果是IPC调用执行下面的代码:
return new ActivityManagerProxy(obj);
}
可以看到我们通过:return new ActivityManagerProxy(obj);
获取到了影子的实例。
一句话总结:ActivityManagerNative.getDefault().startService()
最终调用的是ActivityManagerProxy 的startService()方法
这里将有一个IPC的逻辑:
mRemote.transact(START_SERVICE_TRANSACTION, data, reply, 0);
经过Binder驱动的各种操作
最终是运行到ActivityManagerNative的
onTransact方法里面的。
onTransact()">ActivityManagerNative->onTransact()
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
switch (code) {
//省略代码
case START_SERVICE_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder b = data.readStrongBinder();
IApplicationThread app = ApplicationThreadNative.asInterface(b);
Intent service = Intent.CREATOR.createFromParcel(data);
String resolvedType = data.readString();
String callingPackage = data.readString();
int userId = data.readInt();
ComponentName cn = startService(app, service, resolvedType, callingPackage, userId);
reply.writeNoException();
ComponentName.writeToParcel(cn, reply);
return true;
}
//省略代码
}
最终调用的是:
ComponentName cn = startService(app, service, resolvedType, callingPackage, userId);(注意这里已经不是运行在App的进程的,而是在system_Server进程中,system_Server是由Zygote进程孵化出来的。)
在ActivityManagerNative中找不到 startService(app, service, resolvedType, callingPackage, userId);这个方法,由于ActivityManagerNative是一个抽象类,自然想到方法的实现在子类中,其实就是ActivityManagerService
startService()">4.ActivityManagerService->startService()
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, String callingPackage, int userId)
throws TransactionTooLargeException {
enforceNotIsolatedCaller("startService");
// Refuse possible leaked file descriptors
if (service != null && service.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
if (callingPackage == null) {
throw new IllegalArgumentException("callingPackage cannot be null");
}
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
"startService: " + service + " type=" + resolvedType);
synchronized(this) {
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
ComponentName res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid, callingPackage, userId);
Binder.restoreCallingIdentity(origId);
return res;
}
}
调用的是mServices.startServiceLocked()方法
mService是:
final ActiveServices mServices;
startServiceLocked">5.ActiveServices ->startServiceLocked
最终调用的是
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
ServiceState stracker = r.getTracker();
if (stracker != null) {
stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
}
r.callStart = false;
synchronized (r.stats.getBatteryStats()) {
r.stats.startRunningLocked();
}
//调用这个方法:
String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
if (error != null) {
return new ComponentName("!!", error);
}
if (r.startRequested && addToStarting) {
boolean first = smap.mStartingBackground.size() == 0;
smap.mStartingBackground.add(r);
r.startingBgTimeout = SystemClock.uptimeMillis() + BG_START_TIMEOUT;
if (DEBUG_DELAYED_SERVICE) {
RuntimeException here = new RuntimeException("here");
here.fillInStackTrace();
Slog.v(TAG_SERVICE, "Starting background (first=" + first + "): " + r, here);
} else if (DEBUG_DELAYED_STARTS) {
Slog.v(TAG_SERVICE, "Starting background (first=" + first + "): " + r);
}
if (first) {
smap.rescheduleDelayedStarts();
}
} else if (callerFg) {
smap.ensureNotStartingBackground(r);
}
return r.name;
}
startServiceInnerLocked()调用的是 String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
bringUpServiceLocked(r, service.getFlags(), callerFg, false, false)方法:
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
//省略代码
if (!isolated) {
//注意这里获取的需要启动Service的进程的信息
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
+ " app=" + app);
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
//调用到这里:
realStartServiceLocked(r, app, execInFg);
return null;
} catch (TransactionTooLargeException e) {
throw e;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting service " + r.shortName, e);
}
// If a dead object exception was thrown -- fall through to
// restart the application.
}
} else {
// If this service runs in an isolated process, then each time
// we call startProcessLocked() we will get a new isolated
// process, starting another process if we are currently waiting
// for a previous process to come up. To deal with this, we store
// in the service any current isolated process it is running in or
// waiting to have come up.
app = r.isolatedProc;
}
//省略代码
}
调用到了realStartServiceLocked()
private final void realStartServiceLocked(ServiceRecord r,ProcessRecord app, boolean execInFg) throws RemoteException {
//省略代码
这里就回到的app的进程
app.thread.scheduleCreateService(r,r.serviceInfo,mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),app.repProcState);
//省略代码
}
scheduleCreateService()">最终调用ActivityThread里面的ApplicationThread->scheduleCreateService()
public final void scheduleCreateService(IBinder token,
ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
updateProcessState(processState, false);
CreateServiceData s = new CreateServiceData();
s.token = token;
s.info = info;
s.compatInfo = compatInfo;
sendMessage(H.CREATE_SERVICE, s);
}
6.由ActivityThread的内部的Handler处理 sendMessage(H.CREATE_SERVICE, s);发送的消息
private class H extends Handler {
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
//略
case CREATE_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceCreate: " + String.valueOf(msg.obj)));
handleCreateService((CreateServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
//略
}
}
最终是通过反射创建一个新的Service,然后调用它的onCreate()方法
private void handleCreateService(CreateServiceData data) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();//反射创建一个新的Service
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
"Unable to instantiate service " + data.info.name
+ ": " + e.toString(), e);
}
}
try {
if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
Application app = packageInfo.makeApplication(false, mInstrumentation);
service.attach(context, this, data.info.name, data.token, app,
ActivityManagerNative.getDefault());
service.onCreate();//调用Service的onCreate()方法
mServices.put(data.token, service);
try {
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
"Unable to create service " + data.info.name
+ ": " + e.toString(), e);
}
}
}
总结:
我们可以看到其实启动一个Service的过程也是挺复杂的,由于能力所限,仅跟踪了Java Framework这一层的代码,深入到底层的就不分析了。可以参考Gityuan大神的博客。
Service的启动流程源码跟踪的更多相关文章
- 【图解源码】Zookeeper3.7源码分析,包含服务启动流程源码、网络通信源码、RequestProcessor处理请求源码
Zookeeper3.7源码剖析 能力目标 能基于Maven导入最新版Zookeeper源码 能说出Zookeeper单机启动流程 理解Zookeeper默认通信中4个线程的作用 掌握Zookeepe ...
- Android Activity启动流程源码全解析(1)
前言 Activity是Android四大组件的老大,我们对它的生命周期方法调用顺序都烂熟于心了,可是这些生命周期方法到底是怎么调用的呢?在启动它的时候会用到startActivty这个方法,但是这个 ...
- Android Activity启动流程源码全解析(2)
接上之前的分析 ++Android Activity启动流程源码全解析(1)++ 1.正在运行的Activity调用startPausingLocked 一个一个分析,先来看看startPausing ...
- Spark(五十一):Spark On YARN(Yarn-Cluster模式)启动流程源码分析(二)
上篇<Spark(四十九):Spark On YARN启动流程源码分析(一)>我们讲到启动SparkContext初始化,ApplicationMaster启动资源中,讲解的内容明显不完整 ...
- Spark(四十九):Spark On YARN启动流程源码分析(一)
引导: 该篇章主要讲解执行spark-submit.sh提交到将任务提交给Yarn阶段代码分析. spark-submit的入口函数 一般提交一个spark作业的方式采用spark-submit来提交 ...
- Spring IOC 容器预启动流程源码探析
Spring IOC 容器预启动流程源码探析 在应用程序中,一般是通过创建ClassPathXmlApplicationContext或AnnotationConfigApplicationConte ...
- Spring IOC容器启动流程源码解析(四)——初始化单实例bean阶段
目录 1. 引言 2. 初始化bean的入口 3 尝试从当前容器及其父容器的缓存中获取bean 3.1 获取真正的beanName 3.2 尝试从当前容器的缓存中获取bean 3.3 从父容器中查找b ...
- Spring Boot的自动配置原理及启动流程源码分析
概述 Spring Boot 应用目前应该是 Java 中用得最多的框架了吧.其中 Spring Boot 最具特点之一就是自动配置,基于Spring Boot 的自动配置,我们可以很快集成某个模块, ...
- springboot的启动流程源码分析
.测试项目,随便一个简单的springboot项目即可: 直接debug调试: 可见,分2步,第一步是创建SpringApplication对象,第二步是调用run方法: 1.SpringApplic ...
随机推荐
- CVE-2012-2122-Mysql身份认证漏洞及利用
一.漏洞简介 当连接MariaDB/MySQL时,输入的密码会与期望的正确密码比较,由于不正确的处理,会导致即便是memcmp()返回一个非零值,也会使MySQL认为两个密码是相同的.按照公告说法大约 ...
- 2017qcon大会的一点想法(安全人才如何不被淘汰?)
2017 qcon 上海专门设立了“直击黑产,业务安全的攻与防”专题,通过这次专题的了解和学习,让我对黑产的攻防有了更深入认识. 1. 安全防护趋势 2017 qcon 上海专门设立了“直击黑产,业务 ...
- [web]深入理解Session和Cookie
一.理解Cookie 由于http是一种无状态的协议,当用户的一次访问结束后,后端的服务器就无法知道下一次来访问的请求是不是上一次的用户了.那么Cookie的作用就是用户通过http访问一个服务器时, ...
- window下Ionic环境安装
安装以下文件 1.java.jdk 2apache ant 3.android skd 4.node 目前是这几个. 大该流程就是这样子的. Ionic官方教程: http://learn.ioni ...
- SQL语句之数据库操作
SQL语句系列 1.SQL语句之行操作 2.SQL语句之表操作 3.SQL语句之数据库操作 4.SQL语句之用户管理 占坑,带写……
- requests库的使用
requests库的使用 pip快速安装 pip install requests 请求方法 每一个请求方法都有一个对应的API,比如GET请求就可以使用get()方法: import reques ...
- php中慎用==
var_dump(' 123fg456'==123);var_dump('some string' == 0);var_dump(123.0 == '123d456');var_dump(0 == & ...
- Python爬虫常用之登录(三) 使用http请求登录
前面说了使用浏览器登录较为简单,不需要过多分析,而使用请求登录恰恰就是以分析为主. 开发一个请求登录程序的流程: 分析请求->模拟请求->测试登录->调整参数->测试登录-&g ...
- Shiro源码解析-Session篇
上一篇Shiro源码解析-登录篇中提到了在登录验证成功后有对session的处理,但未详细分析,本文对此部分源码详细分析下. 1. 分析切入点:DefaultSecurityManger的login方 ...
- 【车联网T-BOX】基于CANoe实现的远程服务业务自动化测试方案
为满足项目过程中不同阶段绝大部分测试需求,更方便快捷构造测试场景,支持异常场景测试.更早介入,不依赖周边ECU的稳定情况,专注于被测ECU.更经济,不加油,不充电,时间节省,物料节省等维度考虑.我们需 ...