1. IBinder跨进程通信文件的创建

1.1 aidl文件编写

as可以通过右键创建一个aidl,方便我们进行操作。正常创建的过程是在 main文件夹下创建和 java文件下同包名的包,然后创建后缀 .aidl的文件

interface IMyAidlInterface {/*** Demonstrates some basic types that you can use as parameters* and return values in AIDL.*/String getName();int getAge();void setInterface(in Person person);
}

1.2 service服务端编写

没啥好说的,记得在manifest中注册然后启动

public class MyService extends Service {private Person mPerson;@Nullable@Overridepublic IBinder onBind(Intent intent) {return mIBinder;}private IBinder mIBinder = new IMyAidlInterface.Stub() {@Overridepublic String getName() throws RemoteException {return mPerson.getName();}@Overridepublic int getAge() throws RemoteException {return mPerson.getAge();}@Overridepublic void setInterface(Person person) throws RemoteException {mPerson = person;}};
}

1.3 客户端编写

客户端需要编写一个 同样aidl 文件

然后bindservice

public class MainActivity2 extends Activity {TextView view,view2;private IMyAidlInterface myAidlInterface;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main2);view = findViewById(R.id.tv1);view2=findViewById(R.id.tv2);Intent intent = new Intent(getApplicationContext(), MyService.class);bindService(intent, connection, BIND_AUTO_CREATE);view.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {setPerson();}});view2.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {try {String name = myAidlInterface.getName();int age = myAidlInterface.getAge();Log.e("debugt","name = " + name + ", age = " + age);} catch (RemoteException e) {e.printStackTrace();}}});}private ServiceConnection connection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {myAidlInterface = IMyAidlInterface.Stub.asInterface(service);}@Overridepublic void onServiceDisconnected(ComponentName name) {myAidlInterface = null;}};private void setPerson(){Person person = new Person();person.setAge(10);person.setName("zhangsan");try {myAidlInterface.setInterface(person);} catch (RemoteException e) {e.printStackTrace();}}@Overrideprotected void onDestroy() {unbindService(connection);super.onDestroy();}
}

2. 源码分析

为什么能够跨进程通信?

从客户端的asInterface触发

public static com.example.studydemo.IMyAidlInterface asInterface(android.os.IBinder obj)
{if ((obj==null)) {return null;}android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);if (((iin!=null)&&(iin instanceof com.example.studydemo.IMyAidlInterface))) {return ((com.example.studydemo.IMyAidlInterface)iin);}return new com.example.studydemo.IMyAidlInterface.Stub.Proxy(obj);
}//通过代理给我们返回一个IMyAidlInterface的代理

客户端是怎么拿到相应service的

看下bindservice的源码流程

2.1 ContextImpl

 //ContextImpl的bindservice   第四个参数instanceName = null@Overridepublic boolean bindService(Intent service, ServiceConnection conn, int flags) {warnIfCallingFromSystemProcess();return bindServiceCommon(service, conn, flags, null, mMainThread.getHandler(), null,getUser());}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) {} else {throw new RuntimeException("Not supported in system context");}validateServiceIntent(service);try {IBinder token = getActivityToken();//这里,来到ActivityManagerServiceint 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();}}

2.2 ActivityManagerService

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 descriptorsif (service != null && service.hasFileDescriptors() == true) {throw new IllegalArgumentException("File descriptors passed in Intent");}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);}
}

2.3 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 {//省略掉一堆抛异常的代码//这里会返回null或者一个ServiceLookupResult对象,从下面两个条件看这个对象不能为null和其成员变量record不能为null//这个对象包含两个变量,一个是record 另一个是permission,即这个对象有正确的record和足够的权限才能进行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;final long origId = Binder.clearCallingIdentity();try {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);}final ProcessServiceRecord clientPsr = b.client.mServices;clientPsr.addConnection(c);ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);if (clist == null) {clist = new ArrayList<>();mServiceConnections.put(binder, clist);}clist.add(c);boolean needOomAdj = false;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);} 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);}} finally {Binder.restoreCallingIdentity(origId);}return 1;}private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,boolean execInFg, boolean rebind) throws TransactionTooLargeException {if (r.app == null || r.app.getThread() == null) {// If service is not currently running, can't yet bind.return false;}if (DEBUG_SERVICE) Slog.d(TAG_SERVICE, "requestBind " + i + ": requested=" + i.requested+ " rebind=" + rebind);if ((!i.requested || rebind) && i.apps.size() > 0) {try {//这里是ApplicationThread  它是ActivityThread的内部类r.app.getThread().scheduleBindService(r, i.intent.getIntent(), rebind,r.app.mState.getReportedProcState());if (!rebind) {i.requested = true;}i.hasBound = true;i.doRebind = false;} }return true;}

2.4 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);
}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) {CreateServiceData createData = mServicesData.get(data.token);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(isProtectedComponent(createData.info),s.getAttributionSource());try {if (!data.rebind) {//这里,回调Service的onBind方法IBinder binder = s.onBind(data.intent);//这里将binder对象公开出去,回到ActivityAManagerServiceActivityAManager.getService().publishService(data.token, data.intent, binder);} else {s.onRebind(data.intent);ActivityManager.getService().serviceDoneExecuting(data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);}} catch (RemoteException ex) {throw ex.rethrowFromSystemServer();}} catch (Exception e) {if (!mInstrumentation.onException(s, e)) {throw new RuntimeException("Unable to bind to service " + s+ " with " + data.intent + ": " + e.toString(), e);}}}}

2.5 回到ActivityAManagerService

public void publishService(IBinder token, Intent intent, IBinder service) {// Refuse possible leaked file descriptorsif (intent != null && intent.hasFileDescriptors() == true) {throw new IllegalArgumentException("File descriptors passed in Intent");}synchronized(this) {if (!(token instanceof ServiceRecord)) {throw new IllegalArgumentException("Invalid service token");}mServices.publishServiceLocked((ServiceRecord)token, intent, service);}
}

2.6 回到ActiveServices

void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {final long origId = Binder.clearCallingIdentity();try {if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "PUBLISHING " + r+ " " + intent + ": " + service);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)) {if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Not publishing to: " + c);if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bound intent: " + c.binding.intent.intent);if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Published intent: " + intent);continue;}if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Publishing to: " + c);try {//这里,将service公开出去进行连接,找到这里之后,后面两个类都是抽象类,没能找到具体实现//不过,从代码流程上来说,到这里已经可以算是一个完整的流程了c.conn.connected(r.name, service, false);} 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, false);}} finally {Binder.restoreCallingIdentity(origId);}
}

IBinder跨进程通信相关推荐

  1. Android的跨进程通信

    Android系统的跨进程简介 为什么不能直接跨进程通信? 为了安全考虑,应用之间的内存是无法互相访问的,各自的数据都存在于自身的内存区域内. 如何跨进程通信? 要想跨进程通信,就要找到一个大家都能访 ...

  2. Android跨进程通信一 Messenger

    实现客户端与服务端之间的交互 说明:         Messenger是信使的意思,从它的名字就可以了解到它充当着信差的角色.Android通过它实现跨进程通信,主要有客户端信使与服务端信使两种角色 ...

  3. Android 跨进程通信大总结

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/111553746 本文出自[赵彦军的博客] 文章目录 1.Android进程 2.修 ...

  4. Android组件化跨进程通信框架Andromeda解析

    关于组件化 随着项目结构越来越庞大,模块与模块间的边界逐渐变得不清晰,代码维护越来越困难,甚至编译速度都成为影响开发效率的瓶颈. 组件化拆分是比较常见的解决方案,一方面解决模块间的耦合关系.将通用模块 ...

  5. 【朝花夕拾】Android跨进程通信总结篇

    前言 原文:https://www.cnblogs.com/andy-songwei/p/10256379.html 只要是面试高级工程师岗位,Android跨进程通信就是最受面试官青睐的知识点之一. ...

  6. 【朝花夕拾】Android性能篇之(七)Android跨进程通信篇

    前言 转载请声明,转自[https://www.cnblogs.com/andy-songwei/p/10256379.html],谢谢! 只要是面试高级工程师岗位,Android跨进程通信就是最受面 ...

  7. 【朝花夕拾】Android性能篇之(七)Android跨进程通信篇...

    前言 原文:https://www.cnblogs.com/andy-songwei/p/10256379.html 只要是面试高级工程师岗位,Android跨进程通信就是最受面试官青睐的知识点之一. ...

  8. Android IPC 进程进程间通信或跨进程通信

    Android IPC 机制 老话长谈,趁现在有时间对IPC做一个具体的总结. IPC是Inter-Process Communication的缩写,含义就是进程间通信或者跨进程通信,是指两个进程之间 ...

  9. 再谈Android Binder跨进程通信原理

    在谈Android的跨进程通信问题上时,总会问到Android的IPC机制,是指两个进程之间进行数据交换的过程.按操作系统的中的描述,线程是CPU调度最小的单元,同时线程是一种有限的系统资源,而进程是 ...

最新文章

  1. JAVA 实现扫码二维码登录
  2. JavaEE企业级快速开发平台jeesite4的使用和快速搭建项目
  3. 翻译 github上How to be a good programmer
  4. gin-jwt对API进行权限控制
  5. win7怎么把计算机放到桌面6,win7系统如何设置更改桌面图标?
  6. 12015.linux通过代码或命令形式操作内存/dev/mem
  7. java switch语句与switch表达式区别及使用
  8. 记录一下目前thinksoar portal的进度和计划!
  9. 机器学习、数据分析类面经分享
  10. MacOS Monterey 12.5.1 (21G83) OC 0.8.4 / Cl 5148 / PE 三分区原版黑苹果镜像
  11. 房屋出租系统java版
  12. unity3D游戏素材素材哪家强?Top3都在这!
  13. 几何画板 html5,几何画板菜单栏
  14. win10 戴尔电脑 禁用触摸板
  15. 如何在批处理 bat cmd 运行时 延时 等待 ?
  16. 用python开发一款云笔记_Python成为专业人士笔记–os模块
  17. 阿里云免费SSL证书申请详细流程
  18. Hadoop3.x端口变化
  19. Coding and Paper Letter(七十)
  20. 淘宝商品采集上架拼多多店铺(无货源数据采集接口,拼多多商品详情数据,淘宝商品详情数据)接口代码对接教程

热门文章

  1. SwinTransformer:使用shifted window的层级Transformer(ICCV2021)
  2. 论文精读:Swin Transformer: Hierarchical Vision Transformer using Shifted Windows
  3. PS3手柄连接斐讯T1盒子
  4. 终端软件测试风险,终端的性能测试分析
  5. 虚幻4中常用按键和快捷键
  6. 程序员职场江湖的工具书
  7. 2023自动化/计算机保研经验贴
  8. Scikit-Lear(machine learning)
  9. vue-draggable-resizable-gorkys 可拖拽缩放的组件
  10. RocketMQ msgId与offsetMsgId释疑(实战篇),腾讯技术官发布的“神仙文档”火爆网络