Android BitTube

From:

http://netaz.blogspot.my/2015/06/android-bittube.html

在浏览Android SensorService模块源代码的时候看到BitTube,相较于其他AOSP (Android Open Source Project) 类,它的代码量很小。第一眼,我莫名地非常喜欢BitTube这个名字(do geeks really need reasons to like class names?)。虽然BitTube只有寥寥100多行的代码,但在这短小精悍背后,似乎隐藏着某些有意思的事情,值得花时间去深入发掘。

如果脱离了Android环境(outside of the Android context),BitTube显得十分的其貌不扬:BitTube的实现很简洁,就是一对"parcel-able"模式的socket,用Linux/Unix中的术语来说叫“socketpair”。“socketpair”是Linux/Unix系统中用于进程间通信的一种机制,和“pipe”十分类似。对于进程间通信,AOSP特意花大力气实现了“Binder”,而Binder”应用场合也是无处不在(没有使用Binder”的另一个例外是rild(radio interface daemon)中的“RIL”,socket IPC),为何在如此关键的地方,AOSP放弃Binder”而使用 Linux 的IPC呢

socketpair”利用socket为双方建立了全双工的通信管道(communication pipe)。通过文件描述符的复用(dup/dup2),可以传递socket handle到另一个进程,复用它并开启通信。BitTube使用了Linux/Unix socket中的顺序数据包(sequenced packets,SOCK_SEQPACKET),像SOCK_DGRAM,它只传送整包数据;又像SOCK_STREAM,面向连接且提供有序的数据报传送。尽管socketpair”是一个全双工的管道,但BitTube是按照单向方式使用它的:一端写入数据,另一端读出数据。收、发缓存都被默认限制为4KB大小。在BitTube中,提供了收发序列化对象的方法(sendObjects, recvObjects)。
socket_type.h
SOCK_STREAM = 1,/* Sequenced, reliable, connection-based byte streams.  */
SOCK_DGRAM = 2,	/* Connectionless, unreliable datagrams
SOCK_SEQPACKET = 5,/* Sequenced, reliable, connection-based, datagrams of fixed maximum length.  */

AOSP中使用BitTube 的地方有显示(Display)子系统和Sensor子系统,接下来看下Sensor子系统是如何使用它的:
APP通过SensorManager这一系统服务去访问(虚拟的/物理的)sensor设备,APP注册2个回调函数,用来接收sensor产生的事件。一个回调函数报告精度的改变(accuracy change),另一个报告数据(事件)是否可获取。
public class SensorActivity extends Activity, implements SensorEventListener {
     private final SensorManager mSensorManager;
     private final Sensor mAccelerometer;
     public SensorActivity() {
         mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
         mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
     }
     protected void onResume() {
         super.onResume();
         mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
     }
     protected void onPause() {
         super.onPause();
         mSensorManager.unregisterListener(this);
     }
     public void onAccuracyChanged(Sensor sensor, int accuracy) {
     }
     public void onSensorChanged(SensorEvent event) {
     }
}

SensorManager.registerListener的实现背后有大量工作要做:首先,SensorManager向SystemSensorManager提交注册请求,由SystemSensorManager最终实现监听器的注册,如下代码片段:
/** @hide */
@Override
protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,
		int delayUs, Handler handler, int maxBatchReportLatencyUs, int reservedFlags) {
	// Invariants to preserve:
	// - one Looper per SensorEventListener
	// - one Looper per SensorEventQueue
	// We map SensorEventListener to a SensorEventQueue, which holds the looper
	synchronized (mSensorListeners) {
		SensorEventQueue queue = mSensorListeners.get(listener);
		if (queue == null) {
			Looper looper = (handler != null) ? handler.getLooper() : mMainLooper;
			queue = new SensorEventQueue(listener, looper, this);
			if (!queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs, reservedFlags)) {
				queue.dispose();
				return false;
			}
			mSensorListeners.put(listener, queue);
			return true;
		} else {
			return queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs, reservedFlags);
		}
	}
}

可见,每注册一个SensorEventListener都会穿件一个SensorEventQueue和Looper。Sensor产生的事件最终由SensorEventQueue上传给APP,为便于更加深入的理解Java和native代码的交互流程,请看下图:


鉴于本篇blog的主体是BitTube而非Sensor子系统,所以忽略细节,结论是:最终创建了一个native的SensorEventQueue 。native的SensorEventQueue (IPC客户端)使用SensorEventConnection作为和SensorService通信的桥梁。BnSensorEventConnection(IPC服务端)创建了一个带socketpair功能的BitTube,该BitTube的另一端由BpSensorEventConnection dup'ed('dup' system call)了,如下图描述:


如前所述,BitTube是被当作半双工管道使用的:事件由一端写入,另一端读取,读取由SensorEventQueue完成。
创建BitTube这一socketpair 的过程中,kernel为其分配了2 x 4KB(默认大小)的缓存:一方发送缓存,通过SO_SNDBUF选项设置;另一个接收缓存,通过SO_RCVBUF选项设置:
#define SOCKET_BUFFER_SIZE_NON_BATCHED 4 * 1024
new BitTube(SOCKET_BUFFER_SIZE_NON_BATCHED);
BitTube::BitTube(size_t bufsize)
    : mSendFd(-1), mReceiveFd(-1)
{
    init(bufsize, bufsize);
}
void BitTube::init(size_t rcvbuf, size_t sndbuf) {
    int sockets[2];
    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets) == 0) {
        size_t size = DEFAULT_SOCKET_BUFFER_SIZE;
        setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf));
        setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf));
        // sine we don't use the "return channel", we keep it small...
        setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
        setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
        fcntl(sockets[0], F_SETFL, O_NONBLOCK);
        fcntl(sockets[1], F_SETFL, O_NONBLOCK);
        mReceiveFd = sockets[0];
        mSendFd = sockets[1];
    } else {
        mReceiveFd = -errno;
        ALOGE("BitTube: pipe creation failed (%s)", strerror(-mReceiveFd));
    }
}

需要注意的是:这只是一个SensorEventListener的开销(2x4KB)!此外,每一个SensorEventListener还有一个Looper线程,总体算下来,这是一笔相当的的开销。So,问题依旧:使用BitTube这一"新" IPC到底有什么好处?起初,我以为这或许是早前版本的Android遗留下来的设计(legacy design),又或许是系统中的某个模块早先留在系统代码中的,但这不能解释为什么DisplayEventReceiver也使用BitTube。。。
也许这么做可以达到更低的延时(extra low latency)?BitTube可以在一个write/read中传送多个事件,但这同样可以通过Binder”实现并且不会带来任何并发问题。它们几乎引起了同样数量的上下文切换、缓存拷贝、系统调用。
BitTube简化了实现?肯定没有,它几乎和Binder”一样复杂。

译言:个人对Binder”不熟悉,也不了解使用Binder”的场合,最近遇到BitTube,在资料很少的情况下,这是讲述很有调理且准确的好Blog。至于为什么使用BitTube,有限的知识给不出结论,至于“Sensor数据量大”的说法,更没说服力。
以下为原文下的一篇回复:
I recently stumbled across bittube as well. I wanted to figure out why they introduce this and ended up here.
So far, the only reason I could think of is because the sensor data is being pumped from the native service to the application. Sort of push model, where the client subscribes for it and server pushes the data. In the binder mechanism, it is always a pull mechanism, where a client wishes for some processing to be done and that is off loaded to the server. One advantage I could think of this design is that the client doesn't need to spawn new thread to wait for data from service.
This got me to wonder which other service would use a pull model, off the top of my head, location services would suit this model. But I haven't checked the code on how they achieve the data communications in location services, need to look up that.
Does this reason sound plausible? What do you think?

原文 http://netaz.blogspot.my/2015/06/android-bittube.html

  • 0
    点赞
  • 0
    收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:编程工作室 设计师:CSDN官方博客 返回首页
评论
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值