本篇介绍
本篇介绍下android中bindService相关的内容,包括bindService的简单功能,并提供一个demo进行操作演示,最后从源码角度分析下这块流程,希望通过阅读源码可以对该流程可以掌握的清楚一些。
功能介绍
在android中,一般有两种使用service的方法,一种是startService,一种是bindService,两者最大的区别就是前者需要调用方明确调用stopService才会停止,而后者可以和调用方activity实现共存亡。对于IPC场景,优先使用bindService,因为通过bindService可以拿到远端service的binder,这样就可以像操作本地引用一样进行IPC通信了。
使用演示
这儿提供了一个例子,bind 远端的一个service,并调用该service的对外接口,获取返回结果并显示的流程。主要代码如下:
MainActivity.java
代码语言:javascript复制public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private static final String TAG = "MyTest";
private IDemoInterface demoInterface = null;
private Button bindService;
private Button unbindService;
private TextView textView;
private ServiceConnection serviceConnect = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
demoInterface = IDemoInterface.Stub.asInterface(service);
if (demoInterface == null) {
Log.e(TAG, " null service");
} else {
Log.d(TAG, " bind service");
try {
String result = demoInterface.getResult("demo");
textView.setText(result);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.i(TAG, " service disconnected");
demoInterface = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initActivity();
}
private void initActivity() {
bindService = findViewById(R.id.bind);
unbindService = findViewById(R.id.unbind);
textView = findViewById(R.id.textView);
bindService.setOnClickListener(this);
unbindService.setOnClickListener(this);
}
private void bindService() {
Intent intent = new Intent();
intent.setAction("com.example.myapplication.DemoService");
intent.setPackage("com.example.myapplication");
bindService(intent, serviceConnect, BIND_AUTO_CREATE);
Log.i(TAG, "start bind service");
}
private void unbindService() {
unbindService(serviceConnect);
Log.i(TAG, "unbind service");
}
@Override
public void onClick(View v) {
switch(v.getId()) {
case R.id.bind:
bindService();
break;
case R.id.unbind:
unbindService();
break;
default:
break;
}
}
}
DemoService.java
代码语言:javascript复制public class DemoService extends Service {
private static final String TAG = DemoService.class.getName();
private IBinder stub = new IDemoInterface.Stub() {
@Override
public String getResult(String name) throws RemoteException {
return name " from aidl";
}
};
public DemoService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return stub;
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
@Override
public void onRebind(Intent intent) {
super.onRebind(intent);
}
}
IDemoInterface.aidl
代码语言:javascript复制interface IDemoInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
String getResult(String name);
}
xml等配置文件先略去,不过整个工程的地址是(https://github.com/leehaoran/androidprojects),可以随意使用。
该demo的功能很纯粹,就是bind 一个service,然后调用该service的接口,获取返回结果。
源码解读
现在看下bindService的流程: ContextImpl.java
代码语言:javascript复制 @Override
public boolean bindService(Intent service, ServiceConnection conn, int flags) {
warnIfCallingFromSystemProcess();
return bindServiceCommon(service, conn, flags, null, mMainThread.getHandler(), null,
getUser());
}
调用了bindServiceCommon
代码语言:javascript复制 private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
String instanceName, Handler handler, Executor executor, UserHandle user) {
// Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
IServiceConnection sd;
if (conn == null) {
throw new IllegalArgumentException("connection is null");
}
if (handler != null && executor != null) {
throw new IllegalArgumentException("Handler and Executor both supplied");
}
if (mPackageInfo != null) {
if (executor != null) {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), executor, flags);
} else {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
} //获取对应的ServiceConnection
} else {
throw new RuntimeException("Not supported in system context");
}
validateServiceIntent(service);
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);
int res = ActivityManager.getService().bindIsolatedService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, instanceName, getOpPackageName(), user.getIdentifier()); //调用ams 去bind service
if (res < 0) {
throw new SecurityException(
"Not allowed to bind to service " service);
}
return res != 0;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
这里的流程是先获取一个serviceConnection,然后调用了ams的bindIsolatedService 执行具体的bind操作,在看ams 操作前先看下getServiceDispatcher的内容: LoadedApk.java
代码语言:javascript复制 public final IServiceConnection getServiceDispatcher(ServiceConnection c,
Context context, Handler handler, int flags) {
synchronized (mServices) {
LoadedApk.ServiceDispatcher sd = null;
ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
if (map != null) {
if (DEBUG) Slog.d(TAG, "Returning existing dispatcher " sd " for conn " c);
sd = map.get(c);
}
if (sd == null) {
sd = new ServiceDispatcher(c, context, handler, flags);
if (DEBUG) Slog.d(TAG, "Creating new dispatcher " sd " for conn " c);
if (map == null) {
map = new ArrayMap<>();
mServices.put(context, map);
}
map.put(c, sd); //每个context 对应一个serviceconnection map,这个map又将对外的ServiceConnection和内部的ServiceDispatcher对应起来作为键值对。
} else {
sd.validate(context, handler);
}
return sd.getIServiceConnection();
}
}
看下ServiceDispatcher 的关键定义部分:
代码语言:javascript复制 static final class ServiceDispatcher {
private final ServiceDispatcher.InnerConnection mIServiceConnection;
private final ServiceConnection mConnection;
private final Context mContext;
private final Handler mActivityThread;
private final ServiceConnectionLeaked mLocation;
private final int mFlags;
private RuntimeException mUnbindLocation;
private boolean mForgotten;
private static class ConnectionInfo {
IBinder binder;
IBinder.DeathRecipient deathMonitor;
}
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) {
sd.connected(name, service, dead);
}
}
}
这儿出现了一个InnerConnection,这是一个binder stub,可以看到getServiceDispatcher 最终就是将这个stub对象返回给了调用方,然后通过binder传递给了ams。这个就是匿名binder的使用场景,在fwk中,很多地方都使用了这个方法。 目前进程还是处于业务中,在进入ams之前先看下传递的参数:
入参 | 含义 |
---|---|
IApplicationThread caller | mMainThread.getApplicationThread(), 当前应用的binder |
IBinder token | getActivityToken(), 和activity关联的binder |
Intent service | service 的intent filter |
String resolvedType | intent的type |
IServiceConnection connection | serviceconnection的匿名binder |
int flags | flags |
String instanceName | null |
String callingPackage | 当前包名 |
int userId | 当前用户id |
接下来调用就到了ams中,运行进程是systemserver。看下bindIsolatedService的实现。
代码语言:javascript复制public int bindIsolatedService(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, IServiceConnection connection, int flags, String instanceName,
String callingPackage, int userId) throws TransactionTooLargeException {
enforceNotIsolatedCaller("bindService");
// Refuse possible leaked file descriptors
if (service != null && service.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
} // 不允许通过intent传递fd
if (callingPackage == null) {
throw new IllegalArgumentException("callingPackage cannot be null");
}
// Ensure that instanceName, which is caller provided, does not contain
// unusual characters.
if (instanceName != null) {
for (int i = 0; i < instanceName.length(); i) {
char c = instanceName.charAt(i);
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
|| (c >= '0' && c <= '9') || c == '_' || c == '.')) {
throw new IllegalArgumentException("Illegal instanceName");
}
}
}
synchronized(this) {
return mServices.bindServiceLocked(caller, token, service,
resolvedType, connection, flags, instanceName, callingPackage, userId);
}
}
bindIsolatedService里面只是做了一个检查,接下来就调用了bindServiceLocked。 这儿的mServices就是ActiveServices,接下来看下bindServiceLocked的实现,这块代码比较多,分开看:
代码语言:javascript复制 int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, final IServiceConnection connection, int flags,
String instanceName, String callingPackage, final int userId)
throws TransactionTooLargeException {
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
if (callerApp == null) {
throw new SecurityException(
"Unable to find app for caller " caller
" (pid=" callingPid
") when binding service " service);
}
ActivityServiceConnectionsHolder<ConnectionRecord> activity = null;
if (token != null) {
activity = mAm.mAtmInternal.getServiceConnectionsHolder(token);
if (activity == null) {
Slog.w(TAG, "Binding with unknown activity: " token);
return 0;
}
}
这儿只做了2件事,拿到调用方的进程信息和activity 信息。 接下来就是找目标service信息:
代码语言:javascript复制 ServiceLookupResult res =
retrieveServiceLocked(service, instanceName, resolvedType, callingPackage,
callingPid, callingUid, userId, true,
callerFg, isBindExternal, allowInstant);
if (res == null) {
return 0;
}
if (res.record == null) {
return -1;
}
ServiceRecord s = res.record;
boolean permissionsReviewRequired = false;
如果是在启动目标服务时需要用户确认,那么先不启动目标服务,而是先起一个activity,让用户确认。
代码语言:javascript复制 // If permissions need a review before any of the app components can run,
// we schedule binding to the service but do not start its process, then
// we launch a review activity to which is passed a callback to invoke
// when done to start the bound service's process to completing the binding.
if (mAm.getPackageManagerInternalLocked().isPermissionsReviewRequired(
s.packageName, s.userId)) {
permissionsReviewRequired = true;
// Show a permission review UI only for binding from a foreground app
if (!callerFg) {
Slog.w(TAG, "u" s.userId " Binding to a service in package"
s.packageName " requires a permissions review");
return 0;
}
final ServiceRecord serviceRecord = s;
final Intent serviceIntent = service;
RemoteCallback callback = new RemoteCallback(
new RemoteCallback.OnResultListener() {
@Override
public void onResult(Bundle result) {
synchronized(mAm) {
final long identity = Binder.clearCallingIdentity();
try {
if (!mPendingServices.contains(serviceRecord)) {
return;
}
// If there is still a pending record, then the service
// binding request is still valid, so hook them up. We
// proceed only if the caller cleared the review requirement
// otherwise we unbind because the user didn't approve.
if (!mAm.getPackageManagerInternalLocked()
.isPermissionsReviewRequired(
serviceRecord.packageName,
serviceRecord.userId)) {
try {
bringUpServiceLocked(serviceRecord,
serviceIntent.getFlags(),
callerFg, false, false); //同意后才启动service
} catch (RemoteException e) {
/* ignore - local call */
}
} else {
unbindServiceLocked(connection);
}
} finally {
Binder.restoreCallingIdentity(identity);
}
}
}
});
final Intent intent = new Intent(Intent.ACTION_REVIEW_PERMISSIONS);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_MULTIPLE_TASK
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
intent.putExtra(Intent.EXTRA_PACKAGE_NAME, s.packageName);
intent.putExtra(Intent.EXTRA_REMOTE_CALLBACK, callback);
if (DEBUG_PERMISSIONS_REVIEW) {
Slog.i(TAG, "u" s.userId " Launching permission review for package "
s.packageName);
}
mAm.mHandler.post(new Runnable() {
@Override
public void run() {
mAm.mContext.startActivityAsUser(intent, new UserHandle(userId)); //启动一个临时activity
}
});
}
接下来就是建立各种关联关系
代码语言:javascript复制mAm.startAssociationLocked(callerApp.uid, callerApp.processName,
callerApp.getCurProcState(), s.appInfo.uid, s.appInfo.longVersionCode,
s.instanceName, s.processName); // 将target process和source process 关联起来,记录到一个结构里面
// Once the apps have become associated, if one of them is caller is ephemeral
// the target app should now be able to see the calling app
mAm.grantImplicitAccess(callerApp.userId, service,
callerApp.uid, UserHandle.getAppId(s.appInfo.uid));
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
ConnectionRecord c = new ConnectionRecord(b, activity,
connection, flags, clientLabel, clientIntent,
callerApp.uid, callerApp.processName, callingPackage);
IBinder binder = connection.asBinder();
s.addConnection(binder, c); //在目标服务中添加记录
b.connections.add(c);
if (activity != null) {
activity.addConnection(c);
}
b.client.connections.add(c);
c.startAssociationIfNeeded();
单个serviceconnection可以用来bind多个service
代码语言:javascript复制ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);
if (clist == null) {
clist = new ArrayList<>();
mServiceConnections.put(binder, clist);
}
clist.add(c);
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false, // 如果指定了BIND_AUTO_CREATE标记,则负责拉起服务
permissionsReviewRequired) != null) {
return 0;
}
}
if (s.app != null) {
if ((flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
s.app.treatLikeActivity = true;
}
if (s.whitelistManager) {
s.app.whitelistManager = true;
}
// This could have made the service more important.
mAm.updateLruProcessLocked(s.app,
(callerApp.hasActivitiesOrRecentTasks() && s.app.hasClientActivities())
|| (callerApp.getCurProcState() <= ActivityManager.PROCESS_STATE_TOP
&& (flags & Context.BIND_TREAT_LIKE_ACTIVITY) != 0),
b.client);
mAm.updateOomAdjLocked(s.app, OomAdjuster.OOM_ADJ_REASON_BIND_SERVICE); //更新内存优先级adj
}
if (s.app != null && b.intent.received) {
// Service is already running, so we can immediately
// publish the connection.
try {
c.conn.connected(s.name, b.intent.binder, false); //发布connect,其实就是触发调用方的回调
} catch (Exception e) {
Slog.w(TAG, "Failure sending service " s.shortInstanceName
" to connection " c.conn.asBinder()
" (in " c.binding.client.processName ")", e);
}
// If this is the first app connected back to this binding,
// and the service had previously asked to be told when
// rebound, then do so.
if (b.intent.apps.size() == 1 && b.intent.doRebind) {
requestServiceBindingLocked(s, b.intent, callerFg, true);
}
} else if (!b.intent.requested) {
requestServiceBindingLocked(s, b.intent, callerFg, false);
}
ams里面的逻辑总结下就是拉起目标服务,然后触发调用方的回调,同时也记录了调用方和目标应用的结构关联关系。 接下来需要看下是如何启动目标service的,以及启动service后, ams是如何通知给调用方的。首先看下启动目标service的,入口函数就是bringUpServiceLocked
代码语言:javascript复制 private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
if (r.app != null && r.app.thread != null) {
sendServiceArgsLocked(r, execInFg, false); 如果service对应的进程已经启动了,那么直接给该进程发请求,启动该service即可
return null;
}
...
// Make sure this service is no longer considered delayed, we are starting it now.
if (r.delayed) {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (bring up): " r);
getServiceMapLocked(r.userId).mDelayedStartList.remove(r);
r.delayed = false;
}
// 下面就是判断是否需要在单独进程中运行了
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;
} catch (TransactionTooLargeException e) {
throw e;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting service " r.shortInstanceName, e);
}
// If a dead object exception was thrown -- fall through to
// restart the application.
}
} else {
// If this service runs in an isolated process, then each time
// we call startProcessLocked() we will get a new isolated
// process, starting another process if we are currently waiting
// for a previous process to come up. To deal with this, we store
// in the service any current isolated process it is running in or
// waiting to have come up.
app = r.isolatedProc; // 否则就需要单独起一个进程来运行service了
if (WebViewZygote.isMultiprocessEnabled()
&& r.serviceInfo.packageName.equals(WebViewZygote.getPackageName())) {
hostingRecord = HostingRecord.byWebviewZygote(r.instanceName);
}
if ((r.serviceInfo.flags & ServiceInfo.FLAG_USE_APP_ZYGOTE) != 0) {
hostingRecord = HostingRecord.byAppZygote(r.instanceName, r.definingPackageName,
r.definingUid);
}
}
关于ams如何起进程,其实就是ams 给zygote 发一个socket消息,zygote接收到后就fork一个子进程,并且在他的主线程中attach到ams上。这儿有一个经典的疑问,就是zygote通信为什么要用socket而不是用binder?这个属于开放性问题,不过要回答的让人满意还是需要对系统有深入的理解的。在这儿我说下本人的看法,如果要用binder通信,那么就会用到binder的线程池,在多线程场景中调用fork是比较危险的,因为cow(copy on write)机制,好多独占锁,读写锁标记也会共享,在修改的时候再拷贝一份,如果是父进程的某个线程持有了某个锁,然后调用fork后,这个线程释放这个锁了,这样父进程的其他线程就可以正常持锁了,而子进程需要拿这个锁的话,就会发现这个锁的标记一直处于被持有状态,这样就一直阻塞了。而用socket就不会有这种问题,binder带来的系统复杂度是不必要的,因此zygote就选择了socket。 题归正传,继续看下realStartServiceLocked的内容:
代码语言:javascript复制 /**
* Note the name of this method should not be confused with the started services concept.
* The "start" here means bring up the instance in the client, and this method is called
* from bindService() as well.
*/
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
r.setProcess(app);
r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
final boolean newService = app.startService(r);
bumpServiceExecutingLocked(r, execInFg, "create");
// 这个就是start,bind等的anr来源了,
//这里面会判断是前台服务还是后台服务,如果是后台服务,那么anr时间是200s,前台服务是20s,
//里面实现的机制就是在ams的looper里面发一个延时消息,服务起来后,会删掉ams中的超时消息,如果没有及时删除,
//那么这个超时消息对应的执行方法就会触发,获取目标进程的当前堆栈记录到anr后,kill调目标进程。
mAm.updateLruProcessLocked(app, false, null);
updateServiceForegroundLocked(r.app, /* oomAdj= */ false);
mAm.updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_START_SERVICE);
boolean created = false;
try {
if (LOG_SERVICE_START_STOP) {
String nameTerm;
int lastPeriod = r.shortInstanceName.lastIndexOf('.');
nameTerm = lastPeriod >= 0 ? r.shortInstanceName.substring(lastPeriod)
: r.shortInstanceName;
EventLogTags.writeAmCreateService(
r.userId, System.identityHashCode(r), nameTerm, r.app.uid, r.app.pid);
}
FrameworkStatsLog.write(FrameworkStatsLog.SERVICE_LAUNCH_REPORTED, r.appInfo.uid,
r.name.getPackageName(), r.name.getClassName());
synchronized (r.stats.getBatteryStats()) {
r.stats.startLaunchedLocked();
}
mAm.notifyPackageUse(r.serviceInfo.packageName,
PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
app.getReportedProcState()); //这儿就是通过binder通信给目标进程发创建服务命令
r.postNotification();
created = true;
} catch (DeadObjectException e) {
Slog.w(TAG, "Application dead when creating service " r);
mAm.appDiedLocked(app, "Died when creating service");
throw e;
} finally {
if (!created) {
// Keep the executeNesting count accurate.
final boolean inDestroying = mDestroyingServices.contains(r);
serviceDoneExecutingLocked(r, inDestroying, inDestroying);
// Cleanup.
if (newService) {
app.stopService(r);
r.setProcess(null);
}
// Retry.
if (!inDestroying) {
scheduleServiceRestartLocked(r, false);
}
}
}
if (r.whitelistManager) {
app.whitelistManager = true;
}
requestServiceBindingsLocked(r, execInFg); //请求bind服务
updateServiceClientActivitiesLocked(app, null, true);
if (newService && created) {
app.addBoundClientUidsOfNewService(r);
}
// If the service is in the started state, and there are no
// pending arguments, then fake up one so its onStartCommand() will
// be called.
if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
null, null, 0));
}
sendServiceArgsLocked(r, execInFg, true);
if (r.delayed) {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (new proc): " r);
getServiceMapLocked(r.userId).mDelayedStartList.remove(r);
r.delayed = false;
}
if (r.delayedStop) {
// Oh and hey we've already been asked to stop!
r.delayedStop = false;
if (r.startRequested) {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
"Applying delayed stop (from start): " r);
stopServiceLocked(r);
}
}
}
看下是如何scheduleCreateService的:
代码语言:javascript复制 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);
}
这时候已经到了目标进程的binder线程里面了,然后发一个消息,处理该消息的就是该进程对应的主线程Handler
代码语言:javascript复制 case CREATE_SERVICE:
if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
("serviceCreate: " String.valueOf(msg.obj)));}
handleCreateService((CreateServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
接下来看下handleCreateService的操作,这块代码看起来会很惬意,流程都很清晰
代码语言:javascript复制 private void handleCreateService(CreateServiceData data) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
if (localLOGV) Slog.v(TAG, "Creating service " data.info.name);
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
Application app = packageInfo.makeApplication(false, mInstrumentation);
java.lang.ClassLoader cl = packageInfo.getClassLoader(); //拿到类加载器
service = packageInfo.getAppFactory()
.instantiateService(cl, data.info.name, data.intent); // 实例化服务
// Service resources must be initialized with the same loaders as the application
// context.
context.getResources().addLoaders(
app.getResources().getLoaders().toArray(new ResourcesLoader[0]));
context.setOuterContext(service);
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService()); // 将服务attach到ams
service.onCreate(); //调用服务的回调函数
mServices.put(data.token, service);
try {
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);//这儿就是给ams发一个消息,删除掉前面设置的anr 超时消息
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
"Unable to create service " data.info.name
": " e.toString(), e);
}
}
}
走到这儿服务的创建就结束了,还有一个流程是服务的bind,流程大致一致,可以简单看下,ams里面的调用起点是requestServiceBindingsLocked:
代码语言:javascript复制 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;
}
}
}
对每个IntentBindRecord进行bind
代码语言:javascript复制 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"); //这个anr 函数前面介绍过了
r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind, // bind 服务
r.app.getReportedProcState());
if (!rebind) {
i.requested = true;
}
i.hasBound = true;
i.doRebind = false;
}
...
}
return true;
}
这儿就是binder通信,处理请求的在目标进程那边,直接掠过Looper流程,直接看实现:
代码语言:javascript复制 private void handleBindService(BindServiceData data) {
Service s = mServices.get(data.token);
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) {
IBinder binder = s.onBind(data.intent); //调用回调
ActivityManager.getService().publishService( //发布服务
data.token, data.intent, binder);
} else {
s.onRebind(data.intent);
ActivityManager.getService().serviceDoneExecuting( // 去掉anr消息
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
稍微看下publishService的内容,请求到了ams里面,最后调用的就是publishServiceLocked:
代码语言:javascript复制 void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
final long origId = Binder.clearCallingIdentity();
try {
if (r != null) {
Intent.FilterComparison filter
= new Intent.FilterComparison(intent);
IntentBindRecord b = r.bindings.get(filter);
if (b != null && !b.received) {
b.binder = service;
b.requested = true;
b.received = true;
ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
for (int conni = connections.size() - 1; conni >= 0; conni--) {
ArrayList<ConnectionRecord> clist = 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, false); 这儿的service就是onBInd返回的binder } catch (Exception e) {
Slog.w(TAG, "Failure sending service " r.shortInstanceName
" to connection " c.conn.asBinder()
" (in " c.binding.client.processName ")", e);
}
}
}
}
serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false);
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
接下来就看下ams是如何通知给请求方的, 对于c.conn.connected,这里的conn就是请求方传过来的匿名binder,执行connected方法其实就是ams通过binder把调用发给了请求方:
代码语言:javascript复制 private static class InnerConnection extends IServiceConnection.Stub {
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
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) {
sd.connected(name, service, dead);
}
}
}
可以看到这儿执行的就是servicedispatcher的connected:
代码语言:javascript复制 public void connected(ComponentName name, IBinder service, boolean dead) {
if (mActivityExecutor != null) {
mActivityExecutor.execute(new RunConnection(name, service, 0, dead));
} else if (mActivityThread != null) {
mActivityThread.post(new RunConnection(name, service, 0, dead));
} else {
doConnected(name, service, dead);
}
}
这儿就是给主线程发一个RunConnection,看下这里面的操作:
代码语言:javascript复制 private final class RunConnection implements Runnable {
RunConnection(ComponentName name, IBinder service, int command, boolean dead) {
mName = name;
mService = service;
mCommand = command;
mDead = dead;
}
public void run() {
if (mCommand == 0) {
doConnected(mName, mService, mDead);
} else if (mCommand == 1) {
doDeath(mName, mService);
}
}
final ComponentName mName;
final IBinder mService;
final int mCommand;
final boolean mDead;
}
调用的是doConnected
代码语言:javascript复制 public void doConnected(ComponentName name, IBinder service, boolean dead) {
ServiceDispatcher.ConnectionInfo old;
ServiceDispatcher.ConnectionInfo info;
synchronized (this) {
if (mForgotten) {
// We unbound before receiving the connection; ignore
// any connection received.
return;
}
old = mActiveConnections.get(name);
if (old != null && old.binder == service) {
// Huh, already have this one. Oh well!
return;
}
if (service != null) {
// A new service is being connected... set it all up.
info = new ConnectionInfo();
info.binder = service;
info.deathMonitor = new DeathMonitor(name, service);
try {
service.linkToDeath(info.deathMonitor, 0);
mActiveConnections.put(name, info);
} catch (RemoteException e) {
// This service was dead before we got it... just
// don't do anything with it.
mActiveConnections.remove(name);
return;
}
} else {
// The named service is being disconnected... clean up.
mActiveConnections.remove(name);
}
if (old != null) {
old.binder.unlinkToDeath(old.deathMonitor, 0);
}
}
// If there was an old service, it is now disconnected.
if (old != null) {
mConnection.onServiceDisconnected(name);
}
if (dead) {
mConnection.onBindingDied(name);
}
// If there is a new viable service, it is now connected.
if (service != null) {
mConnection.onServiceConnected(name, service); // 这儿就执行到了最开始应用自己定义的回调里面了
} else {
// The binding machinery worked, but the remote returned null from onBind().
mConnection.onNullBinding(name);
}
}
终于把bindService流程介绍完了,大体上流程很清晰,就是应用到AMS,AMS再到目标服务,目标服务执行onBind后通知给AMS,AMS再通过匿名binder回调给应用。 通过看这块流程,不得不感概binder的神奇,通过binder 把如此负责的进程间通信问题给解决得如此完美,正如binder的含义胶水,通过binder,仿佛各个服务间的间隙被淡化了,通过胶水牢牢地粘在了一起。c/s间的通信变得既方便又安全,其中匿名binder更是一个伟大的创新,把C/S通信做的如此便捷安全。
本篇总结
花了一周时间梳理了下这块流程,收获很多,希望可以坚持下来,持续介绍这块内容。