Android-Framework学习笔记(八)Service的启动-绑定过程

本文详细解析了Android中ActivityThread创建Activity和Service的上下文环境,以及Service的启动和绑定过程,涉及ContextImpl、ActivityThread、AMS、ServiceRecord、ProcessRecord等关键组件的交互和工作原理。
摘要由CSDN通过智能技术生成


return activity;
}

注释1用来创建要启动Activity的上下文环境appContext。
注释2调用Activity的attach方法,将Activity与上下文关联起来。

ActivityThread#createBaseContextForActivity()

private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {

ContextImpl appContext = ContextImpl.createActivityContext(
this, r.packageInfo, r.token, displayId, r.overrideConfig); //1
appContext.setOuterContext(activity);
Context baseContext = appContext;

return baseContext;
}

static ContextImpl createActivityContext(ActivityThread mainThread,
LoadedApk packageInfo, IBinder activityToken, int displayId,
Configuration overrideConfiguration) {
if (packageInfo == null) throw new IllegalArgumentException(“packageInfo”);
return new ContextImpl(null, mainThread, packageInfo, activityToken, null, 0,
null, overrideConfiguration, displayId);
}

注释1处的上下文对象appContext 的具体类型就是ContextImpl 。Activity的attach方法中将ContextImpl赋值给ContextWrapper的成员变量mBase中,因此,mBase具体指向就是ContextImpl 。
具体是不是这样呢?看看Activity的attach方法:

frameworks/base/core/java/android/app/Activity.java

Activity#attach()

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) {
attachBaseContext(context); //1

}

Activity继承ContextThemeWrapper,ContextThemeWrapper继承ContextWrapper,因此注释1执行的是ContextWrapper类attachBaseContext方法。

ContextWrapper#attachBaseContext()

protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException(“Base context already set”);
}
mBase = base;
}

果不其然,因此,ContextWrapper中的mBase具体指向就是ContextImpl 。

继续来看mBase.startService方法,就是ContextImpl的startService方法。

frameworks/base/core/java/android/app/ContextImpl.java

ContextImpl#startService()

@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, mUser);
}

ContextImpl#startServiceCommon()

private ComponentName startServiceCommon(Intent service, UserHandle user) {
try {
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
//1
ComponentName cn = ActivityManagerNative.getDefault().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), getOpPackageName(), user.getIdentifier());

return cn;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}

注释1有没有很熟悉?在Framework学习(七)AMS家族一文说过AMS中Binder机制。注释1其实最终调用的是AMS的startService方法。

AMS到ActivityThread的调用

接着来查看AMS的startService方法。
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

ActivityManagerService#startService()

@Override
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, String callingPackage, int userId)
throws TransactionTooLargeException {

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); //1
Binder.restoreCallingIdentity(origId);
return res;
}
}

注释1处调用mServices的startServiceLocked方法,mServices的类型是ActiveServices。

frameworks/base/services/core/java/com/android/server/am/ActiveServices.java

ActiveServices#startServiceLocked()

ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, String callingPackage, final int userId)
throws TransactionTooLargeException {

return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
}

ActiveServices#startServiceInnerLocked()

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;
}

ActiveServices#bringUpServiceLocked()

private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {

final String procName = r.processName;//1
ProcessRecord app;
if (!isolated) {
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);//2
if (DEBUG_MU) Slog.v(TAG_MU, “bringUpServiceLocked: appInfo.uid=” + r.appInfo.uid

  • " app=" + app);
    if (app != null && app.thread != null) {//3
    try {
    app.addPackage(r.appInfo.packageName, r.appInfo.versionCode,
    mAm.mProcessStats);
    realStartServiceLocked(r, app, execInFg);//4
    return null;
    } catch (TransactionTooLargeException e) {
    throw e;
    } catch (RemoteException e) {
    Slog.w(TAG, "Exception when starting service " + r.shortName, e);
    }
    }
    } else {
    app = r.isolatedProc;
    }
    if (app == null && !permissionsReviewRequired) {//5
    if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
    “service”, r.name, false, isolated, false)) == null) {//6

    }
    if (isolated) {
    r.isolatedProc = app;
    }
    }

    }

和应用程序启动流程基本一致。
注释1处得到ServiceRecord的processName的值赋值给procName ,其中ServiceRecord用来描述Service的android:process属性。
注释2处将procName和Service的uid传入到AMS的getProcessRecordLocked方法中,来查询是否存在一个与Service对应的ProcessRecord类型的对象app,ProcessRecord主要用来记录运行的应用程序进程的信息。
注释5处判断Service对应的app为null则说明用来运行Service的应用程序进程不存在,则调用注释6处的AMS的startProcessLocked方法来创建对应的应用程序进程,具体创建过程参考Framework学习(六)应用程序进程启动过程。
注释3处表示Service的应用程序进程已经存在,则执行注释4的realStartServiceLocked方法。

ActiveServices#realStartServiceLocked()

private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {

try {

//1
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
r.postNotification();
created = true;
} catch (DeadObjectException e) {

}

}

注释1调用了app.thread的scheduleCreateService方法。其中app.thread是IApplicationThread类型的,它的实现是ActivityThread的内部类ApplicationThread,其中ApplicationThread继承了ApplicationThreadNative,而ApplicationThreadNative继承了Binder并实现了IApplicationThread接口。

ActivityThread启动Service
frameworks/base/core/java/android/app/ActivityThread.java

ApplicationThread#scheduleCreateService()

public final void scheduleCreateService(IBinder token,
ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
updateProcessState(processState, false);
CreateServiceData s = new CreateServiceData(); //1
s.token = token;
s.info = info;
s.compatInfo = compatInfo;

sendMessage(H.CREATE_SERVICE, s); //2
}

注释1将要启动的信息封装成CreateServiceData对象。
注释2将CreateServiceData对象通过sendMessage方法向H发送CREATE_SERVICE消息。

ApplicationThread#sendMessage()

private void sendMessage(int what, Object obj) {
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);
    }
    mH.sendMessage(msg);
    }

这里mH指的是H,它是ActivityThread的内部类并继承Handler。

ActivityThread.H

private class H extends Handler {
public static final int CREATE_SERVICE = 114;

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;

}

ActivityThread#handleCreateService()

private void handleCreateService(CreateServiceData data) {

LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo); //1
Service service = null;
try {
java.lang.ClassLoader cl = packageInfo.getClassLoader(); //2
service = (Service) cl.loadClass(data.info.name).newInstance(); //3
} catch (Exception e) {

}

try {
ContextImpl context = ContextImpl.createAppContext(this, packageInfo); //4
context.setOuterContext(service);

Application app = packageInfo.makeApplication(false, mInstrumentation); //5
service.attach(context, this, data.info.name, data.token, app,
ActivityManagerNative.getDefault()); //6
service.onCreate(); //7
mServices.put(data.token, service); //8

}
}

注释1处获取要启动Service的应用程序的LoadedApk,LoadedApk是一个APK文件的描述类。
注释2处通过调用LoadedApk的getClassLoader方法来获取类加载器。
注释3处根据CreateServiceData对象中存储的Service信息,通过反射创建service实例。
注释4处创建Service的上下文环境ContextImpl对象。
注释5处获取当前应用的Application对象,该对象的唯一作用就是作为参数传递到Service里,然后在Service类中可以获得调用getApplication方法来获取Application对象。
注释6处调用Service的attach方法初始化Service,将ContextImpl对象注册到对应的Service中,之后在Service类中就可以使用Context的所有功能了。
注释7处调用Service的onCreate方法,这样Service就启动了。
注释8处将启动的Service加入到ActivityThread的成员变量mServices中,其中mServices是ArrayMap类型。

最后看看Service的启动时序图:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Service的绑定过程

Service的绑定过程和Service的启动过程很多内容有重复,这里简单跟一下流程。

ContextImpl请求AMS

frameworks/base/core/java/android/content/ContextWrapper.java

ContextWrapper#bindService()

@Override
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
return mBase.bindService(service, conn, flags);
}

frameworks/base/core/java/android/app/ContextImpl.java

ContextImpl#bindService()

@Override
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
warnIfCallingFromSystemProcess();
return bindServiceCommon(service, conn, flags, mMainThread.getHandler(),
Process.myUserHandle());
}

ContextImpl#bindServiceCommon()

private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
handler, UserHandle user) {
IServiceConnection sd;
if (conn == null) {
throw new IllegalArgumentException(“connection is null”);
}
if (mPackageInfo != null) {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);//1
} else {
throw new RuntimeException(“Not supported in system context”);
}
validateServiceIntent(service);
try {

//2
int res = ActivityManagerNative.getDefault().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, getOpPackageName(), user.getIdentifier());

} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}

注释1处调用了LoadedApk类型的对象mPackageInfo的getServiceDispatcher方法,它的主要作用是将ServiceConnection封装为IServiceConnection类型的对象sd,从IServiceConnection的名字我们就能得知它实现了Binder机制,这样Service的绑定就支持了跨进程通信。
注释2处我们又看见了熟悉的代码,最终会调用AMS的bindService方法。

AMS到ActivityThread的调用
接着来查看AMS的bindService方法。
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

ActivityManagerService#bindService()

public int bindService(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, IServiceConnection connection, int flags, String callingPackage,
int userId) throws TransactionTooLargeException {


synchronized(this) {
return mServices.bindServiceLocked(caller, token, service,
resolvedType, connection, flags, callingPackage, userId);
}
}

frameworks/base/services/core/java/com/android/server/am/ActiveServices.java

ActiveServices#bindServiceLocked()

int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, final IServiceConnection connection, int flags,
String callingPackage, final int userId) throws TransactionTooLargeException {

if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
//1
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
permissionsReviewRequired) != null) {
return 0;
}
}

if (s.app != null && b.intent.received) { //2
try {
c.conn.connected(s.name, b.intent.binder); //3
} catch (Exception e) {

}
if (b.intent.apps.size() == 1 && b.intent.doRebind) { //4
requestServiceBindingLocked(s, b.intent, callerFg, true); //5
}
} else if (!b.intent.requested) { //6
requestServiceBindingLocked(s, b.intent, callerFg, false); //7
}
getServiceMap(s.userId).ensureNotStartingBackground(s);
} finally {
Binder.restoreCallingIdentity(origId);
}
return 1;
}

注释1处会调用bringUpServiceLocked方法,在bringUpServiceLocked方法中又会调用realStartServiceLocked方法,最终由ActivityThread来调用Service的onCreate方法启动Service,这一过程上面已经介绍了。
在注释2处s.app != null 表示Service已经运行,其中s是ServiceRecord类型对象,app是ProcessRecord类型对象。b.intent.received表示当前应用程序进程的Client端已经接收到绑定Service时返回的Binder,这样应用程序进程的Client端就可以通过Binder来获取要绑定的Service的访问接口。
注释3处调用c.conn的connected方法,其中c.conn指的是IServiceConnection,它的具体实现为ServiceDispatcher.InnerConnection,其中ServiceDispatcher是LoadedApk的内部类,InnerConnection的connected方法内部会调用H的post方法向主线程发送消息,从而解决当前应用程序进程和Service跨进程通信的问题,在后面会详细介绍这一过程。
注释4处如果当前应用程序进程的Client端第一次与Service进行绑定的,并且Service已经调用过onUnBind方法,则需要调用注释5的代码。
注释6处如果应用程序进程的Client端没有发送过绑定Service的请求,则会调用注释7的代码,注释7和注释5的代码区别就是最后一个参数rebind为false,表示不是重新绑定。
接着我们查看注释7的requestServiceBindingLocked方法。

ActiveServices#requestServiceBindingLocked()

private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
boolean execInFg, boolean rebind) throws TransactionTooLargeException {

if ((!i.requested || rebind) && i.apps.size() > 0) {//1
try {
bumpServiceExecutingLocked(r, execInFg, “bind”);
r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
r.app.repProcState);//2

}

}
return true;
}

注释1处i.requested表示是否发送过绑定Service的请求,从前面的代码得知是没有发送过,因此,!i.requested为true。从前面的代码得知rebind值为false,那么(!i.requested || rebind)的值为true。如果IntentBindRecord中的应用程序进程记录大于0,则会调用注释2的代码,r.app.thread的类型为IApplicationThread,它的实现我们已经很熟悉了,是ActivityThread的内部类ApplicationThread。

ActivityThread绑定Service

frameworks/base/core/java/android/app/ActivityThread.java

ApplicationThread#scheduleBindService()

public final void scheduleBindService(IBinder token, Intent intent,
boolean rebind, int processState) {
updateProcessState(processState, false);
BindServiceData s = new BindServiceData();
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

Android高级架构师

由于篇幅问题,我呢也将自己当前所在技术领域的各项知识点、工具、框架等汇总成一份技术路线图,还有一些架构进阶视频、全套学习PDF文件、面试文档、源码笔记。

  • 330页PDF Android学习核心笔记(内含上面8大板块)

  • Android学习的系统对应视频

  • Android进阶的系统对应学习资料

  • Android BAT部分大厂面试题(有解析)

好了,以上便是今天的分享,希望为各位朋友后续的学习提供方便。觉得内容不错,也欢迎多多分享给身边的朋友哈。

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!

droid高级架构师

由于篇幅问题,我呢也将自己当前所在技术领域的各项知识点、工具、框架等汇总成一份技术路线图,还有一些架构进阶视频、全套学习PDF文件、面试文档、源码笔记。

  • 330页PDF Android学习核心笔记(内含上面8大板块)

[外链图片转存中…(img-Nqi8a2Br-1712200122317)]

[外链图片转存中…(img-nKbDFDJ8-1712200122318)]

  • Android学习的系统对应视频

  • Android进阶的系统对应学习资料

[外链图片转存中…(img-w4ilg7Ao-1712200122318)]

  • Android BAT部分大厂面试题(有解析)

[外链图片转存中…(img-7hhxPbf4-1712200122319)]

好了,以上便是今天的分享,希望为各位朋友后续的学习提供方便。觉得内容不错,也欢迎多多分享给身边的朋友哈。

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!
  • 26
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值