Messenger简介及其作用
Messenger是一种轻量级的IPC方案,通过它可以在不同进程中传递Message对象,在Message中放入我们需要传递的数据,就可以实现数据的进程间传递了。其中本质还是Handler和AIDL的封装和结合。
- 按键截屏使用的就是Messenger的方式进行IPC通信
我们都知道原生android中截屏触发是同时按住电源键和音量下键,然后就能够截取屏幕了。
这个事件的处理流程在PhoneWindowManager.java中进行处理。
经过多步骤的跳转(后续补充完整),跳到了方法takeScreenshot,代码如下:
private static final String SYSUI_PACKAGE = "com.android.systemui";
private static final String SYSUI_SCREENSHOT_SERVICE =
"com.android.systemui.screenshot.TakeScreenshotService";
private void takeScreenshot(final int screenshotType) {
synchronized (mScreenshotLock) {
if (mScreenshotConnection != null) {
return;
}
final ComponentName serviceComponent = new ComponentName(SYSUI_PACKAGE,
SYSUI_SCREENSHOT_SERVICE);
final Intent serviceIntent = new Intent();
serviceIntent.setComponent(serviceComponent);
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
synchronized (mScreenshotLock) {
if (mScreenshotConnection != this) {
return;
}
Messenger messenger = new Messenger(service);
Message msg = Message.obtain(null, screenshotType);
final ServiceConnection myConn = this;
Handler h = new Handler(mHandler.getLooper()) {
@Override
public void handleMessage(Message msg) {
synchronized (mScreenshotLock) {
if (mScreenshotConnection == myConn) {
//绑定成功之后,就通知客户端进行解绑操作(我也不知道为什么立刻解绑,可能是启动之后会自动截图,不再需要绑定)
mContext.unbindService(mScreenshotConnection);
mScreenshotConnection = null;
mHandler.removeCallbacks(mScreenshotTimeout);
}
}
}
};
msg.replyTo = new Messenger(h);
msg.arg1 = msg.arg2 = 0;
if (mStatusBar != null && mStatusBar.isVisibleLw())
msg.arg1 = 1;
if (mNavigationBar != null && mNavigationBar.isVisibleLw())
msg.arg2 = 1;
try {
messenger.send(msg);
} catch (RemoteException e) {
}
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
notifyScreenshotError();
}
};
if (mContext.bindServiceAsUser(serviceIntent, conn,
Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
UserHandle.CURRENT)) {
mScreenshotConnection = conn;
mHandler.postDelayed(mScreenshotTimeout, 10000);
}
}
}
主要步骤就是bindServiceAsUser,绑定SystemUI模块中的TakeScreenshotService服务。
ServiceConnection中onServiceConnected方法,
synchronized (mScreenshotLock) {
if (mScreenshotConnection != this) {
return;
}
Messenger messenger = new Messenger(service);
Message msg = Message.obtain(null, screenshotType);
final ServiceConnection myConn = this;
Handler h = new Handler(mHandler.getLooper()) {
@Override
public void handleMessage(Message msg) {
synchronized (mScreenshotLock) {
if (mScreenshotConnection == myConn) {
mContext.unbindService(mScreenshotConnection);
mScreenshotConnection = null;
mHandler.removeCallbacks(mScreenshotTimeout);
}
}
}
};
msg.replyTo = new Messenger(h);
msg.arg1 = msg.arg2 = 0;
if (mStatusBar != null && mStatusBar.isVisibleLw())
msg.arg1 = 1;
if (mNavigationBar != null && mNavigationBar.isVisibleLw())
msg.arg2 = 1;
try {
messenger.send(msg);
} catch (RemoteException e) {
}
}
根据服务端传过来的IBinder,构建对应的Messenger,相当于构建服务端的Messenger代理,然后封装各种数据到Message,然后通过Messenger代理传回给服务端,服务端根据封装的数据,进行截图。
其中还有一个包含重要的步骤:
msg.replyTo = new Messenger(h);
这一步将客户端的Messenger传送给服务端,服务端根据msg.replyTo,回调客户端。
那么这个takeScreenshot方法端就是所谓的客户端,用来绑定SystemUI中的服务端。
调用服务端的TakeScreenshotService进行实际的截屏操作。再来看看TakeScreenshotService源码:
public class TakeScreenshotService extends Service {
private static final String TAG = "TakeScreenshotService";
private static GlobalScreenshot mScreenshot;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
final Messenger callback = msg.replyTo;
Runnable finisher = new Runnable() {
@Override
public void run() {
Message reply = Message.obtain(null, 1);
try {
callback.send(reply);
} catch (RemoteException e) {
}
}
};
if (mScreenshot == null) {
mScreenshot = new GlobalScreenshot(TakeScreenshotService.this);
}
switch (msg.what) {
case WindowManager.TAKE_SCREENSHOT_FULLSCREEN:
mScreenshot.takeScreenshot(finisher, msg.arg1 > 0, msg.arg2 > 0);
break;
case WindowManager.TAKE_SCREENSHOT_SELECTED_REGION:
mScreenshot.takeScreenshotPartial(finisher, msg.arg1 > 0, msg.arg2 > 0);
break;
}
}
};
@Override
public IBinder onBind(Intent intent) {
return new Messenger(mHandler).getBinder();
}
@Override
public boolean onUnbind(Intent intent) {
if (mScreenshot != null) mScreenshot.stopScreenshot();
return true;
}
}
就是一个标准的绑定服务的写法 返回new Messenger(mHandler).getBinder(),其实就是将服务端Messenger的地址发送给客户端。回调onServiceConnected方法,告诉客户端绑定成功。服务端自己绑定成功之后就根据screenshotType,进行全部
截图还是部分截图。
- Messenger源码分析 先看一下Messenger的源码:
//实现了Parcelable,可以再进程之间传递的数据
public final class Messenger implements Parcelable {
private final IMessenger mTarget;
//通过Handler创建mTarget,一般先在服务端建立Messenger,传给客户端,然后在客户端获取对应的IBinder,然后建立一个Messenger(相当于服务端Messenger的代理)
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
通过IBinder创建mTarget,一般在客户端建立(相当于服务端Messenger的代理)
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
//跨进程发送消息
public void send(Message message) throws RemoteException {
mTarget.send(message);
}
//服务端返回Messenger对应的IBinder地址,给客户端进行处理
public IBinder getBinder() {
return mTarget.asBinder();
}
public boolean equals(Object otherObj) {
if (otherObj == null) {
return false;
}
try {
return mTarget.asBinder().equals(((Messenger)otherObj)
.mTarget.asBinder());
} catch (ClassCastException e) {
}
return false;
}
}
其中就一个属性mTarget,看看这个具体是什么吧。就是MessengerImpl对象,继承IMessenger.Stub。 这个一看就是IMessenger这个AIDL的实现类。
private final IMessenger mTarget;
//通过Handler创建mTarget,一般先在服务端建立,传给客户端,然后再客户端建立一个Messenger,通过msg.reply传给服务端
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
final IMessenger getIMessenger() {
//就是在Handler中建立一个MessengerImpl对象
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();
//实际mTarget的send方法,还是Handler发送消息。
//所以服务端send,实际就是服务端的Handler发送消息,然后在服务端处理。客户端的send发送消息,就是客户端的Handler进行处理
Handler.this.sendMessage(msg);
}
}
然后就是发送消息,然后通过Messenger的send发送,而这个send方法上面我们也分析过了,其实现就是通过Handler的sendMessage方法来发送的,所以不再多解释,又回归到了Handler与Message过程。