hi,粉丝朋友们大家好!
今天本来是想给大家写一下高级面试问题答案的,题目:如果一个进程自己调用自己的跨进程接口是否会通过binder,但是刚好这部分又要涉及到Service,那么就来给大家刚好源码级别分析一下bindService。
入门课,实战课,跨进程专题
ps需要学习深入framework课程和课程优惠
(可以加我qq:2102309716 优惠购买)
一般我们发起bindService来绑定远程服务Service,调用如下:
Intent intent = new Intent(MainActivity.this,MyService.class);
// startService(intent);
bindService(intent, new ServiceConnection() {},BIND_AUTO_CREATE);
这里就直接调用了context的bindService方法来绑定,那么接下来继续分析就会调用到
ContextWrapper.java
@Override
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
return mBase.bindService(service, conn, flags);
}
这里会调用mBase,mBase其实本质是ContentImpl类型变量:
ActivityThread.java可以看出
/** Core implementation of activity launch. */
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
//省略部分
ContextImpl appContext = createBaseContextForActivity(r);
//省略部分
}
所以接下来看ContextImpl.java中的bindService方法:
@Override
public boolean bindService(Intent service, ServiceConnection conn, int flags) {
warnIfCallingFromSystemProcess();
return bindServiceCommon(service, conn, flags, null, mMainThread.getHandler(), null,
getUser());
}
这里又调用bindServiceCommon:
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
String instanceName, Handler handler, Executor executor, UserHandle user) {
//省略部分
try {
IBinder token = getActivityToken();
if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null
&& mPackageInfo.getApplicationInfo().targetSdkVersion
< android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
flags |= BIND_WAIVE_PRIORITY;
}
service.prepareToLeaveProcess(this);
//这里是核心,调用了AMS的bindIsolatedService
int res = ActivityManager.getService().bindIsolatedService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, instanceName, 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();
}
}
这个方法最重要就是调用了服务systemserver的AMS bindIsolatedService方法,到此调用端就暂时发起的调用就结束了,当然后面肯定还要继续,因为我们传递了ServiceConnection,通过它我们才可以获取到真正的远端进程的Service
下面我们来看
ActivityManagerService的bindIsolatedService方法:
public int bindIsolatedService(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, IServiceConnection connection, int flags, String instanceName,
String callingPackage, int userId) throws TransactionTooLargeException {
//省略部分
synchronized(this) {
return mServices.bindServiceLocked(caller, token, service,
resolvedType, connection, flags, instanceName, callingPackage, userId);
}
}
这里调用了mServices的bindServiceLocked方法,mServices是ActiveServices类型:
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, final IServiceConnection connection, int flags,
String instanceName, String callingPackage, final int userId)
throws TransactionTooLargeException {
//省略部分
//AMS中调用retrieveServiceLocked把对应ServiceRecord创建
ServiceLookupResult res =
retrieveServiceLocked(service, instanceName, resolvedType, callingPackage,
Binder.getCallingPid(), Binder.getCallingUid(), userId, true,
callerFg, isBindExternal, allowInstant);
//省略部分
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
//重要方法,会调用到真正Service对应的服务端进程进行onCreate onBind
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
permissionsReviewRequired) != null) {
return 0;
}
}
//省略部分
return 1;
}
这个方法实在太长,我们主要来分析一下bringUpServiceLocked,因为他才是真正与远端进程交互的方法:
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
//省略部分
final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
final String procName = r.processName;
HostingRecord hostingRecord = new HostingRecord("service", r.instanceName);
ProcessRecord app;
if (!isolated) {
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode, mAm.mProcessStats);
//核心方法
realStartServiceLocked(r, app, execInFg);
return null;
}
}
}
//省略部分
return null;
}
这里我们只分析已经有了远端进程存在情况,这里会调用到一个核心方法realStartServiceLocked:
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
//省略部分
mAm.notifyPackageUse(r.serviceInfo.packageName,
PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
//调用远端进程的scheduleCreateService
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
app.getReportedProcState());
r.postNotification();
created = true;
}
//省略部分
当Service Create调用后,会调用要求bind的方法
requestServiceBindingsLocked(r, execInFg);
//省略部分
}
这里我们看到了 app.thread.scheduleCreateService这里就代表AMS会跨进程调用到远端进程CreateService方法,这里具体远端进程由下面分析。
这里CreateService执行后又会调用requestServiceBindingsLocked:
private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg)
throws TransactionTooLargeException {
for (int i=r.bindings.size()-1; i>=0; i--) {
IntentBindRecord ibr = r.bindings.valueAt(i);
if (!requestServiceBindingLocked(r, ibr, execInFg, false)) {
break;
}
}
}
这里又会调用requestServiceBindingLocked:
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
boolean execInFg, boolean rebind) throws TransactionTooLargeException {
//省略部分
if ((!i.requested || rebind) && i.apps.size() > 0) {
try {
bumpServiceExecutingLocked(r, execInFg, "bind");
r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
//调用到Service进程执行bind修改
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
r.app.getReportedProcState());
if (!rebind) {
i.requested = true;
}
i.hasBound = true;
i.doRebind = false;
}
//省略部分
}
return true;
}
这里最重要方法就是scheduleBindService,他就是让远端执行onBind相关,那么相当于到了这里服务端的任务就完成了一大部分,因为它已经触发了远程Service执行onCreate和onBind,接下来AMS就只需要等待着远程Service进程执行完毕,回调到publishServiceLocked方法:
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
//省略大部分
//会调用到最开始bindService那个客户端进程,而且带有了IBinder service参数
c.conn.connected(r.name, service, false);
//省略大部分
}
注意这里publishServiceLocked是由远程Service进程进行主动调用的,然后它干的事就是调用connected方法,其实他就是调用到我们最开始ServiceConnection回调
AMS分析时候就说过远端Service执行onCreate,onBind方法
那么从onCreate先开始分析:
这里我们原来课程就分析过这里AMS调用到是在ActivityThread中:
这里我们来看ActivityThread.java的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);
}
这里主要创建了一个CreateServiceData,然后就发消息让主线程处理消息:
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;
这里调用是handleCreateService:
private void handleCreateService(CreateServiceData data) {
//省略部分
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,
ActivityManager.getService());
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();
}
}
//省略部分
}
这里其实和实战课程讲解的Activity创建非常像,主要就是创建出Service这个类然后调用对应onCreate方法,这个就是到了我们app层面Service的onCreate执行,执行完成后这里还会调用AMS的serviceDoneExecuting方法通知到AMS
那接下来Service已经onCreate了,那就要执行onBind了,来看:
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);
}
这里其实和onCreate一致发消息到主线程:
case BIND_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");
handleBindService((BindServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
调用到了handleBindService:
private void handleBindService(BindServiceData data) {
//省略
if (!data.rebind) {
IBinder binder = s.onBind(data.intent);
ActivityManager.getService().publishService(
data.token, data.intent, binder);
//省略
}
这里handleBindService就更加简单,执行Service的onBind方法后,在调用ActivityManager.getService().publishService方法,并且把onBind返回的IBinder对象也传递进去了,这里就是为什么远端的onBind返回的binder对象会传递到客户端的onServiceConnected方法中
new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {}
csdn在线学习课程,课程咨询答疑和新课信息:QQ交流群:422901085进行课程讨论
android跨进程通信实战视频课程(加群获取优惠)