Android IPC进程间通信(从应用层源码分)《二》
2016-12-09 15:12
162 查看
我们来分析这张图,其实里面有一个很重要的角色ServiceManager,这个类是系统帮我们管理Service服务的类,在AIDL中,我们在服务端不是要注册一个服务吗?当这个服务启动就会往系统SericeManager类中注册,把类的描述引用通过Binder注册到里面,当我们客户端要通讯的时候,就会开始在系统服务ServiceManager中找相应的服务,只能拿到里面引用进行通信,大概就是这样的一个流程。
源码分析:
1、首先我们从入口开始看:
this.bindService(intent,new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { } @Override public void onServiceConnected(ComponentName name, IBinder service) { IBinderTest asInterface = IBinderTest.Stub.asInterface(service); try { asInterface.testBinder(); } catch (RemoteException e) { e.printStackTrace(); } } },Context.BIND_AUTO_CREATE);
这段代码非常熟悉吧,他就是我们绑定服务进程进程通讯的代码,首先我看this.bindService大家都用过这方法,不就是绑定服务的方法吗,可大家有没真正的点进去看系统是怎么绑定的,this其实在Android中指的是ContextImpl这个类,所以bindService就在ContextImpl中调用的,我们点进去一看
ContextImpl:
@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 (conn == null) { throw new IllegalArgumentException("connection is null"); } if (mPackageInfo != null) { sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), mMainThread.getHandler(), flags); } 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_S 4000 ANDWICH) { flags |= BIND_WAIVE_PRIORITY; } service.prepareToLeaveProcess(); //核心代码 int res = ActivityManagerNative.getDefault().bindService( mMainThread.getApplicationThread(), getActivityToken(), service, service.resolveTypeIfNeeded(getContentResolver()), sd, flags, user.getIdentifier()); if (res < 0) { throw new SecurityException( "Not allowed to bind to service " + service); } return res != 0; } catch (RemoteException e) { return false; } }
在bindService方法中直接调用bindServiceCommon这个方法,我们点进去,里面代码不是很多,我们只看核心代码,我在里面已经标注出来了,ActivityManagerNative.getDefault()这里就是获取IActivityManager的一个单列接口:
ActivityManagerNative:
/** * Retrieve the system's default/global activity manager. */ static public IActivityManager getDefault() { return gDefault.get(); } private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() { protected IActivityManager create() { IBinder b = ServiceManager.getService("activity"); if (false) { Log.v("ActivityManager", "default service binder = " + b); } IActivityManager am = asInterface(b); if (false) { Log.v("ActivityManager", "default service = " + am); } return am; } };
这里就是我前面的图里面所说的,通过ServiceManager.getService来获取系统中一个IBinder对象,通过asInterface这个对象来拿到IActivityManager接口,IActivityManager是继承了IInterface接口,从ActivityManagerNative中类中可以得出,这也是一个AIDL进程通讯,这里面总体的意思就是说,通过asInterface拿到服务端的对象,好了,既然拿到了对象,在看在哪里使用,我们再回到上面的代码ActivityManagerNative.getDefault().bindService,又是一个bindService方法,其实这个就是要找到ActivityManagerNative的父类就知道哪里引用了bindService方法,这里我直接告诉大家,父类就是ActivityManagerService这个类,我们找这个类的bindService
ActivityManagerService:
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.bindServiceLocked
ActiveServices:
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service, String resolvedType, IServiceConnection connection, int flags, int userId) { if (DEBUG_SERVICE) Slog.v(TAG, "bindService: " + service + " type=" + resolvedType + " conn=" + connection.asBinder() + " flags=0x" + Integer.toHexString(flags)); final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller); if (callerApp == null) { throw new SecurityException( "Unable to find app for caller " + caller + " (pid=" + Binder.getCallingPid() + ") when binding service " + service); } ActivityRecord activity = null; if (token != null) { activity = ActivityRecord.isInStackLocked(token); if (activity == null) { Slog.w(TAG, "Binding with unknown activity: " + token); return 0; } } int clientLabel = 0; PendingIntent clientIntent = null; if (callerApp.info.uid == Process.SYSTEM_UID) { // Hacky kind of thing -- allow system stuff to tell us // what they are, so we can report this elsewhere for // others to know why certain services are running. try { clientIntent = service.getParcelableExtra(Intent.EXTRA_CLIENT_INTENT); } catch (RuntimeException e) { } if (clientIntent != null) { clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0); if (clientLabel != 0) { // There are no useful extras in the intent, trash them. // System code calling with this stuff just needs to know // this will happen. service = service.cloneFilter(); } } } if ((flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) { mAm.enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS, "BIND_TREAT_LIKE_ACTIVITY"); } final boolean callerFg = callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE; ServiceLookupResult res = retrieveServiceLocked(service, resolvedType, Binder.getCallingPid(), Binder.getCallingUid(), userId, true, callerFg); if (res == null) { return 0; } if (res.record == null) { return -1; } ServiceRecord s = res.record; final long origId = Binder.clearCallingIdentity(); try { 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()) { // 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 b = s.retrieveAppBindingLocked(service, callerApp); ConnectionRecord c = new ConnectionRecord(b, activity, connection, flags, clientLabel, clientIntent); IBinder binder = connection.asBinder(); ArrayList<ConnectionRecord> clist = s.connections.get(binder); if (clist == null) { clist = new ArrayList<ConnectionRecord>(); s.connections.put(binder, clist); } clist.add(c); b.connections.add(c); if (activity != null) { if (activity.connections == null) { activity.connections = new HashSet<ConnectionRecord>(); } activity.connections.add(c); } 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); } clist = mServiceConnections.get(binder); if (clist == null) { clist = new ArrayList<ConnectionRecord>(); 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) { if ((flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) { s.app.treatLikeActivity = true; } // This could have made the service more important. mAm.updateLruProcessLocked(s.app, s.app.hasClientActivities || s.app.treatLikeActivity, b.client); mAm.updateOomAdjLocked(s.app); } if (DEBUG_SERVICE) Slog.v(TAG, "Bind " + s + " with " + b + ": received=" + b.intent.received + " apps=" + b.intent.apps.size() + " doRebind=" + b.intent.doRebind); 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); } catch (Exception e) { Slog.w(TAG, "Failure sending service " + s.shortName + " 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, callerF b213 g, false); } getServiceMap(s.userId).ensureNotStartingBackground(s); } finally { Binder.restoreCallingIdentity(origId); } return 1; } private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i, boolean execInFg, boolean rebind) { if (r.app == null || r.app.thread == null) { // If service is not currently running, can't yet bind. return false; } if ((!i.requested || rebind) && i.apps.size() > 0) { try { bumpServiceExecutingLocked(r, execInFg, "bind"); r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE); r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind, r.app.repProcState); if (!rebind) { i.requested = true; } i.hasBound = true; i.doRebind = false; } catch (RemoteException e) { if (DEBUG_SERVICE) Slog.v(TAG, "Crashed while binding " + r); return false; } } return true; }
这段代码有点长,我就不一一分析了,挑重点,这方法执行完之后会跳到requestServiceBindingLocked这个方法,这方法里面最重要一行代码就是r.app.thread.scheduleBindService,这代码的意思就是调用ActivityThread里面的scheduleBindService方法
ActivityThread:
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); } 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); ActivityManagerNative.getDefault().publishService( data.token, data.intent, binder); } else { s.onRebind(data.intent); ActivityManagerNative.getDefault().serviceDoneExecuting( data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0); } ensureJitEnabled(); } catch (RemoteException ex) { } } catch (Exception e) { if (!mInstrumentation.onException(s, e)) { throw new RuntimeException( "Unable to bind to service " + s + " with " + data.intent + ": " + e.toString(), e); } } } }
这边发送一个Handle消息BIND_SERVICE,handleBindService这是接受的地方,里面有这么一个方法ActivityManagerNative.getDefault().publishService,还是在我们ActivityManagerService方法里面找publishService,然后又会调用ActivityThread中的publishServiceLocked方法,最终我们可以看到c.conn.connected(r.name, service);这个方法回调,差不多整体的流程清楚了,希望大家看的时候把这些相关的源码下载下来,不要没个方法都去看,不然看得非常累,看一些关键的代码,希望这篇文章可以帮助到大家。
相关文章推荐
- Android IPC进程间通信(从应用层源码分)《一》
- Android进程间通信--消息机制及IPC机制实现
- 浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路(1)
- Android系统进程间通信(IPC)机制Binder中的Client获得Server远程接口过程源代码分析
- Android进程间通信--消息机制及IPC机制实现
- Android进程间通信(IPC)机制Binder简要介绍和学习计划
- IPC(进程间通信),Remote Call(远程调用),IDL(接口描述语言)架构及其在BMP(BREW移动平台),Android中的应用浅析
- Android进程间通信(IPC)机制Binder
- Android系统进程间通信(IPC)机制Binder中的Client获得Server远程接口过程源代码分析
- Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析
- Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析(4)
- Android进程间通信(IPC)机制Binder简要介绍和学习计划
- Android进程间通信(IPC)机制Binder简要介绍和学习计划
- 浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路
- Android进程间通信--消息机制及IPC机制实现 推荐
- Android进程间通信--消息机制及IPC机制实现
- [转Android进程间通信--消息机制及IPC机制实现 ]
- 浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路
- Android进程间通信(IPC)机制Binder简要介绍和学习计划
- Android进程间通信--消息机制及IPC机制实现