Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fc32881f authored by Mathias Agopian's avatar Mathias Agopian
Browse files

new SensorService

remove old sensor service and implement SensorManager
on top of the new (native) SensorManger API.

Change-Id: Iddb77d498755da3e11646473a44d651f12f40281
parent ec44ed07
Loading
Loading
Loading
Loading
+28 −0
Original line number Diff line number Diff line
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \
    SensorService.cpp

LOCAL_CFLAGS:= -DLOG_TAG=\"SensorService\"

# need "-lrt" on Linux simulator to pick up clock_gettime
ifeq ($(TARGET_SIMULATOR),true)
	ifeq ($(HOST_OS),linux)
		LOCAL_LDLIBS += -lrt -lpthread
	endif
endif

LOCAL_SHARED_LIBRARIES := \
	libcutils \
	libhardware \
	libutils \
	libbinder \
	libui \
	libgui

LOCAL_PRELINK_MODULE := false

LOCAL_MODULE:= libsensorservice

include $(BUILD_SHARED_LIBRARY)
+359 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2010 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.
 */

#include <stdint.h>
#include <sys/types.h>

#include <utils/SortedVector.h>
#include <utils/KeyedVector.h>
#include <utils/threads.h>
#include <utils/Atomic.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>

#include <binder/BinderService.h>

#include <gui/ISensorServer.h>
#include <gui/ISensorEventConnection.h>

#include <hardware/sensors.h>

#include "SensorService.h"

namespace android {
// ---------------------------------------------------------------------------

/*
 * TODO:
 * - handle per-connection event rate
 * - filter events per connection
 * - make sure to keep the last value of each event type so we can quickly
 *   send something to application when they enable a sensor that is already
 *   active (the issue here is that it can take time before a value is
 *   produced by the h/w if the rate is low or if it's a one-shot sensor).
 */

SensorService::SensorService()
    : Thread(false),
      mDump("android.permission.DUMP")
{
}

void SensorService::onFirstRef()
{
    status_t err = hw_get_module(SENSORS_HARDWARE_MODULE_ID,
            (hw_module_t const**)&mSensorModule);

    LOGE_IF(err, "couldn't load %s module (%s)",
            SENSORS_HARDWARE_MODULE_ID, strerror(-err));

    err = sensors_open(&mSensorModule->common, &mSensorDevice);

    LOGE_IF(err, "couldn't open device for module %s (%s)",
            SENSORS_HARDWARE_MODULE_ID, strerror(-err));

    LOGD("nuSensorService starting...");

    struct sensor_t const* list;
    int count = mSensorModule->get_sensors_list(mSensorModule, &list);
    for (int i=0 ; i<count ; i++) {
        Sensor sensor(list + i);
        LOGI("%s", sensor.getName().string());
        mSensorList.add(sensor);
        mSensorDevice->activate(mSensorDevice, sensor.getHandle(), 0);
    }

    run("SensorService", PRIORITY_URGENT_DISPLAY);
}

SensorService::~SensorService()
{
}

status_t SensorService::dump(int fd, const Vector<String16>& args)
{
    const size_t SIZE = 1024;
    char buffer[SIZE];
    String8 result;
    if (!mDump.checkCalling()) {
        snprintf(buffer, SIZE, "Permission Denial: "
                "can't dump SurfaceFlinger from pid=%d, uid=%d\n",
                IPCThreadState::self()->getCallingPid(),
                IPCThreadState::self()->getCallingUid());
        result.append(buffer);
    } else {
        Mutex::Autolock _l(mLock);
        snprintf(buffer, SIZE, "%d connections / %d active\n",
                mConnections.size(), mActiveConnections.size());
        result.append(buffer);
        snprintf(buffer, SIZE, "Active sensors:\n");
        result.append(buffer);
        for (size_t i=0 ; i<mActiveSensors.size() ; i++) {
            snprintf(buffer, SIZE, "handle=%d, connections=%d\n",
                    mActiveSensors.keyAt(i),
                    mActiveSensors.valueAt(i)->getNumConnections());
            result.append(buffer);
        }
    }
    write(fd, result.string(), result.size());
    return NO_ERROR;
}

bool SensorService::threadLoop()
{
    LOGD("nuSensorService thread starting...");

    sensors_event_t buffer[16];
    struct sensors_poll_device_t* device = mSensorDevice;
    ssize_t count;

    do {
        count = device->poll(device, buffer, sizeof(buffer)/sizeof(*buffer));
        if (count<0) {
            LOGE("sensor poll failed (%s)", strerror(-count));
            break;
        }

        const SortedVector< wp<SensorEventConnection> > activeConnections(
                getActiveConnections());

        size_t numConnections = activeConnections.size();
        if (numConnections) {
            for (size_t i=0 ; i<numConnections ; i++) {
                sp<SensorEventConnection> connection(activeConnections[i].promote());
                if (connection != 0) {
                    connection->sendEvents(buffer, count);
                }
            }
        }

    } while (count >= 0 || Thread::exitPending());

    LOGW("Exiting SensorService::threadLoop!");
    return false;
}

SortedVector< wp<SensorService::SensorEventConnection> >
SensorService::getActiveConnections() const
{
    Mutex::Autolock _l(mLock);
    return mActiveConnections;
}

Vector<Sensor> SensorService::getSensorList()
{
    return mSensorList;
}

sp<ISensorEventConnection> SensorService::createSensorEventConnection()
{
    sp<SensorEventConnection> result(new SensorEventConnection(this));
    Mutex::Autolock _l(mLock);
    mConnections.add(result);
    return result;
}

void SensorService::cleanupConnection(const wp<SensorEventConnection>& connection)
{
    Mutex::Autolock _l(mLock);
    ssize_t index = mConnections.indexOf(connection);
    if (index >= 0) {

        size_t size = mActiveSensors.size();
        for (size_t i=0 ; i<size ; ) {
            SensorRecord* rec = mActiveSensors.valueAt(i);
            if (rec && rec->removeConnection(connection)) {
                mSensorDevice->activate(mSensorDevice, mActiveSensors.keyAt(i), 0);
                mActiveSensors.removeItemsAt(i, 1);
                delete rec;
                size--;
            } else {
                i++;
            }
        }

        mActiveConnections.remove(connection);
        mConnections.removeItemsAt(index, 1);
    }
}

status_t SensorService::enable(const sp<SensorEventConnection>& connection,
        int handle)
{
    status_t err = NO_ERROR;
    Mutex::Autolock _l(mLock);
    SensorRecord* rec = mActiveSensors.valueFor(handle);
    if (rec == 0) {
        rec = new SensorRecord(connection);
        mActiveSensors.add(handle, rec);
        err = mSensorDevice->activate(mSensorDevice, handle, 1);
        LOGE_IF(err, "Error activating sensor %d (%s)", handle, strerror(-err));
    } else {
        err = rec->addConnection(connection);
    }
    if (err == NO_ERROR) {
        // connection now active
        connection->addSensor(handle);
        if (mActiveConnections.indexOf(connection) < 0) {
            mActiveConnections.add(connection);
        }
    }
    return err;
}

status_t SensorService::disable(const sp<SensorEventConnection>& connection,
        int handle)
{
    status_t err = NO_ERROR;
    Mutex::Autolock _l(mLock);
    SensorRecord* rec = mActiveSensors.valueFor(handle);
    LOGW("sensor (handle=%d) is not enabled", handle);
    if (rec) {
        // see if this connection becomes inactive
        connection->removeSensor(handle);
        if (connection->hasAnySensor() == false) {
            mActiveConnections.remove(connection);
        }
        // see if this sensor becomes inactive
        if (rec->removeConnection(connection)) {
            mActiveSensors.removeItem(handle);
            delete rec;
            err = mSensorDevice->activate(mSensorDevice, handle, 0);
        }
    }
    return err;
}

status_t SensorService::setRate(const sp<SensorEventConnection>& connection,
        int handle, nsecs_t ns)
{
    status_t err = NO_ERROR;
    Mutex::Autolock _l(mLock);

    err = mSensorDevice->setDelay(mSensorDevice, handle, ns);

    // TODO: handle rate per connection
    return err;
}

// ---------------------------------------------------------------------------

SensorService::SensorRecord::SensorRecord(
        const sp<SensorEventConnection>& connection)
{
    mConnections.add(connection);
}

status_t SensorService::SensorRecord::addConnection(
        const sp<SensorEventConnection>& connection)
{
    if (mConnections.indexOf(connection) < 0) {
        mConnections.add(connection);
    }
    return NO_ERROR;
}

bool SensorService::SensorRecord::removeConnection(
        const wp<SensorEventConnection>& connection)
{
    ssize_t index = mConnections.indexOf(connection);
    if (index >= 0) {
        mConnections.removeItemsAt(index, 1);
    }
    return mConnections.size() ? false : true;
}

// ---------------------------------------------------------------------------

SensorService::SensorEventConnection::SensorEventConnection(
        const sp<SensorService>& service)
    : mService(service), mChannel(new SensorChannel())
{
}

SensorService::SensorEventConnection::~SensorEventConnection()
{
    mService->cleanupConnection(this);
}

void SensorService::SensorEventConnection::onFirstRef()
{
}

void SensorService::SensorEventConnection::addSensor(int32_t handle) {
    if (mSensorList.indexOf(handle) <= 0) {
        mSensorList.add(handle);
    }
}

void SensorService::SensorEventConnection::removeSensor(int32_t handle) {
    mSensorList.remove(handle);
}

bool SensorService::SensorEventConnection::hasSensor(int32_t handle) const {
    return mSensorList.indexOf(handle) >= 0;
}

bool SensorService::SensorEventConnection::hasAnySensor() const {
    return mSensorList.size() ? true : false;
}

status_t SensorService::SensorEventConnection::sendEvents(
        sensors_event_t const* buffer, size_t count)
{
    // TODO: we should only send the events for the sensors this connection
    // is registered for.

    ssize_t size = mChannel->write(buffer, count*sizeof(sensors_event_t));
    if (size == -EAGAIN) {
        // the destination doesn't accept events anymore, it's probably
        // full. For now, we just drop the events on the floor.
        LOGW("dropping %d events on the floor", count);
        return size;
    }

    LOGE_IF(size<0, "dropping %d events on the floor (%s)",
            count, strerror(-size));

    return size < 0 ? size : NO_ERROR;
}

sp<SensorChannel> SensorService::SensorEventConnection::getSensorChannel() const
{
    return mChannel;
}

status_t SensorService::SensorEventConnection::enableDisable(
        int handle, bool enabled)
{
    status_t err;
    if (enabled) {
        err = mService->enable(this, handle);
    } else {
        err = mService->disable(this, handle);
    }
    return err;
}

status_t SensorService::SensorEventConnection::setEventRate(
        int handle, nsecs_t ns)
{
    return mService->setRate(this, handle, ns);
}

// ---------------------------------------------------------------------------
}; // namespace android
+119 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2010 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.
 */

#ifndef ANDROID_SENSOR_SERVICE_H
#define ANDROID_SENSOR_SERVICE_H

#include <stdint.h>
#include <sys/types.h>

#include <utils/Vector.h>
#include <utils/SortedVector.h>
#include <utils/KeyedVector.h>
#include <utils/threads.h>
#include <utils/RefBase.h>

#include <binder/BinderService.h>
#include <binder/Permission.h>

#include <gui/Sensor.h>
#include <gui/SensorChannel.h>
#include <gui/ISensorServer.h>
#include <gui/ISensorEventConnection.h>

// ---------------------------------------------------------------------------

struct sensors_poll_device_t;
struct sensors_module_t;

namespace android {
// ---------------------------------------------------------------------------

class SensorService :
        public BinderService<SensorService>,
        public BnSensorServer,
        protected Thread
{
   friend class BinderService<SensorService>;

            SensorService();
    virtual ~SensorService();

    virtual void onFirstRef();

    // Thread interface
    virtual bool threadLoop();

    // ISensorServer interface
    virtual Vector<Sensor> getSensorList();
    virtual sp<ISensorEventConnection> createSensorEventConnection();
    virtual status_t dump(int fd, const Vector<String16>& args);


    class SensorEventConnection : public BnSensorEventConnection {
        virtual sp<SensorChannel> getSensorChannel() const;
        virtual status_t enableDisable(int handle, bool enabled);
        virtual status_t setEventRate(int handle, nsecs_t ns);
        sp<SensorService> const mService;
        sp<SensorChannel> const mChannel;
        SortedVector<int32_t> mSensorList;
    public:
        SensorEventConnection(const sp<SensorService>& service);
        virtual ~SensorEventConnection();
        virtual void onFirstRef();
        status_t sendEvents(sensors_event_t const* buffer, size_t count);
        bool hasSensor(int32_t handle) const;
        bool hasAnySensor() const;
        void addSensor(int32_t handle);
        void removeSensor(int32_t handle);
    };

    class SensorRecord {
        SortedVector< wp<SensorEventConnection> > mConnections;
    public:
        SensorRecord(const sp<SensorEventConnection>& connection);
        status_t addConnection(const sp<SensorEventConnection>& connection);
        bool removeConnection(const wp<SensorEventConnection>& connection);
        size_t getNumConnections() const { return mConnections.size(); }
    };

    SortedVector< wp<SensorEventConnection> > getActiveConnections() const;

    // constants
    Vector<Sensor> mSensorList;
    struct sensors_poll_device_t* mSensorDevice;
    struct sensors_module_t* mSensorModule;
    Permission mDump;

    // protected by mLock
    mutable Mutex mLock;
    SortedVector< wp<SensorEventConnection> > mConnections;
    DefaultKeyedVector<int, SensorRecord*> mActiveSensors;
    SortedVector< wp<SensorEventConnection> > mActiveConnections;

public:
    static char const* getServiceName() { return "sensorservice"; }

    void cleanupConnection(const wp<SensorEventConnection>& connection);
    status_t enable(const sp<SensorEventConnection>& connection, int handle);
    status_t disable(const sp<SensorEventConnection>& connection, int handle);
    status_t setRate(const sp<SensorEventConnection>& connection, int handle, nsecs_t ns);
};

// ---------------------------------------------------------------------------
}; // namespace android

#endif // ANDROID_SENSOR_SERVICE_H
+14 −0
Original line number Diff line number Diff line
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \
	sensorservicetest.cpp

LOCAL_SHARED_LIBRARIES := \
	libcutils libutils libui libgui

LOCAL_MODULE:= test-sensorservice

LOCAL_MODULE_TAGS := optional

include $(BUILD_EXECUTABLE)
+90 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2010 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.
 */

#include <android/sensor.h>
#include <gui/Sensor.h>
#include <gui/SensorManager.h>
#include <gui/SensorEventQueue.h>
#include <utils/PollLoop.h>

using namespace android;

bool receiver(int fd, int events, void* data)
{
    sp<SensorEventQueue> q((SensorEventQueue*)data);
    ssize_t n;
    ASensorEvent buffer[8];
    while ((n = q->read(buffer, 8)) > 0) {
        for (int i=0 ; i<n ; i++) {
            if (buffer[i].type == Sensor::TYPE_ACCELEROMETER) {
                printf("time=%lld, value=<%5.1f,%5.1f,%5.1f>\n",
                        buffer[i].timestamp,
                        buffer[i].acceleration.x,
                        buffer[i].acceleration.y,
                        buffer[i].acceleration.z);
            }
        }
    }
    if (n<0 && n != -EAGAIN) {
        printf("error reading events (%s)\n", strerror(-n));
    }
    return true;
}


int main(int argc, char** argv)
{
    SensorManager& mgr(SensorManager::getInstance());

    Sensor const* const* list;
    ssize_t count = mgr.getSensorList(&list);
    printf("numSensors=%d\n", count);

    sp<SensorEventQueue> q = mgr.createEventQueue();
    printf("queue=%p\n", q.get());

    Sensor const* accelerometer = mgr.getDefaultSensor(Sensor::TYPE_ACCELEROMETER);
    printf("accelerometer=%p (%s)\n",
            accelerometer, accelerometer->getName().string());
    q->enableSensor(accelerometer);

    q->setEventRate(accelerometer, ms2ns(10));

    sp<PollLoop> loop = new PollLoop(false);
    loop->setCallback(q->getFd(), POLLIN, receiver, q.get());

    do {
        //printf("about to poll...\n");
        int32_t ret = loop->pollOnce(-1, 0, 0);
        switch (ret) {
            case ALOOPER_POLL_CALLBACK:
                //("ALOOPER_POLL_CALLBACK\n");
                break;
            case ALOOPER_POLL_TIMEOUT:
                printf("ALOOPER_POLL_TIMEOUT\n");
                break;
            case ALOOPER_POLL_ERROR:
                printf("ALOOPER_POLL_TIMEOUT\n");
                break;
            default:
                printf("ugh? poll returned %d\n", ret);
                break;
        }
    } while (1);


    return 0;
}