Binder之bindService
一个需要进行Binder通信的Client一般通过bindService()来启动Service。
bindService(it, mServiceConnection, Service.BIND_AUTO_CREATE);
binderService()的实现在ContextWrapper中,
frameworks/base/core/java/android/app/ContextImpl.java @Override public boolean bindService(Intent service, ServiceConnection conn, int flags) { //如果是系统进程,发出警告 warnIfCallingFromSystemProcess(); return bindServiceCommon(service, conn, flags, Process.myUserHandle());}...... private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, UserHandle user) { IServiceConnection sd; ...... if (mPackageInfo != null) { // 获取IServiceConnection对象 sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), mMainThread.getHandler(), flags); } else { throw new RuntimeException("Not supported in system context"); } // 验证service有效性 validateServiceIntent(service); try { ...... // 准备离开应用程序 service.prepareToLeaveProcess(); // 调用ActivityManagerProxy的bindService() int res = ActivityManagerNative.getDefault().bindService( mMainThread.getApplicationThread(), getActivityToken(), service, service.resolveTypeIfNeeded(getContentResolver()), sd, flags, user.getIdentifier()); ...... } }
其中,getServiceDispatcher()返回一个IServiceConnection对象,它为一个Binder实体,将负责与ServiceConnection通信。
frameworks/base/core/java/android/app/LoadedApk.java public final IServiceConnection getServiceDispatcher(ServiceConnection c, Context context, Handler handler, int flags) { synchronized (mServices) { LoadedApk.ServiceDispatcher sd = null; // 获取map,map存储ServiceConnection与ServiceDispatcher的映射 ArrayMap map = mServices.get(context); if (map != null) { sd = map.get(c); } // 如果map中没有c映射,新建一个插入到mServices和map中 if (sd == null) { sd = new ServiceDispatcher(c, context, handler, flags); if (map == null) { map = new ArrayMap(); mServices.put(context, map); } map.put(c, sd); } else { sd.validate(context, handler); } // 返回mIServiceConnection,InnerConnection对象 return sd.getIServiceConnection(); } }
接着看bindService。通过ActivityManagerNative.getDefault()获得了ActivityManagerProxy, 它的bindService()就是发起一个Binder调用。调用的远端为system_server的ActivityManagerService。
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java public int bindService(IApplicationThread caller, IBinder token, Intent service, String resolvedType, IServiceConnection connection, int flags, int userId) { enforceNotIsolatedCaller("bindService"); // Refuse possible leaked file descriptors if (service != null && service.hasFileDescriptors() == true) { throw new IllegalArgumentException("File descriptors passed in Intent"); } synchronized(this) { return mServices.bindServiceLocked(caller, token, service, resolvedType, connection, flags, userId); } }
mServices为ActiveServices的对象。
frameworks/base/services/core/java/com/android/server/am/ActiveServices.java int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service, String resolvedType, IServiceConnection connection, int flags, int userId) { ...... // 查找发起bindSevice应用在AMS中的记录 final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller); ...... if (callerApp.info.uid == Process.SYSTEM_UID) { // 当应用为system进程时 ...... } ...... final boolean callerFg = callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE; // 根据Intent查找相应的服务 ServiceLookupResult res = retrieveServiceLocked(service, resolvedType, Binder.getCallingPid(), Binder.getCallingUid(), userId, true, callerFg); ...... ServiceRecord s = res.record; final long origId = Binder.clearCallingIdentity(); try { // 取消服务的restart机制 if (unscheduleServiceRestartLocked(s, callerApp.info.uid, false)) { if (DEBUG_SERVICE) Slog.v(TAG, "BIND SERVICE WHILE RESTART PENDING: " + s); } if ((flags&Context.BIND_AUTO_CREATE) != 0) { // 更新服务最后活跃时间 s.lastActivity = SystemClock.uptimeMillis(); if (!s.hasAutoCreateConnections()) { // 如果是第一次连接,设置bind // This is the first binding, let the tracker know. ProcessStats.ServiceState stracker = s.getTracker(); if (stracker != null) { stracker.setBound(true, mAm.mProcessStats.getMemFactorLocked(), s.lastActivity); } } } mAm.startAssociationLocked(callerApp.uid, callerApp.processName, s.appInfo.uid, s.name, s.processName); // 创建AppBindRecord,关联应用与服务 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp); // 创建ConnectionRecord,记录bind信息 ConnectionRecord c = new ConnectionRecord(b, activity, connection, flags, clientLabel, clientIntent); // 转换interface到binder IBinder binder = connection.asBinder(); ArrayList clist = s.connections.get(binder); if (clist == null) { clist = new ArrayList(); s.connections.put(binder, clist); } // 将新的Connection加入到ServiceRecord和AppBindRecord中 clist.add(c); b.connections.add(c); if (activity != null) { // 当由activity发起bind时,将Connection加入到ActivityRecord if (activity.connections == null) { activity.connections = new HashSet(); } activity.connections.add(c); } // 将新的Connection加入到AppBindRecord的client中 b.client.connections.add(c); if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0) { b.client.hasAboveClient = true; } if (s.app != null) { updateServiceClientActivitiesLocked(s.app, c, true); } // 将新的Connection加入到service connections映射表中 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) != null) { return 0; } } ...... if (s.app != null && b.intent.received) { // 如果service已经运行,声明已连接,回调到应用的onServiceConnected try { c.conn.connected(s.name, b.intent.binder); ...... } // 如果第一个连接的应用重新bind时执行onRebind if (b.intent.apps.size() == 1 && b.intent.doRebind) { requestServiceBindingLocked(s, b.intent, callerFg, true); } } else if (!b.intent.requested) { // 执行onBind requestServiceBindingLocked(s, b.intent, callerFg, false); } getServiceMap(s.userId).ensureNotStartingBackground(s); } finally { Binder.restoreCallingIdentity(origId); } return 1; }
上述的流程中有两个对connection的描述,需要区分一下。一个是传参进入的IServiceConnection对象,它实质上时一个Binder,由bindService发起端创建。应用创建一个ServiceConnection Binder,将代理传递到system_server中,这样system_server可以返回conneted和disconnected等状态。另一个connect是函数内部创建的ConnectionRecord对象。它描述了bind service的相关信息,并存储到ServiceRecord和AppBindRecord中。
Service的启动通过bringUpServiceLocked()完成。
frameworks/base/services/core/java/com/android/server/am/ActiveServices.java private final String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg, boolean whileRestarting) { if (r.app != null && r.app.thread != null) { // 如果service已经运行,直接执行onStartCommand sendServiceArgsLocked(r, execInFg, false); return null; } ...... // Service启动过程中不能停止package try { AppGlobals.getPackageManager().setPackageStoppedState( r.packageName, false, r.userId); ...... } final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0; final String procName = r.processName; 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.versionCode, mAm.mProcessStats); realStartServiceLocked(r, app, execInFg); return null; ...... } // 如果服务进程不存在,先创建进程,然后将服务加入队列,等待执行 if (app == null) { if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags, "service", r.name, false, isolated, false)) == null) { ...... } if (!mPendingServices.contains(r)) { mPendingServices.add(r); } ...... return null; }
当服务进程不存在时,需要先创建服务进程,然后再启动进程。启动进程通过AMS的startProcessLocked来完成。startProcessLocked中通过Process.start()创建新进程。新进程启动时会执行ActivityThread的main函数,里面会调用到ActivityThread.attach。这个attach通过binder最终调用到AMS中的attachApplication,再调用ActiveServices的attachApplicationLocked,这里启动pending的service。启动还是通过realStartServiceLocked完成的。
frameworks/base/services/core/java/com/android/server/am/ActiveServices.java private final void realStartServiceLocked(ServiceRecord r, ProcessRecord app, boolean execInFg) throws RemoteException { ...... r.app = app; r.restartTime = r.lastActivity = SystemClock.uptimeMillis(); app.services.add(r); bumpServiceExecutingLocked(r, execInFg, "create"); mAm.updateLruProcessLocked(app, false, null); mAm.updateOomAdjLocked(); boolean created = false; try { ...... mAm.ensurePackageDexOpt(r.serviceInfo.packageName); app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE); // 启动service app.thread.scheduleCreateService(r, r.serviceInfo, mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo), app.repProcState); r.postNotification(); created = true; ...... } // 执行service的onBind requestServiceBindingsLocked(r, execInFg); // 更新client状态 updateServiceClientActivitiesLocked(app, null, true); ...... // 执行Service的onStartCommand方法 sendServiceArgsLocked(r, execInFg, true); ...... }
app.thread为新建服务的Binder代理,运行scheduleCreateService()就远程调用到ActivityThread中。
frameworks/base/core/java/android/app/ActivityThread.javaprivate class ApplicationThread extends ApplicationThreadNative { ...... 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; // 发送消息CREATE_SERVICE sendMessage(H.CREATE_SERVICE, s); } ......}........private class H extends Handler { ...... public void handleMessage(Message msg) { ...... case CREATE_SERVICE: Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceCreate"); // 在handler中处理消息 handleCreateService((CreateServiceData)msg.obj); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; ...... }...... private void handleCreateService(CreateServiceData data) {l // 跳过GC unscheduleGcIdler(); LoadedApk packageInfo = getPackageInfoNoCheck( data.info.applicationInfo, data.compatInfo); Service service = null; try { // 通过反射创建service java.lang.ClassLoader cl = packageInfo.getClassLoader(); service = (Service) cl.loadClass(data.info.name).newInstance(); ...... } try { // 创建context ContextImpl context = ContextImpl.createAppContext(this, packageInfo); context.setOuterContext(service); // 创建Application Application app = packageInfo.makeApplication(false, mInstrumentation); service.attach(context, this, data.info.name, data.token, app, ActivityManagerNative.getDefault()); // 调用service的onCreate方法,正式启动service service.onCreate(); mServices.put(data.token, service); try { ActivityManagerNative.getDefault().serviceDoneExecuting( data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0); } catch (RemoteException e) { // nothing to do. } ...... } }
到这里,Service就已经完成启动。之后AMS会进行bindService,服务端执行bind时调用publishService来发布service,表明service已经可以使用。Bind过程最后会通过bindService最开始时传给AMS的IServiceConnection代理回调到应用进程,执行onServiceConnected()。这个Binder回调也会将新建服务的Binder代理传回去,这样应用就可以使用这个代理与服务进行通信。细节就不再继续分析,通过下面的图简单描述一下整个流程。本文只是在最简单的角度来分析bindService过程,实际代码中许多的细节都没有描述。
上图重点描述各进程之间的关系,可以看到整个Service的bind过程涉及到多个不同的Binder。
- IActivityManager:应用进程或服务进程与AMS通信时使用的Binder接口。AMS启动后向ServiceManager注册,其他进程从ServiceManager中获取代理。
- IApplicationThread:服务进程启动后创建的Binder接口。回传给AMS,并由AMS进行管理。
- IServiceConnection:应用进程创建发送给AMS,当服务连接成功后通过该Binder回调到应用进程,同时将服务进程的Binder接口回传给应用。
本文仅讲解了通过bindService来启动服务,但Android中存在多种启动服务的方式,它们存在区别,使用场景也不同。
- startService: 仅仅启动Service,通常为后台服务。服务启动后就与发起者无关。
- bindService:启动Service并绑定,用于发起者与服务进行交互。当发起者退出时,服务也跟随退出。
- 启动系统服务:创建一个进程,通过ServiceManager.addService()注册为系统服务,Client通过ServiceManager.getService()来获取服务。这种方法在native和java都可以使用,但需要手动启动服务进程。
Service的管理也是不同的,系统服务是由ServiceManager进行管理的,而startService和bindService启动的服务是由AMS来管理。
更多相关文章
- Android(安卓)之Notification 用法
- 《android 利用自带技术解析json字符》
- android 通过uri启动Activity
- Activity 组件的启动流程
- Android(安卓)studio黑科技
- Android(安卓)优化开机启动
- Android(安卓)动态代理以及利用动态代理实现 ServiceHook
- Android主题更换换肤
- [Android5.1]开机动画显示工作流程分析