/* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* this implements a sensors hardware library for the Android emulator. * the following code should be built as a shared library that will be * placed into /system/lib/hw/sensors.goldfish.so * * it will be loaded by the code in hardware/libhardware/hardware.c * which is itself called from com_android_server_SensorService.cpp */ /* we connect with the emulator through the "sensors" qemud service */ #define SENSORS_SERVICE_NAME "sensors" #define LOG_TAG "QemuSensors" #include #include #include #include #include #include #include #if 0 #define D(...) ALOGD(__VA_ARGS__) #else #define D(...) ((void)0) #endif #define E(...) ALOGE(__VA_ARGS__) #include /** SENSOR IDS AND NAMES **/ #define MAX_NUM_SENSORS 5 #define SUPPORTED_SENSORS ((1<"; } static int _sensorIdFromName( const char* name ) { int nn; if (name == NULL) return -1; for (nn = 0; nn < MAX_NUM_SENSORS; nn++) if (!strcmp(name, _sensorIds[nn].name)) return _sensorIds[nn].id; return -1; } /* return the current time in nanoseconds */ static int64_t now_ns(void) { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return (int64_t)ts.tv_sec * 1000000000 + ts.tv_nsec; } /** SENSORS POLL DEVICE ** ** This one is used to read sensor data from the hardware. ** We implement this by simply reading the data from the ** emulator through the QEMUD channel. **/ typedef struct SensorDevice { struct sensors_poll_device_1 device; sensors_event_t sensors[MAX_NUM_SENSORS]; uint32_t pendingSensors; int64_t timeStart; int64_t timeOffset; uint32_t active_sensors; int fd; pthread_mutex_t lock; } SensorDevice; /* Grab the file descriptor to the emulator's sensors service pipe. * This function returns a file descriptor on success, or -errno on * failure, and assumes the SensorDevice instance's lock is held. * * This is needed because set_delay(), poll() and activate() can be called * from different threads, and poll() is blocking. * * Note that the emulator's sensors service creates a new client for each * connection through qemud_channel_open(), where each client has its own * delay and set of activated sensors. This precludes calling * qemud_channel_open() on each request, because a typical emulated system * will do something like: * * 1) On a first thread, de-activate() all sensors first, then call poll(), * which results in the thread blocking. * * 2) On a second thread, slightly later, call set_delay() then activate() * to enable the acceleration sensor. * * The system expects this to unblock the first thread which will receive * new sensor events after the activate() call in 2). * * This cannot work if both threads don't use the same connection. * * TODO(digit): This protocol is brittle, implement another control channel * for set_delay()/activate()/batch() when supporting HAL 1.3 */ static int sensor_device_get_fd_locked(SensorDevice* dev) { /* Create connection to service on first call */ if (dev->fd < 0) { dev->fd = qemud_channel_open(SENSORS_SERVICE_NAME); if (dev->fd < 0) { int ret = -errno; E("%s: Could not open connection to service: %s", __FUNCTION__, strerror(-ret)); return ret; } } return dev->fd; } /* Send a command to the sensors virtual device. |dev| is a device instance and * |cmd| is a zero-terminated command string. Return 0 on success, or -errno * on failure. */ static int sensor_device_send_command_locked(SensorDevice* dev, const char* cmd) { int fd = sensor_device_get_fd_locked(dev); if (fd < 0) { return fd; } int ret = 0; if (qemud_channel_send(fd, cmd, strlen(cmd)) < 0) { ret = -errno; E("%s(fd=%d): ERROR: %s", __FUNCTION__, fd, strerror(errno)); } return ret; } /* Pick up one pending sensor event. On success, this returns the sensor * id, and sets |*event| accordingly. On failure, i.e. if there are no * pending events, return -EINVAL. * * Note: The device's lock must be acquired. */ static int sensor_device_pick_pending_event_locked(SensorDevice* d, sensors_event_t* event) { uint32_t mask = SUPPORTED_SENSORS & d->pendingSensors; if (mask) { uint32_t i = 31 - __builtin_clz(mask); d->pendingSensors &= ~(1U << i); *event = d->sensors[i]; event->sensor = i; event->version = sizeof(*event); D("%s: %d [%f, %f, %f]", __FUNCTION__, i, event->data[0], event->data[1], event->data[2]); return i; } E("No sensor to return!!! pendingSensors=0x%08x", d->pendingSensors); // we may end-up in a busy loop, slow things down, just in case. usleep(100000); return -EINVAL; } /* Block until new sensor events are reported by the emulator, or if a * 'wake' command is received through the service. On succes, return 0 * and updates the |pendingEvents| and |sensors| fields of |dev|. * On failure, return -errno. * * Note: The device lock must be acquired when calling this function, and * will still be held on return. However, the function releases the * lock temporarily during the blocking wait. */ static int sensor_device_poll_event_locked(SensorDevice* dev) { D("%s: dev=%p", __FUNCTION__, dev); int fd = sensor_device_get_fd_locked(dev); if (fd < 0) { E("%s: Could not get pipe channel: %s", __FUNCTION__, strerror(-fd)); return fd; } // Accumulate pending events into |events| and |new_sensors| mask // until a 'sync' or 'wake' command is received. This also simplifies the // code a bit. uint32_t new_sensors = 0U; sensors_event_t* events = dev->sensors; int64_t event_time = -1; int ret = 0; for (;;) { /* Release the lock since we're going to block on recv() */ pthread_mutex_unlock(&dev->lock); /* read the next event */ char buff[256]; int len = qemud_channel_recv(fd, buff, sizeof(buff) - 1U); /* re-acquire the lock to modify the device state. */ pthread_mutex_lock(&dev->lock); if (len < 0) { ret = -errno; E("%s(fd=%d): Could not receive event data len=%d, errno=%d: %s", __FUNCTION__, fd, len, errno, strerror(errno)); break; } buff[len] = 0; D("%s(fd=%d): received [%s]", __FUNCTION__, fd, buff); /* "wake" is sent from the emulator to exit this loop. */ /* TODO(digit): Is it still needed? */ if (!strcmp((const char*)buff, "wake")) { ret = 0x7FFFFFFF; break; } float params[3]; /* "acceleration:::" corresponds to an acceleration event */ if (sscanf(buff, "acceleration:%g:%g:%g", params+0, params+1, params+2) == 3) { new_sensors |= SENSORS_ACCELERATION; events[ID_ACCELERATION].acceleration.x = params[0]; events[ID_ACCELERATION].acceleration.y = params[1]; events[ID_ACCELERATION].acceleration.z = params[2]; events[ID_ACCELERATION].type = SENSOR_TYPE_ACCELEROMETER; continue; } /* "orientation:::" is sent when orientation * changes */ if (sscanf(buff, "orientation:%g:%g:%g", params+0, params+1, params+2) == 3) { new_sensors |= SENSORS_ORIENTATION; events[ID_ORIENTATION].orientation.azimuth = params[0]; events[ID_ORIENTATION].orientation.pitch = params[1]; events[ID_ORIENTATION].orientation.roll = params[2]; events[ID_ORIENTATION].orientation.status = SENSOR_STATUS_ACCURACY_HIGH; events[ID_ACCELERATION].type = SENSOR_TYPE_ORIENTATION; continue; } /* "magnetic:::" is sent for the params of the magnetic * field */ if (sscanf(buff, "magnetic:%g:%g:%g", params+0, params+1, params+2) == 3) { new_sensors |= SENSORS_MAGNETIC_FIELD; events[ID_MAGNETIC_FIELD].magnetic.x = params[0]; events[ID_MAGNETIC_FIELD].magnetic.y = params[1]; events[ID_MAGNETIC_FIELD].magnetic.z = params[2]; events[ID_MAGNETIC_FIELD].magnetic.status = SENSOR_STATUS_ACCURACY_HIGH; events[ID_ACCELERATION].type = SENSOR_TYPE_MAGNETIC_FIELD; continue; } /* "temperature:" */ if (sscanf(buff, "temperature:%g", params+0) == 1) { new_sensors |= SENSORS_TEMPERATURE; events[ID_TEMPERATURE].temperature = params[0]; events[ID_ACCELERATION].type = SENSOR_TYPE_TEMPERATURE; continue; } /* "proximity:" */ if (sscanf(buff, "proximity:%g", params+0) == 1) { new_sensors |= SENSORS_PROXIMITY; events[ID_PROXIMITY].distance = params[0]; events[ID_ACCELERATION].type = SENSOR_TYPE_PROXIMITY; continue; } /* "sync: