Android-binder
这是一张图片,ocr 内容为:AIDL跨进除调用 O CLIENT SERVER PROXY STUB TRANSACT BINDER () ONTRANSACT 驱动 HTTPS//BLDG.CS'DN.NET/LELARNITARNEWC回忆。
Android-binder
app层的binder应用
2种:
1.使用service组件
这种间接使用的也是serviceManager

public class MyService extends Service {
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return mBinder;
}
IChangeCallback mCallBack = null;
IStudentInterface.Stub mBinder = new IStudentInterface.Stub() {
@Override
public int getStudentId(String name) throws RemoteException {
if (name.equals( "helloworld")) {
if (mCallBack!= null) {
Log.i("test"," mCallBack changeData result = " + mCallBack.changeData(1111));
}
return 1;
} else {
return 10;
}
}
};
@Override
public void onCreate() {
Log.i("test","MyService onCreate");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("test","MyService onStartCommand intent = " + intent );
return super.onStartCommand(intent, flags, startId);
}
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
Log.i("test","MyService onDestroy");
super.onDestroy();
}
}
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this,MyService.class);
bindService(intent, new ServiceConnection() {
//bind后会调用这个onServiceConnected
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//service这个对象就是服务端onBind返回的IBinder对象
IStudentInterface remoteInterface = IStudentInterface.Stub.asInterface(service);
try {
int helloworld = remoteInterface.getStudentId("helloworld");
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.i("test","client onServiceDisconnected name = " +name);
}
}, BIND_AUTO_CREATE);
}
});
2.直接使用serviceManager.getService
BatteryManager manager = (BatteryManager) getSystemService(BATTERY_SERVICE);
例如getSystemService实际上最终也是调用的binder 下面的是源码注册BatteryManager时把register(binder)对象返回出来
然后我们在使用BatteryManager manager时最终会调用到这个register 也就是说使用的是binder

| 特性 | Binder | AIDL |
|---|---|---|
| 本质 | 一套 IPC 机制和内核驱动 | 一种接口定义语言和代码生成工具 |
| 在代码中看到的是(AIDL封装) | 实际底层发生的是(Binder机制) |
|---|---|
IStudentInterface.Stub |
一个继承了 Binder的类 |
AIDL 是基于 Binder 机制的一套高级封装,它通过自动生成代码的方式,让开发者能够以一种简单、直观的方式(类似于本地接口调用)来使用复杂的 Binder IPC。
AIDL
https://blog.csdn.net/learnframework/article/details/120103471
参考:详细https://blog.csdn.net/learnframework/article/details/119634022
what?aidl是一种语言,用来帮助写binder跨进程通信的接口
why:
1.如果要java语言实现那会导致要写很多重复的固定代码,写的代码量比较大,稍微不小心容易出错
2这一部分完全可以让脚本根据某些配置文件来生成对应的java代码

生成的IStudentInterface.java中主要了解的是Stub 类和Stub .Proxy
按照调用顺序:
Proxy就是remoteInterface=asInterface(iBinder);返回的类
然后remoteInterface.getStudentId(“helloworld”);
然后调用到 mRemote.transact(Stub.TRANSACTION_getStudentId, _data, _reply, 0);
然后会调用到Stub的onTransact
public static abstract class Stub的onTransact方法最终会调用到我们自己实现的匿名内部类的具体实现方法(getStudentId)
总结proxy在客户端 Stub在调用服务端方法 
回忆
public IBinder onBind(Intent intent) {
return mBinder; } IChangeCallback mCallBack = null; IStudentInterface.Stub mBinder = new IStudentInterface.Stub() { @Override public int getStudentId(String name) throws RemoteException { }}};
final IStudentInterface1 remoteInterface = IStudentInterface1.Stub.asInterface(service);
remoteInterface.getStudentId(“helloworld”);
AIDL写法
写个aidl文件
interface IStudentInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
// void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
// double aDouble, String aString);
int getStudentId(String name);
}
这个aidl文件写好后,点击make编译一下工程,在编译过程就会被aidl.exe转成对应的java文件
在Service写个Stub的匿名实现类,在onbind方法中返回出去
public class MyService extends Service {
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return mBinder;
}
IChangeCallback mCallBack = null;
IStudentInterface.Stub mBinder = new IStudentInterface.Stub() {
@Override
public int getStudentId(String name) throws RemoteException {
if (name.equals( "helloworld")) {
if (mCallBack!= null) {
Log.i("test"," mCallBack changeData result = " + mCallBack.changeData(1111));
}
return 1;
} else {
return 10;
}
}
act调用方:
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this,MyService.class);
bindService(intent, new ServiceConnection() {
//bind后会调用这个onServiceConnected
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//service这个对象就是服务端onBind返回的IBinder对象
IStudentInterface remoteInterface = IStudentInterface.Stub.asInterface(service);
try {
int helloworld = remoteInterface.getStudentId("helloworld");
aidl的几个关键字

默认aidl是同步的, 默认in类型
in out inout修饰的是传参数,和返回值没有关系,不影响return的值
1.oneway
立即返回,没有callback,异步的,不能有返回值
2.in(以服务端角度)
in 表示数据只能由客户端流向服务端。(表现为服务端修改此参数,不会影响客户端的对象)
3.out(以服务端角度)
out 表示数据只能由服务端流向客户端。(表现为服务端收到的参数是空对象,并且服务端修改对象后客户端会同步变动)
4.inout
inout 则表示数据可在服务端与客户端之间双向流通。(表现为服务端能接收到客户端传来的完整对象,并且服务端修改对象后客户端会同步变动)
binder双向通信
setCallback把Ibinder对象传到服务端,服务端作为新的客户端调用这个Ibinder对象的方法
客户端:
IStudentInterface remoteInterface = IStudentInterface.Stub.asInterface(service);
try {
remoteInterface.setCallback(new CallbackeService());
服务端
public class MyService extends Service {
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return mBinder;
}
IChangeCallback mCallBack = null; //是个adil的接口实际上就是这里把IChangeCallback的实现类传过来了,
之后就可以调用客户端提供的方法了
IStudentInterface.Stub mBinder = new IStudentInterface.Stub() {
@Override
public void setCallback(IChangeCallback callback) throws RemoteException {
mCallBack = callback;
mCallBack.asBinder().linkToDeath(new DeathRecipient() {
@Override
public void binderDied() {
Log.i("test","linkToDeath binderDied");
}
},0);
}

4、linktodeath介绍
bindSevices,当服务端crash时,客户端service会回调OnSeviceDisconnected
那为什么还需要linktodeath?
在双向通信时setCallback()这个实现是在客户端,这个时候如果服务端调用客户端的方法是感知不到客户端是否crash,(也就是上图的第3步)
死亡通知是为了让Bp端(客户端进程)进能知晓Bn端(服务端进程)的生死情况,当Bp端进程死亡后能通知到Bn端。
定义:AppDeathRecipient是继承IBinder::DeathRecipient类,主要需要实现其binderDied()来进行死亡通告。
注册:binder->linkToDeath(AppDeathRecipient)是为了将AppDeathRecipient死亡通知注册到Binder上。
Bp端只需要覆写binderDied()方法,实现一些后尾清除类的工作,则在Bn端死掉后,会回调binderDied()进行相应处理。
@Override
public void setCallback(IChangeCallback callback) throws RemoteException {
mCallBack = callback;
//监听客户端(上图左边)的进程是否死了
mCallBack.asBinder().linkToDeath(new DeathRecipient() {
@Override
public void binderDied() {
Log.i("test","linkToDeath binderDied");
}
},0);
}
当然双向通信时 你可以在两边都加上linktodeath
Messenger
Message 消息
Messenger 消息者 邮递员
Messenger是基于AIDL实现的轻量级IPC方案。
这里立马就会有疑问为什么要它呢?明明有了aidl
毕竟通信什么的要写aidl,而且客户端和服务端都需要aidl文件,两个过程里面都需要,相对来说还是比较麻烦,对于项目过程中可能就是一些简单的跨进程数据传递,就是调用几个非常非常简单的方法,很多觉得都要写aidl成本比较大,那么有没有更加简单的方案来解决这个问题呢?
那就是Messenger。
https://blog.csdn.net/learnframework/article/details/119845833
1、服务端对Messenger的使用
服务端需要实现一个Handler用于处理客户端发来的跨进程通信信息:
Handler messengerHandler = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
switch (msg.what) {
case 1:
Log.i("test","MessengerService Messenger handleMessage msg = " + msg + " bundle key value = " + msg.getData().getString("bundleKey"));
Messenger clientSend = msg.replyTo;
Message toClientMsg = Message.obtain();
toClientMsg.what = 2;
// toClientMsg.obj = "I am replay from Server";
try {
clientSend.send(toClientMsg);
}catch (Exception e) {
Log.i("test","MessengerService clientSend error ",e);
}
break;
}
super.handleMessage(msg);
}
};
其次服务端构造出对应的Messenger:
服务端构造:
Messenger messenger = new Messenger(messengerHandler);
注意这里参数是messengerHandler即一个Handler
最后,当服务端的onBinder回调时候要返回Messenger的IBinder对象给客户端
@Nullable
@Override
public IBinder onBind(Intent intent) {
return messenger.getBinder();
}
2、客户端的使用
客户端还是和以前一样通过bindService在ServiceConnection类的onServiceConnected获取到服务端的返回的IBinder,从而获取到服务端的Messenger代理类,调用send函数发送Message。所以Messenger能发送的信息只有Message能携带的信息。
Intent intent = new Intent(MainActivity.this,MessengerService.class);
Log.i("test","MessengerService onClick ");
bindService(intent, new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
try {
Log.i("test","MessengerService onServiceDisconnected name = " +name);
messengerServer = new Messenger(service);
sendMessageToServer();
} catch (Exception e) {
e.printStackTrace();
Log.i("test","error " ,e);
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.i("test","client onServiceDisconnected name = " +name);
}
}, BIND_AUTO_CREATE);
void sendMessageToServer() throws RemoteException {
Message toServer = Message.obtain();//构造Message
toServer.replyTo = messengerClientSend;//这个也是一个messengerServer发信东西。对面可以回复
toServer.what = 1;
//toServer.obj = "hello I send from client"; 注意不可以 传递非parcel的对象,这个只能给obj赋值为parcel类型对象否则报错
Bundle bundle = new Bundle();
bundle.putString("bundleKey","bundleValue Client");
toServer.setData(bundle);
messengerServer.send(toServer); //messengerServer发信
}
大家这里注意客户端获取了服务端IBinder对象后,用它来构造客户端的Messenger,
messengerServer = new Messenger(service);
这里注意是和服务端不一样地方
有了服务端Messenger后,那么就可以通过它与服务端进行通信了,通信的内容载体是我们最为属性Message,对他就是和Handler搭配的Message,它就是具体消息体,即你需要发送什么消息,都是把内容转换成Message对象既可以,这里我们案例中传递一个Bundle的对象,这个Bundle对象可以利用键值对方式装载各种各样类型数据。和Intent传递数据Bundle是一样的。注意这里message对象还有一个属性是replyTo ,这个是Messenger类型的,字面意思就是说这个消息发送过去,如果对方需要回复,就可以通过消息中的replyTo 的Messenger对象来进行回复,这里是不是也和我们上节课讲的binder双向通信一样,所以说Messenger这种方式本身就相当于自带了双向通信
3 Messenger本质原理
Messenger其实本质上也是使用aidl进行实现了,只是这个aidl是在Framework层面进行写好了,不需要你写,你也就没有在意,没有看到。这里对他的源码进行分析一下:
public final class Messenger implements Parcelable {
private final IMessenger mTarget;
/**
* Create a new Messenger pointing to the given Handler. Any Message
* objects sent through this Messenger will appear in the Handler as if
* {@link Handler#sendMessage(Message) Handler.sendMessage(Message)} had
* been called directly.
*
* @param target The Handler that will receive sent messages.
*/
public Messenger(Handler target) {
mTarget = target.getIMessenger();//这个是handler对象获取IMessenger接口
}
/**
* Send a Message to this Messenger's Handler.
*
* @param message The Message to send. Usually retrieved through
* {@link Message#obtain() Message.obtain()}.
*
* @throws RemoteException Throws DeadObjectException if the target
* Handler no longer exists.
*/
public void send(Message message) throws RemoteException {
mTarget.send(message);//这其实调用是IMessenger接口的send
}
。。。。。省略
}
代码中注释提到的handler对象获取IMessenger接口,IMessenger 接口到底又是什么呢?
目前我没没有看到有aidl啊。。。
Handler的getIMessenger
@UnsupportedAppUsage
final IMessenger getIMessenger() {
synchronized (mQueue) {
if (mMessenger != null) {
return mMessenger;
}
mMessenger = new MessengerImpl();
return mMessenger;
}
}
private final class MessengerImpl extends IMessenger.Stub {
public void send(Message msg) {
msg.sendingUid = Binder.getCallingUid();
Handler.this.sendMessage(msg);
}
}
大家看这里其实就是MessengerImpl ,是继承IMessenger.Stub,大家看到IMessenger.Stub是不是和aidl里面的接口和很熟悉啊。对它其实就是IMessenger.aidl文件生成的
更多推荐
所有评论(0)