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

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();
s.token = token;
s.intent = intent;
s.rebind = rebind;
if (DEBUG_SERVICE)
Slog.v(TAG, “scheduleBindService token=” + token + " intent=" + intent + " uid="

  • Binder.getCallingUid() + " pid=" + Binder.getCallingPid());
    sendMessage(H.BIND_SERVICE, s);
    }

ActivityThread.H

public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {

case BIND_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, “serviceBind”);
handleBindService((BindServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;

}

}

}

ActivityThread#handleBindService()

private void handleBindService(BindServiceData data) {
Service s = mServices.get(data.token); //1
if (DEBUG_SERVICE)
Slog.v(TAG, “handleBindService s=” + s + " rebind=" + data.rebind);
if (s != null) {
try {
data.intent.setExtrasClassLoader(s.getClassLoader());
data.intent.prepareToEnterProcess();
try {
if (!data.rebind) { //2
IBinder binder = s.onBind(data.intent); //3
ActivityManagerNative.getDefault().publishService(
data.token, data.intent, binder); //4
} else {
s.onRebind(data.intent); //5
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
ensureJitEnabled();
}

}

}
}

注释1处获取要绑定的Service 。
注释2处如果BindServiceData的成员变量rebind的值为false,这样会调用注释3处的代码来调用Service的onBind方法,这样Service处于绑定状态了。如果rebind的值为true就会调用注释5处的Service的onRebind方法,结合前文的bindServiceLocked方法的注释4,我们得知如果当前应用程序进程的Client端第一次与Service进行绑定,并且Service已经调用过onUnBind方法,则会调用Service的onRebind方法。
注释4的代码,实际上是调用AMS的publishService方法。

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

ActivityManagerService#publishService()

public void publishService(IBinder token, Intent intent, IBinder service) {

synchronized(this) {
if (!(token instanceof ServiceRecord)) {
throw new IllegalArgumentException(“Invalid service token”);
}
mServices.publishServiceLocked((ServiceRecord)token, intent, service);
}
}

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

ActiveServices#publishServiceLocked()

void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {

try {

for (int conni=r.connections.size()-1; conni>=0; conni–) {
ArrayList clist = r.connections.valueAt(conni);
for (int i=0; i<clist.size(); i++) {
ConnectionRecord c = clist.get(i);
if (!filter.equals(c.binding.intent.intent)) {
continue;
}
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Publishing to: " + c);
try {
c.conn.connected(r.name, service); //1
} catch (Exception e) {

}
}
}
}

serviceDoneExecutingLocked(r, mDestroyingServices.contains®, false);
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}

注释1处的代码,我在前面介绍过,c.conn指的是IServiceConnection,它的具体实现为ServiceDispatcher.InnerConnection,其中ServiceDispatcher是LoadedApk的内部类。

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

ServiceDispatcher

static final class ServiceDispatcher {

private static class InnerConnection extends IServiceConnection.Stub {
final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;

InnerConnection(LoadedApk.ServiceDispatcher sd) {
mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
}

public void connected(ComponentName name, IBinder service) throws RemoteException {
LoadedApk.ServiceDispatcher sd = mDispatcher.get();
if (sd != null) {
sd.connected(name, service); //1
}
}
}

}

注释1处调用了ServiceDispatcher类型的sd对象的connected方法。

ServiceDispatcher#connected()

public void connected(ComponentName name, IBinder service) {
if (mActivityThread != null) {
mActivityThread.post(new RunConnection(name, service, 0)); //1
} else {
doConnected(name, service);
}
}

注释1处调用Handler类型对象mActivityThread的post方法,mActivityThread实际上指向的是H。因此,通过调用H的post方法将RunConnection对象的内容运行在主线程中。来看看RunConnection的定义。

RunConnection

private final class RunConnection implements Runnable {
RunConnection(ComponentName name, IBinder service, int command) {
mName = name;
mService = service;
mCommand = command;
}

public void run() {
if (mCommand == 0) {
doConnected(mName, mService); //1
} else if (mCommand == 1) {
doDeath(mName, mService);
}
}

final ComponentName mName;
final IBinder mService;
final int mCommand;
}

注释1中调用了doConnected方法。

ServiceDispatcher#doConnected()

public void doConnected(ComponentName name, IBinder service) {
ServiceDispatcher.ConnectionInfo old;
ServiceDispatcher.ConnectionInfo info;

synchronized (this) {

old = mActiveConnections.get(name);


// If there was an old service, it is not disconnected.
if (old != null) {
mConnection.onServiceDisconnected(name);
}
// If there is a new service, it is now connected.
if (service != null) {
mConnection.onServiceConnected(name, service); //1
}
}

注释1处调用了ServiceConnection类型的对象mConnection的onServiceConnected方法,这样在客户端中实现了ServiceConnection接口的类的onServiceConnected方法就会被执行。

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

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

原文作者:huaxun66
原文链接:https://blog.csdn.net/huaxun66/article/details/78182265


更多系列教程GitHub白嫖入口:https://github.com/Timdk857/Android-Architecture-knowledge-2-

B站全套Android移动架构师进阶视频教程白嫖地址:https://space.bilibili.com/544650554

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

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

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
img

学习分享

在当下这个信息共享的时代,很多资源都可以在网络上找到,只取决于你愿不愿意找或是找的方法对不对了

很多朋友不是没有资料,大多都是有几十上百个G,但是杂乱无章,不知道怎么看从哪看起,甚至是看后就忘

如果大家觉得自己在网上找的资料非常杂乱、不成体系的话,我也分享一套给大家,比较系统,我平常自己也会经常研读。

2021最新上万页的大厂面试真题

七大模块学习资料:如NDK模块开发、Android框架体系架构…

只有系统,有方向的学习,才能在段时间内迅速提高自己的技术。

这份体系学习笔记,适应人群:
**第一,**学习知识比较碎片化,没有合理的学习路线与进阶方向。
**第二,**开发几年,不知道如何进阶更进一步,比较迷茫。
**第三,**到了合适的年纪,后续不知道该如何发展,转型管理,还是加强技术研究。如果你有需要,我这里恰好有为什么,不来领取!说不定能改变你现在的状态呢!

由于文章内容比较多,篇幅不允许,部分未展示内容以截图方式展示 。如有需要获取完整的资料文档的朋友点击我的【GitHub】免费获取。

…(img-8C55Rj4G-1710771285965)]

七大模块学习资料:如NDK模块开发、Android框架体系架构…

[外链图片转存中…(img-6uVgjhO9-1710771285965)]

只有系统,有方向的学习,才能在段时间内迅速提高自己的技术。

这份体系学习笔记,适应人群:
**第一,**学习知识比较碎片化,没有合理的学习路线与进阶方向。
**第二,**开发几年,不知道如何进阶更进一步,比较迷茫。
**第三,**到了合适的年纪,后续不知道该如何发展,转型管理,还是加强技术研究。如果你有需要,我这里恰好有为什么,不来领取!说不定能改变你现在的状态呢!

由于文章内容比较多,篇幅不允许,部分未展示内容以截图方式展示 。如有需要获取完整的资料文档的朋友点击我的【GitHub】免费获取。

  • 23
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值