Android 源码分析 StartService 启动
Posted 小图包
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 源码分析 StartService 启动相关的知识,希望对你有一定的参考价值。
startService 启动过程
ContextImpl 到 AMS 的调用过程
当我们在 Activity 中调用 startActivity 函数的时候,点击 startActivity 看源码实现会发现它是在 ContextWrapper 类中实现的。
我们继续看 Context 的 startService 实现,代码如下:
//Context.java
public abstract class Context
...
@Nullable
public abstract ComponentName startService(Intent service);
...
可以看到 Context 是一个抽象类,那么它具体实现是哪个类?我们之前介绍了 Activity 的启动,那么在启动的时候,就会创建 Context ,注意看下面代码,如下:
//ActivityThread.java
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent)
/**
* 1. 通过封装启动 Activity 信息类 ActivityClientRecord 来获取到 ActivityInfo
*/
ActivityInfo aInfo = r.activityInfo;
/**
* 2. 如果 r.packageInfo == null 就获取 LoadedApk 实例
*/
if (r.packageInfo == null)
r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
Context.CONTEXT_INCLUDE_CODE);
/**
* 3. 通过封装启动 Activity 信息类 ActivityClientRecord 来获取启动 Activity 组件的 ComponentName
*/
ComponentName component = r.intent.getComponent();
if (component == null)
component = r.intent.resolveActivity(
mInitialApplication.getPackageManager());
r.intent.setComponent(component);
if (r.activityInfo.targetActivity != null)
component = new ComponentName(r.activityInfo.packageName,
r.activityInfo.targetActivity);
/**
* 4. 创建Activity 中的上下文环境
*/
ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;
try
/**
* 拿到当前上下文加载的 ClassLoader 加载器
*/
java.lang.ClassLoader cl = appContext.getClassLoader();
/**
* 5. 调用 Instrumentation.newActivity 函数 ,内部通过 ClassLoader 类加载器来创建 Activity 的实例
*/
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null)
r.state.setClassLoader(cl);
catch (Exception e)
...
try
/**
* 6. 得到 Application 对象
*/
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
....
/**
* 7. 将 appContext 等对象依附在 Activity 的 attach 函数中,进行 Activity attach 初始化
*/
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback);
...
return activity;
我们看下注释 4 的实现,代码如下:
//ActivityThread.java
private ContextImpl createBaseContextForActivity(ActivityClientRecord r)
...
//1.创建 Activity 的 Context 对象
ContextImpl appContext = ContextImpl.createActivityContext(
this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);
...
return appContext;
//ContextImpl.java
static ContextImpl createActivityContext(ActivityThread mainThread,
LoadedApk packageInfo, ActivityInfo activityInfo, IBinder activityToken, int displayId,
Configuration overrideConfiguration)
...
2. 实例化 Context 的实现类 ContextImpl
ContextImpl context = new ContextImpl(null, mainThread, packageInfo, activityInfo.splitName,
activityToken, null, 0, classLoader);
...
return context;
通过上面代码我们知道,最后在 createActivityContext 函数中实例化了 ContextImpl 对象,现在我们回到 ActivityThread performLaunchActivity 函数,代码如下
//ActivityThread.java
activity.attach(appContext, this, getInstrumentation(), r.token,r.ident, app, r.intent, r.activityInfo, title, r.parent,r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback);
//Activity.java
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window, ActivityConfigCallback activityConfigCallback)
//调用父类函数
attachBaseContext(context);
....
//ContextThemeWrapper
public class ContextThemeWrapper extends ContextWrapper
...
@Override
protected void attachBaseContext(Context newBase)
super.attachBaseContext(newBase);
...
继续调用父类,代码如下:
public class ContextWrapper extends Context
Context mBase;
public ContextWrapper(Context base)
mBase = base;
protected void attachBaseContext(Context base)
if (mBase != null)
throw new IllegalStateException("Base context already set");
//赋值给 Context
mBase = base;
到最后我们看到 Context 的实现类 ContextImpl 赋值给了 ContextWrapper 的成员变量 mBase,现在我们直接去 ContextImpl 的 startService 看它具体实现,代码如下:
//ContextImpl
class ContextImpl extends Context
...
@Override
public ComponentName startService(Intent service)
warnIfCallingFromSystemProcess();
/**
* 调用内部 startServiceCommon 函数
*/
return startServiceCommon(service, false, mUser);
...
继续调用内部函数,代码如下:
//ContextImpl
private ComponentName startServiceCommon(Intent service, boolean requireForeground,
UserHandle user)
try
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
/**
* 调用 AMS 代理的 IActivityManager 的 startService 函数
*/
ComponentName cn = ActivityManager.getService().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), requireForeground,
getOpPackageName(), user.getIdentifier());
...
return cn;
catch (RemoteException e)
throw e.rethrowFromSystemServer();
我们已经见过了这种调用方式,其内部就是通过 aidl 来进行应用进程与 AMS(SystemServer) 进程通信,最后回调到 AMS 的 startService 函数
ActivityThread 启动 Service
通过上一小节我们知道最后会回到 AMS 的 startService 函数中,那么我们直接看 AMS 中的具体实现,代码如下:
//AMS.java
/**
* 这里是 ContextImpl 通过进程间通信调用的
* @param caller
* @param service
* @param resolvedType
* @param requireForeground
* @param callingPackage
* @param userId
* @return
* @throws TransactionTooLargeException
*/
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, boolean requireForeground, String callingPackage, int userId)
throws TransactionTooLargeException
...
try
1. 调用 ActiveService 的 startServiceLocked 函数
res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid,
requireForeground, callingPackage, userId);
finally
Binder.restoreCallingIdentity(origId);
return res;
注释 1 的代码具体实现是通过 ActiveService 类调用 startServiceLocked 函数,代码如下:
//ActiveService.java
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
throws TransactionTooLargeException
...
1. 查找是否有与参数 Service 对应的 ServiceRecord
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType, callingPackage,
callingPid, callingUid, userId, true, callerFg, false);
if (res == null)
return null;
if (res.record == null)
return new ComponentName("!", res.permission != null
? res.permission : "private to package");
2. 通过 ServiceLookupResult 得到参数 Service 对应的 ServiceRecord ,并传入到注释 3 处的 startServiceInnerLocked 中
*/
ServiceRecord r = res.record;
...
3. 调用内部 startServiceInnerLocked 函数
ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
return cmp;
在注释 1 处的 retrieveServiceLocked 函数会查找是否有与参数 service 对应的 ServiceRecord, 如果没有找到,就会调用 PMS 去获取参数 service 对应的 Service 信息,并封装到 ServiceRecord 中,最后将 ServiceRecord 封装为 ServiceLookupResult 返回。其中 ServiceRecord 用于描述一个 Service, 和此前讲过的 ActivityRecord 类似,在注释 2 中将得到的 ServiceRecord 赋值给注释 3 ,最后调用内部 startServiceInnerLocked 函数,代码如下:
//ActiveServices.java
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
boolean callerFg, boolean addToStarting) throws TransactionTooLargeException
...
/**
* 继续调用内部函数
*/
String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
...
return r.name;
我们继续看 bringUpServiceLocked 函数
//ActiveServices.java
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException
....
1. 获取 Service 想要在哪个进程中运行
final String procName = r.processName;
String hostingType = "service";
ProcessRecord app;
if (!isolated)
2. 将 procname 和 Service 的 uid 传入到 AMS 的getProcessRecordLocked 函数,查询是否已经存在了当前启动的 Service
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
3. 如果运行 Service 的应用程序进程已经存在
if (app != null && app.thread != null)
try
app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
/**
* 3.1 启动 Service
*/
realStartServiceLocked(r, app, execInFg);
return null;
...
else
...
4. 如果用来运行的 Service 的应用程序进程不存在
if (app == null && !permissionsReviewRequired)
5. 创建应用程序进程
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
hostingType, r.name, false, isolated, false)) == null)
String msg = "Unable to launch app "
+ r.appInfo.packageName + "/"
+ r.appInfo.uid + " for service "
+ r.intent.getIntent() + ": process is bad";
Slog.w(TAG, msg);
bringDownServiceLocked(r);
return msg;
....
return null;
主要逻辑就是通过在 AMS 查询需要启动的 Service 所在的进程是否已经存在,如果存在则启动 Service, 如果不存在就调用 注释 5 内部函数,创建一个应用程序进程。
我们接着看启动 Service 函数,代码如下:
//ActiveService.java
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException
...
/**
* 1. 调用 app.thread 函数,其实就是调用 IApplicationThread 的 scheduleCreateService 函数
*/
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
r.postNotification();
created = true;
catch (DeadObjectException e)
...
这里的函数如果调用了 scheduleCreateService 说明已经离开了 AMS 进程,那么 app.thread 到底是什么了?app.thread 就是 IApplicationThread 它是一个 aidl 文件,具体实现在 ActivityThread 的非静态内部类
//ActivityThread.java
public final class ActivityThread
...
private class ApplicationThread extends IApplicationThread.Stub
...
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);
...
这里调用内部重载函数这里只需记住 H.CREATE_SERVIC 标记,具体实现代码如下:
//ActivityThread.java
private void sendMessage(int what, Object obj)
1. 继续调用内部重载函数 what = H.CREATE_SERVIC
sendMessage(what, obj, 0, 0, false);
....
private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async)
if (DEBUG_MESSAGES) Slog.v(
TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
+ ": " + arg1 + " / " + obj);
Message msg = Message.obtain();
msg.what = what;
msg.obj = obj;
msg.arg1 = arg1;
msg.arg2 = arg2;
if (async)
msg.setAsynchronous(true);
2. 通过 H 的 Handler 将 what = H.CREATE_SERVIC 消息 what 发送出去
mH.sendMessage(msg);
H 类的 sendMessage 将标志为 H.CREATE_SERVIC 发送出去。这里的 H 类就是继承的 Handler
//ActivityThread.java
public final class ActivityThread
//初始化 H 类
final H mH = new H();
/**
* H 继承自 handler 是应用程序进程中主线程的消息管理类
*/
private class H extends Handler
...
public static final int CREATE_SERVICE = 114;
....
public void handleMessage(Message msg)
...
case CREATE_SERVICE:
//调用 handleCreateService
handleCreateService((CreateServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
...
H 的 handleMessage 接收到发送过来的消息,调用 handleCreateService 函数,我们来看下具体实现:
//ActivityService.java
private void handleCreateService(CreateServiceData data)
1. 拿到要启动 Service 的应用程序的 LoadApk
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try
2. 拿到类加载器
java.lang.ClassLoader cl = packageInfo.getClassLoader();
3. 创建 Servcie 实例
service = (Service) cl.loadClass(data.info.name).newInstance();
catch (Exception e)
...
try
if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
/**
* 4. 创建 Context 实例
*/
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
5. 拿到缓存中的 Application
Application app = packageInfo.makeApplication(false, mInstrumentation);
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
6. 执行 Service onCreate 生命周期
service.onCreate();
mServices.put(data.token, service);
try
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
catch (RemoteException e)
throw e.rethrowFromSystemServer();
catch (Exception e)
...
至此 主要通过 ClassLoader 加载 Service 类,与 service 绑定 Application 和 Context 一个是应用级别,一个是服务级别,最后执行 Service 生命周期 onCreate 函数,这样服务就启动了
以上是关于Android 源码分析 StartService 启动的主要内容,如果未能解决你的问题,请参考以下文章
Android 音频源码分析——AudioTrack设备选择