注释1:通过 retrieveServiceLocked()
查找是否有与service对应的ServiceRecord
,如果没有找到就会调用 PackageManagerService
去获取参数对应的Service信息,并封装到 ServiceRecord然后再封装为一个 ServiceLookupResult
并返回。
注释2:把封装的 ServiceRecord
给拿出来。 ServiceRecord
用来描述一个Service
注释3:把 ServiceRecord传入到 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);
if (error != null) {
return new ComponentName(“!!”, error);
}
…
return r.name;
}
在 startServiceInnerLocked()
中调用了这么一个方法 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
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
if (DEBUG_MU) Slog.v(TAG_MU, “bringUpServiceLocked: appInfo.uid=” + r.appInfo.uid
- " app=" + app);
//3
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
//4. 启动Service
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 {
…
}
// 5
if (app == null && !permissionsReviewRequired) {
// 6
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®;
return msg;
}
…
}
…
return null;
}
注释1:从ServiceRecord中获取 processName赋值给 procName
注释2:根据 procName和Service的uid来传入到 AMS的 getProcessRecordLocked()
中,查询是否存在一个与Service对应的ProcessRecord类型对象。
如果不存在,则在注释5、6中调用 AMS的 startProcessLocked()
来创建一个引用程序进程。
如果存在,则在注释3、4中调用 realStartServiceLocked()
来启动一个Service。
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) {
Slog.w(TAG, "Application dead when creating service " + r);
mAm.appDiedLocked(app);
throw e;
} finally {
…
}
…
}
这里也有一个Real方法。app.thread.scheduleCreateService
即调用调用主线程的 scheduleCreateService()
的方法。
我们知道 app.thread
就是 IApplicationThread
,通过AIDL,这时候的代码从 SystemServer进程到了 应用程序的进程中。
// ActivityThread.java
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);
}
这里创建了一个 CreateServiceData
类,把Service的信息都封装了进去,设置一个 H.CREATE_SERVICE
字段,sendMessage出去。
到了 ApplicationThread
这里,免不了要使用Handler来将线程切换到主线程去。我们直接来看看 H
是怎么处理这个信息的吧
// ActivityThread.java
public void handleMessage(Message msg) {
switch (msg.what) {
case CREATE_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceCreate: " + String.valueOf(msg.obj)));
//1
handleCreateService((CreateServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
}
}
到了主线程中,调用 handleCreateService()
:
private void handleCreateService(CreateServiceData data) {
// 获取要启动Service的应用程序的 LoadedApk
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
java.lang.ClassLoader cl = packageInfo.getClassLoader();
//1
service = (Service) cl.loadClass(data.info.name).newInstance();
} catch (Exception 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);
//2
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
//3
service.onCreate();
//4
mServices.put(data.token, service);
…
} catch (Exception e) {
…
}
}
这里的代码和创建Activity时的非常相似。
注释1:通过LoadedApk的getClassLoader()
来获取一个类加载器。然后根据 CreateServiceData 来创建一个 Service实例。
注释2:通过 service.attach()
来初始化一个service
注释3:调用这个 service的 onCreate()
方法。这里 service就启动了。
注释4:最后,把这个service放到 ActivityThread的成员变量 mServices中,它是一个 ArrayMap
。
至此,一个Service的完整的创建启动流程就over了。
下面来讲解绑定一个Service。
===============================================================================
因为Service的开启方法有 startService()
, 也有 bindService()
Service的绑定过程分成3个部分
-
ContextImpl到AMS的调用过程
-
AMS调用 bindService() 到 publishService() 过程
-
AMS到 ServiceConnection的过程
我们先来看一下时序图:
在代码中调用 context.bindService()
,就是调用 mBase.bindService()
从之前我们学过, mBase就是 ContextImpl。我们来看看它的 bindService()
:
// ContextImpl.java
@Override
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
warnIfCallingFromSystemProcess();
return bindServiceCommon(service, conn, flags, mMainThread.getHandler(),
Process.myUserHandle());
}
这个方法传入了 Intent
,ServiceConntection
(Service连接的回调),和 flags
,然后这个方法里面带上了 主线程的Handler,传入到 bindServiceCommom
里面去:
// ContextImpl.java
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) {
//1
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
} else {
throw new RuntimeException(“Not supported in system context”);
}
validateServiceIntent(service);
try {
…
// 2
int res = ActivityManager.getService().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, getOpPackageName(), user.getIdentifier());
if (res < 0) {
throw new SecurityException(
"Not allowed to bind to service " + service);
}
return res != 0;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
在注释1中,通过 LoadedApk.getServiceDispatcher()
将传进来的 ServiceConnection
封装成一个 IServiceConnection
对象。
也就是说 ServiceConnection也是实现了Binder的。
注释2中:调用 ActivityManager.getSerive()
即 IActivityManager.bindSerive()
,这里代码进入到 AMS层。
2.2 AMS调用 bindService() 到 publishService() 过程
先来看看时序图:
我们来看看 AMS的 bindService()
:
// ActivityManagerService
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);
}
}
省略号中的代码都是异常判断处理。
在 synchronized
中调用了 ActiveService.bindServiceLocked()
:
// ActivityManagerService.java
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, final IServiceConnection connection, int flags,
String callingPackage, final int userId) throws TransactionTooLargeException {
…
try {
…
//1
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
//2
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
permissionsReviewRequired) != null) {
return 0;
}
}
…
//3
if (s.app != null && b.intent.received) {
try {
//4
c.conn.connected(s.name, b.intent.binder, false);
} …
if (b.intent.apps.size() == 1 && b.intent.doRebind) {
//5
requestServiceBindingLocked(s, b.intent, callerFg, true);
}
} else if (!b.intent.requested) {
//6
requestServiceBindingLocked(s, b.intent, callerFg, false);
}
…
}
这个方法里面出现了几个 Record,我们来看一下他们分别描述什么:
- ServiceRecord
用来描述一个 Service
- ProcessRecord
描述一个进程
- ConnectionRecord
描述应用程序进程和 Service建立的一次通信
- AppBindRecord
应用程序进程通过Intent绑定Service时,会通过AppBindRecord来维护Service与应用程序进程之间的关联。
其内部会创建并存储了 谁绑定的Service(ProcessRecord
)、被绑定的Service(AppBindRecord
)、绑定Service的 Intent(IntentBindRecord
)和所有绑定通信记录的信息(ArraySet<ConnectionRecord>
)
- IntentBindRecord
用于描述绑定Service的Intent
注:不同的应用进程也可能会创建相同的Intent来绑定同一个Serivce。比如说一些公共的、常用的Service。
注释1:调用了 ServiceRecord.retrieveAppBindingLocked()
,获取一个service的 AppBindRecord
对象。我们在前面关于AppBindRecord的介绍可以看到,它内部会创建 IntentBindRecord
并赋值。
注释2:如果传进来的flags == BIND_AUTO_CREATE
就会调用了 bringUpServiceLocked()
,其内部会调用 realStartServiceLocked()
,这个方法我们学习Service的启动流程的时候学到过,其为与服务端的最后一个方法,它会通过Binder最终到 ActivityThread去,然后调用 Service.onCreate()
。这也就是说在Service的绑定流程中也会去启动Serivce。
注释3: s.app != nul
表示Service已经运行。其中s是ServiceRecord, app是ProcessRecord。 b.intent.received
表示当前应用进程已经接收到绑定Service时返回的Binder,这样应用程序就可以通过Binder来获取要绑定的Service的访问接口。
注释4:调用c.conn的 connected
,其中 c.conn就是我们一开始封装好的 IServiceConenction
,它的具体实现类为 ServiceDispatcher.InnerConnection
,其中ServiceDispatcher是 LoadedApk的内部类,InnerConnection的 connected
方法会调用H的post()
向主线程发送消息。
注释5:如果当前应用程序进程是第一个与Service进行绑定的,并且Service已经调用过 onUnBind()
,则就会调用 requestServiceBindingLocked(...,true)
,最后的参数 rebind是true
注释6:如果应用程序进程的Client端没有发送过绑定Service的请求,则也会调用 requestServiceBindingLocked(...,flase)
。最后的rebind是flase
我们来看下注释5的 requestServiceBindingLocked()
:
// ActivesServices.java
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
boolean execInFg, boolean rebind) throws TransactionTooLargeException {
…
//1
if ((!i.requested || rebind) && i.apps.size() > 0) {
try {
bumpServiceExecutingLocked(r, execInFg, “bind”);
r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
//2
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
r.app.repProcState);
if (!rebind) {
i.requested = true;
}
i.hasBound = true;
i.doRebind = false;
} catch (TransactionTooLargeException e) {
…
}
}
return true;
}
注释1中的 i.requested
表示 是否发送过绑定Service的请求,从bindServiceLocked
可以得知已经发送过绑定了,因此 !i.requested == false
。从 bindServiceLocked
中我们得知 rebind为true。所以这里是可以继续走下去的。
i.apps.size()
中,i指的是 IntenBindRecord
,AMS会为每个绑定的Service的Intent分配一个IntentBindRecord对象。我们来看一下IntentBindRecord的代码:
// ActiveServices.java
final class IntentBindRecord {
//被绑定的Service
final ServiceRecord service;
//绑定Service的Intent
final Intent.FilterComparison intent; //
//所有用当前Intent绑定Service应用程序进程
final ArrayMap<ProcessRecord, AppBindRecord> apps
= new ArrayMap<ProcessRecord, AppBindRecord>();
…
}
不同的应用程序进程可能使用同一个Intent来绑定Service,所以我们看到 apps用来存储这些进程。
之前说过 i.apps.size() > 0
就是说明已经有Intent绑定了Serivice了。下面来验证 i.apps.size()>0
为true。我们回到 bindServiceLocked()
的注释1代码处,即 retrieveAppBindingLocked()
:
// ServiceRecord.java
public AppBindRecord retrieveAppBindingLocked(Intent intent,
ProcessRecord app) {
Intent.FilterComparison filter = new Intent.FilterComparison(intent);
IntentBindRecord i = bindings.get(filter);
if (i == null) {
//1
i = new IntentBindRecord(this, filter);
bindings.put(filter, i);
}
//2
AppBindRecord a = i.apps.get(app);
if (a != null) {
return a;
}
//3
a = new AppBindRecord(this, i, app);
i.apps.put(app, a);
return a;
}
注释1:创建了 IntentBindRecord
注释2:根据ProcessRecord获取了 AppBindRecord,如果其不为null就会返回。
如果为null就在注释3中,创建一个新的 AppBindRecord
,并将其put到 apps中,key为 ProcessRecord。
这里代码也就表明, i.apps.size() > 0
是为true的。 这样也就会调用上述 requestServiceBindingLocked(...,true)
中,注释2 的代码。
r.app.thread
是 IApplicationThread,所以 它执行的 scheduleBindService()
肯定就是通过调用 H类来切换线程到ActivityThread中。
因为这里很熟悉,我们直接看ActivityThread最终会执行什么代码:
// ActivityThread.java
public void handleMessage(Message msg) {
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;
…
}
}
private void handleBindService(BindServiceData data) {
//1
Service s = mServices.get(data.token);
…
if (s != null) {
try {
data.intent.setExtrasClassLoader(s.getClassLoader());
data.intent.prepareToEnterProcess();
try {
//2
if (!data.rebind) {
//3
IBinder binder = s.onBind(data.intent);
//4
ActivityManager.getService().publishService(
data.token, data.intent, binder);
} else {
//5
s.onRebind(data.intent);
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
ensureJitEnabled();
} …
} …
}
}
在 handleBindService()
中,我们得知:
注释1:获取要绑定的Service
注释2:BindServiceData
这个类的成员变量 rebind的值为false,就会调用注释3的 Service.onBind()
方法,到这里Service就绑定成功了。
注释5:否则执行 Service.onRebind()
,如果当前应用程序进程第一个与Service绑定,并且Service已经调用过 onUnBind()
,则会调用Service的 onReBind()
。
handleBindService有两个分支,一个是绑定过的Service的情况,一个是未绑定过Service的情况。这里分析没有绑定过的情况。
也就是注释3、注释4的代码。
注释3我们已经了解了,就是调用Service.onBind(),在接下来的注释4中,调用了 ActivityManagerService.publishService()
,这相当于又回到AMS中。
我们先来看一下从AMS到ServiceConnection的过程的时序图:
在AMS的publishService里面调用了 ActiveServices.publishServicedLocked()
,我们来看看这个方法
// ActiveServices.java
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
final long origId = Binder.clearCallingIdentity();
try {
…
for (int conni=r.connections.size()-1; conni>=0; conni–) {
…
try {
//1
c.conn.connected(r.name, service, false);
} …
}
}
}
serviceDoneExecutingLocked(r, mDestroyingServices.contains®, false);
}
} …
}
这个方法传入一个ServiceRecord,然后会去遍历每个绑定这个Service的Intent,每个就是一个 ConnectionRecord
,也就是c
调用 c.conn
就是获取到每次遍历的 IServiceConnection
,它的作用是解决当前应用程序进程和Service跨进程通信的问题。
具体实现为类ServiceDispatcher.InnerConnection
,我们来看看 InnerConnection的connected()
// LoadedApk.java
tatic 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, boolean dead)
throws RemoteException {
LoadedApk.ServiceDispatcher sd = mDispatcher.get();
if (sd != null) {
//1
sd.connected(name, service, dead);
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
最后
给大家分享一份移动架构大纲,包含了移动架构师需要掌握的所有的技术体系,大家可以对比一下自己不足或者欠缺的地方有方向的去学习提升;
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
dead);
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-AT6ohjeo-1712867345700)]
[外链图片转存中…(img-MapgJafM-1712867345701)]
[外链图片转存中…(img-cvpVDa3w-1712867345701)]
[外链图片转存中…(img-H7F2wk81-1712867345701)]
[外链图片转存中…(img-X9RUWcwT-1712867345701)]
[外链图片转存中…(img-CVxMbUGY-1712867345702)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-r1Lry1iI-1712867345702)]
最后
给大家分享一份移动架构大纲,包含了移动架构师需要掌握的所有的技术体系,大家可以对比一下自己不足或者欠缺的地方有方向的去学习提升;
[外链图片转存中…(img-j6s6TBUi-1712867345702)]
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-MKd7fwne-1712867345703)]