模拟器在硬件上为android提供虚拟sensors,通过模拟器console,或者模拟器sensors socket通道,我们可以从外界(比如eclipse调试工具)设置这些虚拟sensors的值
模拟器中运行的android,通过qemu sensor HAL拿到这些sensors值,qemu sensor HAL与实体手机的sensor HAL的区别在于:实体手机的sensor HAL通过底层Linux驱动获取真实sensors数据,qemu sensor HAL通过qemud的socket通道获取前面设置的虚拟sensors值
关于qemud,代码(qemud.c)中有一段介绍,很好说明了qemud与模拟器、qemu sensor HAL之间的关系:
the qemud daemon program is only used within Android as a bridge
between the emulator program and the emulated system. it really works as
a simple stream multiplexer that works as follows:
- qemud is started by init following instructions in
/system/etc/init.goldfish.rc (i.e. it is never started on real devices)
- qemud communicates with the emulator program through a single serial
port, whose name is passed through a kernel boot parameter
(e.g. android.qemud=ttyS1)
- qemud binds one unix local stream socket (/dev/socket/qemud, created
by init through /system/etc/init.goldfish.rc).
emulator <==serial==> qemud <---> /dev/socket/qemud <-+--> client1
|
+--> client2
-+-->--->==serial==>
qemud是一个桥梁,emulator将从外部应用接受到的sensors数据,通过serial串口给qemud,qemud再通过socket通道将数据传递给连接进来的client,qemu sensor HAL就是client之一
init.goldfish.rc脚本的选择依据:查看/proc/cpuinfo文件,其中的Hardware字段表明了使用哪一个init.?.rc配置,模拟器为goldfish
可以看看这幅图,更好理解qemud与模拟器、qemu sensor HAL之间的关系
模拟器通过_hwSensorClient_receive()接受到Android HAL层传递过来的请求,通过qemud_client_send()将sensors数据发送给qemud,qemu sensor HAL通过qemud_channel_recv()从qemud拿到sensors数据
sensors数据格式
HAL层发送过来的请求数据主要包括这么几种格式: "list-sensors":列出支持的sensors列表,模拟器将返回一个int表示支持的sensors mask值 "wake":原样返回给HAL,让HAL退出poll循环 "set-delay:%d":设置sensors轮询间隔 "set:%s:%d":设置对应的sensor是否enable,例如"set:acceleration:1" 模拟器将虚拟sensors数据返回给HAL,格式如下: "acceleration:%g:%g:%g":获取加速度传感器数据 "orientation:%g:%g:%g":获取方向传感器数据 "magnetic:%g:%g:%g":获取磁力传感器数据 "temperature:%g":获取温度传感器数据 "proximity:%g":获取距离传感器数据 "sync:%lld":sent after a series of sensor events where 'time' is expressed in micro-seconds下面来看看具体的代码 qemu sensor HAL层对应的代码位于device/generic/goldfish/sensors/sensors_qemu.c 模拟器的虚拟sensors代码位于android-4.4/external/qemu/android/hw-sensors.c
/* handle incoming messages from the HAL module */
static void
_hwSensorClient_receive( HwSensorClient* cl, uint8_t* msg, int msglen )
{
HwSensors* hw = cl->sensors;
D("%s: '%.*s'", __FUNCTION__, msglen, msg);
/* "list-sensors" is used to get an integer bit map of
* available emulated sensors. We compute the mask from the
* current hardware configuration.
*/
if (msglen == 12 && !memcmp(msg, "list-sensors", 12)) {
char buff[12];
int mask = 0;
int nn;
for (nn = 0; nn < MAX_SENSORS; nn++) {
if (hw->sensors[nn].enabled)
mask |= (1 << nn);
}
snprintf(buff, sizeof buff, "%d", mask);
_hwSensorClient_send(cl, (const uint8_t*)buff, strlen(buff));
return;
}
/* "wake" is a special message that must be sent back through
* the channel. It is used to exit a blocking read.
*/
if (msglen == 4 && !memcmp(msg, "wake", 4)) {
_hwSensorClient_send(cl, (const uint8_t*)"wake", 4);
return;
}
/* "set-delay:<delay>" is used to set the delay in milliseconds
* between sensor events
*/
if (msglen > 10 && !memcmp(msg, "set-delay:", 10)) {
cl->delay_ms = atoi((const char*)msg+10);
if (cl->enabledMask != 0)
_hwSensorClient_tick(cl);
return;
}
/* "set:<name>:<state>" is used to enable/disable a given
* sensor. <state> must be 0 or 1
*/
if (msglen > 4 && !memcmp(msg, "set:", 4)) {
char* q;
int id, enabled, oldEnabledMask = cl->enabledMask;
msg += 4;
q = strchr((char*)msg, ':');
if (q == NULL) { /* should not happen */
D("%s: ignore bad 'set' command", __FUNCTION__);
return;
}
*q++ = 0;
id = _sensorIdFromName((const char*)msg);
if (id < 0 || id >= MAX_SENSORS) {
D("%s: ignore unknown sensor name '%s'", __FUNCTION__, msg);
return;
}
if (!hw->sensors[id].enabled) {
D("%s: trying to set disabled %s sensor", __FUNCTION__, msg);
return;
}
enabled = (q[0] == '1');
if (enabled)
cl->enabledMask |= (1 << id);
else
cl->enabledMask &= ~(1 << id);
if (cl->enabledMask != oldEnabledMask) {
D("%s: %s %s sensor", __FUNCTION__,
(cl->enabledMask & (1 << id)) ? "enabling" : "disabling", msg);
}
/* If emulating device is connected update sensor state there too. */
if (hw->sensors_port != NULL) {
if (enabled) {
sensors_port_enable_sensor(hw->sensors_port, (const char*)msg);
} else {
sensors_port_disable_sensor(hw->sensors_port, (const char*)msg);
}
}
_hwSensorClient_tick(cl);
return;
}
D("%s: ignoring unknown query", __FUNCTION__);
}
/* this function is called periodically to send sensor reports
* to the HAL module, and re-arm the timer if necessary
*/
static void
_hwSensorClient_tick( void* opaque )
{
HwSensorClient* cl = opaque;
HwSensors* hw = cl->sensors;
int64_t delay = cl->delay_ms;
int64_t now_ns;
uint32_t mask = cl->enabledMask;
Sensor* sensor;
char buffer[128];
if (_hwSensorClient_enabled(cl, ANDROID_SENSOR_ACCELERATION)) {
sensor = &hw->sensors[ANDROID_SENSOR_ACCELERATION];
snprintf(buffer, sizeof buffer, "acceleration:%g:%g:%g",
sensor->u.acceleration.x,
sensor->u.acceleration.y,
sensor->u.acceleration.z);
_hwSensorClient_send(cl, (uint8_t*)buffer, strlen(buffer));
}
if (_hwSensorClient_enabled(cl, ANDROID_SENSOR_MAGNETIC_FIELD)) {
sensor = &hw->sensors[ANDROID_SENSOR_MAGNETIC_FIELD];
/* NOTE: sensors HAL expects "magnetic", not "magnetic-field" name here. */
snprintf(buffer, sizeof buffer, "magnetic:%g:%g:%g",
sensor->u.magnetic.x,
sensor->u.magnetic.y,
sensor->u.magnetic.z);
_hwSensorClient_send(cl, (uint8_t*)buffer, strlen(buffer));
}
if (_hwSensorClient_enabled(cl, ANDROID_SENSOR_ORIENTATION)) {
sensor = &hw->sensors[ANDROID_SENSOR_ORIENTATION];
snprintf(buffer, sizeof buffer, "orientation:%g:%g:%g",
sensor->u.orientation.azimuth,
sensor->u.orientation.pitch,
sensor->u.orientation.roll);
_hwSensorClient_send(cl, (uint8_t*)buffer, strlen(buffer));
}
if (_hwSensorClient_enabled(cl, ANDROID_SENSOR_TEMPERATURE)) {
sensor = &hw->sensors[ANDROID_SENSOR_TEMPERATURE];
snprintf(buffer, sizeof buffer, "temperature:%g",
sensor->u.temperature.celsius);
_hwSensorClient_send(cl, (uint8_t*)buffer, strlen(buffer));
}
if (_hwSensorClient_enabled(cl, ANDROID_SENSOR_PROXIMITY)) {
sensor = &hw->sensors[ANDROID_SENSOR_PROXIMITY];
snprintf(buffer, sizeof buffer, "proximity:%g",
sensor->u.proximity.value);
_hwSensorClient_send(cl, (uint8_t*) buffer, strlen(buffer));
}
now_ns = qemu_get_clock_ns(vm_clock);
snprintf(buffer, sizeof buffer, "sync:%" PRId64, now_ns/1000);
_hwSensorClient_send(cl, (uint8_t*)buffer, strlen(buffer));
/* rearm timer, use a minimum delay of 20 ms, just to
* be safe.
*/
if (mask == 0)
return;
if (delay < 20)
delay = 20;
delay *= 1000000LL; /* convert to nanoseconds */
qemu_mod_timer(cl->timer, now_ns + delay);
}
/* send a one-line message to the HAL module through a qemud channel */
static void
_hwSensorClient_send( HwSensorClient* cl, const uint8_t* msg, int msglen )
{
D("%s: '%s'", __FUNCTION__, quote_bytes((const void*)msg, msglen));
qemud_client_send(cl->client, msg, msglen);
}