Merge "improve glgen tool to support EGL1.4"
diff --git a/cmds/sensorservice/Android.mk b/cmds/sensorservice/Android.mk
new file mode 100644
index 0000000..0811be5
--- /dev/null
+++ b/cmds/sensorservice/Android.mk
@@ -0,0 +1,19 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ main_sensorservice.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libsensorservice \
+ libbinder \
+ libutils
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/../../services/sensorservice
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE:= sensorservice
+
+include $(BUILD_EXECUTABLE)
diff --git a/cmds/sensorservice/main_sensorservice.cpp b/cmds/sensorservice/main_sensorservice.cpp
new file mode 100644
index 0000000..8610627
--- /dev/null
+++ b/cmds/sensorservice/main_sensorservice.cpp
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2011 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 <binder/BinderService.h>
+#include <SensorService.h>
+
+using namespace android;
+
+int main(int argc, char** argv) {
+ SensorService::publishAndJoinThreadPool();
+ return 0;
+}
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
index 1ea22fd..0d36baa 100644
--- a/include/gui/BufferQueue.h
+++ b/include/gui/BufferQueue.h
@@ -137,7 +137,7 @@
virtual status_t queueBuffer(int buf,
const QueueBufferInput& input, QueueBufferOutput* output);
- virtual void cancelBuffer(int buf);
+ virtual void cancelBuffer(int buf, sp<Fence> fence);
// setSynchronousMode set whether dequeueBuffer is synchronous or
// asynchronous. In synchronous mode, dequeueBuffer blocks until
@@ -202,6 +202,9 @@
// mBuf is the slot index of this buffer
int mBuf;
+
+ // mFence is a fence that will signal when the buffer is idle.
+ sp<Fence> mFence;
};
// The following public functions is the consumer facing interface
@@ -307,7 +310,7 @@
mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
mTimestamp(0),
mFrameNumber(0),
- mFence(EGL_NO_SYNC_KHR),
+ mEglFence(EGL_NO_SYNC_KHR),
mAcquireCalled(false),
mNeedsCleanupOnRelease(false) {
mCrop.makeInvalid();
@@ -380,15 +383,22 @@
// mFrameNumber is the number of the queued frame for this slot.
uint64_t mFrameNumber;
- // mFence is the EGL sync object that must signal before the buffer
+ // mEglFence is the EGL sync object that must signal before the buffer
// associated with this buffer slot may be dequeued. It is initialized
// to EGL_NO_SYNC_KHR when the buffer is created and (optionally, based
// on a compile-time option) set to a new sync object in updateTexImage.
- EGLSyncKHR mFence;
+ EGLSyncKHR mEglFence;
- // mReleaseFence is a fence which must signal before the contents of
- // the buffer associated with this buffer slot may be overwritten.
- sp<Fence> mReleaseFence;
+ // mFence is a fence which will signal when work initiated by the
+ // previous owner of the buffer is finished. When the buffer is FREE,
+ // the fence indicates when the consumer has finished reading
+ // from the buffer, or when the producer has finished writing if it
+ // called cancelBuffer after queueing some writes. When the buffer is
+ // QUEUED, it indicates when the producer has finished filling the
+ // buffer. When the buffer is DEQUEUED or ACQUIRED, the fence has been
+ // passed to the consumer or producer along with ownership of the
+ // buffer, and mFence is empty.
+ sp<Fence> mFence;
// Indicates whether this buffer has been seen by a consumer yet
bool mAcquireCalled;
diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h
index e4e8aa7..4f32146 100644
--- a/include/gui/ISurfaceComposer.h
+++ b/include/gui/ISurfaceComposer.h
@@ -145,6 +145,9 @@
/* triggers screen on and waits for it to complete */
virtual void unblank() = 0;
+
+ /* connects to an external display */
+ virtual void connectDisplay(const sp<ISurfaceTexture> display) = 0;
};
// ----------------------------------------------------------------------------
@@ -168,6 +171,7 @@
CREATE_DISPLAY_EVENT_CONNECTION,
BLANK,
UNBLANK,
+ CONNECT_DISPLAY,
};
virtual status_t onTransact( uint32_t code,
diff --git a/include/gui/ISurfaceTexture.h b/include/gui/ISurfaceTexture.h
index 019606a..8b4025d 100644
--- a/include/gui/ISurfaceTexture.h
+++ b/include/gui/ISurfaceTexture.h
@@ -89,24 +89,37 @@
// and height of the window and current transform applied to buffers,
// respectively.
- // QueueBufferInput must be a POD structure
- struct QueueBufferInput {
+ struct QueueBufferInput : public Flattenable {
+ inline QueueBufferInput(const Parcel& parcel);
inline QueueBufferInput(int64_t timestamp,
- const Rect& crop, int scalingMode, uint32_t transform)
+ const Rect& crop, int scalingMode, uint32_t transform,
+ sp<Fence> fence)
: timestamp(timestamp), crop(crop), scalingMode(scalingMode),
- transform(transform) { }
+ transform(transform), fence(fence) { }
inline void deflate(int64_t* outTimestamp, Rect* outCrop,
- int* outScalingMode, uint32_t* outTransform) const {
+ int* outScalingMode, uint32_t* outTransform,
+ sp<Fence>* outFence) const {
*outTimestamp = timestamp;
*outCrop = crop;
*outScalingMode = scalingMode;
*outTransform = transform;
+ *outFence = fence;
}
+
+ // Flattenable interface
+ virtual size_t getFlattenedSize() const;
+ virtual size_t getFdCount() const;
+ virtual status_t flatten(void* buffer, size_t size,
+ int fds[], size_t count) const;
+ virtual status_t unflatten(void const* buffer, size_t size,
+ int fds[], size_t count);
+
private:
int64_t timestamp;
Rect crop;
int scalingMode;
uint32_t transform;
+ sp<Fence> fence;
};
// QueueBufferOutput must be a POD structure
@@ -141,7 +154,7 @@
// cancelBuffer indicates that the client does not wish to fill in the
// buffer associated with slot and transfers ownership of the slot back to
// the server.
- virtual void cancelBuffer(int slot) = 0;
+ virtual void cancelBuffer(int slot, sp<Fence> fence) = 0;
// query retrieves some information for this surface
// 'what' tokens allowed are that of android_natives.h
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 622724e..66c390a 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -172,6 +172,10 @@
// getCurrentScalingMode returns the scaling mode of the current buffer.
uint32_t getCurrentScalingMode() const;
+ // getCurrentFence returns the fence indicating when the current buffer is
+ // ready to be read from.
+ sp<Fence> getCurrentFence() const;
+
// isSynchronousMode returns whether the SurfaceTexture is currently in
// synchronous mode.
bool isSynchronousMode() const;
@@ -303,6 +307,9 @@
// set to each time updateTexImage is called.
uint32_t mCurrentScalingMode;
+ // mCurrentFence is the fence received from BufferQueue in updateTexImage.
+ sp<Fence> mCurrentFence;
+
// mCurrentTransformMatrix is the transform matrix for the current texture.
// It gets computed by computeTransformMatrix each time updateTexImage is
// called.
diff --git a/include/ui/Fence.h b/include/ui/Fence.h
index 195f2e9..17cb018 100644
--- a/include/ui/Fence.h
+++ b/include/ui/Fence.h
@@ -51,6 +51,11 @@
// closed.
Fence(int fenceFd);
+ // Check whether the Fence has an open fence file descriptor. Most Fence
+ // methods treat an invalid file descriptor just like a valid fence that
+ // is already signalled, so using this is usually not necessary.
+ bool isValid() const { return mFenceFd != -1; }
+
// wait waits for up to timeout milliseconds for the fence to signal. If
// the fence signals then NO_ERROR is returned. If the timeout expires
// before the fence signals then -ETIME is returned. A timeout of
@@ -69,6 +74,11 @@
static sp<Fence> merge(const String8& name, const sp<Fence>& f1,
const sp<Fence>& f2);
+ // Return a duplicate of the fence file descriptor. The caller is
+ // responsible for closing the returned file descriptor. On error, -1 will
+ // be returned and errno will indicate the problem.
+ int dup() const;
+
// Flattenable interface
size_t getFlattenedSize() const;
size_t getFdCount() const;
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 40e43a1..23e3a4f 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -306,7 +306,7 @@
status_t returnFlags(OK);
EGLDisplay dpy = EGL_NO_DISPLAY;
- EGLSyncKHR fence = EGL_NO_SYNC_KHR;
+ EGLSyncKHR eglFence = EGL_NO_SYNC_KHR;
{ // Scope for the lock
Mutex::Autolock lock(mMutex);
@@ -480,22 +480,22 @@
mSlots[buf].mAcquireCalled = false;
mSlots[buf].mGraphicBuffer = graphicBuffer;
mSlots[buf].mRequestBufferCalled = false;
- mSlots[buf].mFence = EGL_NO_SYNC_KHR;
- mSlots[buf].mReleaseFence.clear();
+ mSlots[buf].mEglFence = EGL_NO_SYNC_KHR;
+ mSlots[buf].mFence.clear();
mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
}
dpy = mSlots[buf].mEglDisplay;
- fence = mSlots[buf].mFence;
- outFence = mSlots[buf].mReleaseFence;
- mSlots[buf].mFence = EGL_NO_SYNC_KHR;
- mSlots[buf].mReleaseFence.clear();
+ eglFence = mSlots[buf].mEglFence;
+ outFence = mSlots[buf].mFence;
+ mSlots[buf].mEglFence = EGL_NO_SYNC_KHR;
+ mSlots[buf].mFence.clear();
} // end lock scope
- if (fence != EGL_NO_SYNC_KHR) {
- EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000);
+ if (eglFence != EGL_NO_SYNC_KHR) {
+ EGLint result = eglClientWaitSyncKHR(dpy, eglFence, 0, 1000000000);
// If something goes wrong, log the error, but return the buffer without
// synchronizing access to it. It's too late at this point to abort the
// dequeue operation.
@@ -504,7 +504,7 @@
} else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
ST_LOGE("dequeueBuffer: timeout waiting for fence");
}
- eglDestroySyncKHR(dpy, fence);
+ eglDestroySyncKHR(dpy, eglFence);
}
ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", *outBuf,
@@ -554,8 +554,9 @@
uint32_t transform;
int scalingMode;
int64_t timestamp;
+ sp<Fence> fence;
- input.deflate(×tamp, &crop, &scalingMode, &transform);
+ input.deflate(×tamp, &crop, &scalingMode, &transform, &fence);
ST_LOGV("queueBuffer: slot=%d time=%#llx crop=[%d,%d,%d,%d] tr=%#x "
"scale=%s",
@@ -622,6 +623,7 @@
mSlots[buf].mTimestamp = timestamp;
mSlots[buf].mCrop = crop;
mSlots[buf].mTransform = transform;
+ mSlots[buf].mFence = fence;
switch (scalingMode) {
case NATIVE_WINDOW_SCALING_MODE_FREEZE:
@@ -655,7 +657,7 @@
return OK;
}
-void BufferQueue::cancelBuffer(int buf) {
+void BufferQueue::cancelBuffer(int buf, sp<Fence> fence) {
ATRACE_CALL();
ST_LOGV("cancelBuffer: slot=%d", buf);
Mutex::Autolock lock(mMutex);
@@ -676,6 +678,7 @@
}
mSlots[buf].mBufferState = BufferSlot::FREE;
mSlots[buf].mFrameNumber = 0;
+ mSlots[buf].mFence = fence;
mDequeueCondition.broadcast();
}
@@ -842,11 +845,11 @@
mSlots[i].mAcquireCalled = false;
// destroy fence as BufferQueue now takes ownership
- if (mSlots[i].mFence != EGL_NO_SYNC_KHR) {
- eglDestroySyncKHR(mSlots[i].mEglDisplay, mSlots[i].mFence);
- mSlots[i].mFence = EGL_NO_SYNC_KHR;
+ if (mSlots[i].mEglFence != EGL_NO_SYNC_KHR) {
+ eglDestroySyncKHR(mSlots[i].mEglDisplay, mSlots[i].mEglFence);
+ mSlots[i].mEglFence = EGL_NO_SYNC_KHR;
}
- mSlots[i].mReleaseFence.clear();
+ mSlots[i].mFence.clear();
}
void BufferQueue::freeAllBuffersLocked() {
@@ -882,11 +885,13 @@
buffer->mFrameNumber = mSlots[buf].mFrameNumber;
buffer->mTimestamp = mSlots[buf].mTimestamp;
buffer->mBuf = buf;
+ buffer->mFence = mSlots[buf].mFence;
mSlots[buf].mAcquireCalled = true;
mSlots[buf].mBufferState = BufferSlot::ACQUIRED;
mQueue.erase(front);
mDequeueCondition.broadcast();
+ mSlots[buf].mFence.clear();
ATRACE_INT(mConsumerName.string(), mQueue.size());
} else {
@@ -897,7 +902,7 @@
}
status_t BufferQueue::releaseBuffer(int buf, EGLDisplay display,
- EGLSyncKHR fence, const sp<Fence>& releaseFence) {
+ EGLSyncKHR eglFence, const sp<Fence>& fence) {
ATRACE_CALL();
ATRACE_BUFFER_INDEX(buf);
@@ -908,8 +913,8 @@
}
mSlots[buf].mEglDisplay = display;
+ mSlots[buf].mEglFence = eglFence;
mSlots[buf].mFence = fence;
- mSlots[buf].mReleaseFence = releaseFence;
// The buffer can now only be released if its in the acquired state
if (mSlots[buf].mBufferState == BufferSlot::ACQUIRED) {
diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp
index bf2539f..513828c 100644
--- a/libs/gui/CpuConsumer.cpp
+++ b/libs/gui/CpuConsumer.cpp
@@ -114,6 +114,15 @@
mBufferSlot[buf] = b.mGraphicBuffer;
}
+ if (b.mFence.get()) {
+ err = b.mFence->wait(Fence::TIMEOUT_NEVER);
+ if (err != OK) {
+ CC_LOGE("Failed to wait for fence of acquired buffer: %s (%d)",
+ strerror(-err), err);
+ return err;
+ }
+ }
+
err = mBufferSlot[buf]->lock(
GraphicBuffer::USAGE_SW_READ_OFTEN,
b.mCrop,
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 8177e4d..bc550bf 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -207,6 +207,13 @@
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
remote()->transact(BnSurfaceComposer::UNBLANK, data, &reply);
}
+
+ virtual void connectDisplay(const sp<ISurfaceTexture> display) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ data.writeStrongBinder(display->asBinder());
+ remote()->transact(BnSurfaceComposer::CONNECT_DISPLAY, data, &reply);
+ }
};
IMPLEMENT_META_INTERFACE(SurfaceComposer, "android.ui.ISurfaceComposer");
@@ -301,6 +308,12 @@
CHECK_INTERFACE(ISurfaceComposer, data, reply);
unblank();
} break;
+ case CONNECT_DISPLAY: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<ISurfaceTexture> surfaceTexture =
+ interface_cast<ISurfaceTexture>(data.readStrongBinder());
+ connectDisplay(surfaceTexture);
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/ISurfaceTexture.cpp b/libs/gui/ISurfaceTexture.cpp
index c8fef06..a0b1e74 100644
--- a/libs/gui/ISurfaceTexture.cpp
+++ b/libs/gui/ISurfaceTexture.cpp
@@ -109,7 +109,7 @@
Parcel data, reply;
data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
data.writeInt32(buf);
- memcpy(data.writeInplace(sizeof(input)), &input, sizeof(input));
+ data.write(input);
status_t result = remote()->transact(QUEUE_BUFFER, data, &reply);
if (result != NO_ERROR) {
return result;
@@ -119,10 +119,15 @@
return result;
}
- virtual void cancelBuffer(int buf) {
+ virtual void cancelBuffer(int buf, sp<Fence> fence) {
Parcel data, reply;
+ bool hasFence = fence.get() && fence->isValid();
data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
data.writeInt32(buf);
+ data.writeInt32(hasFence);
+ if (hasFence) {
+ data.write(*fence.get());
+ }
remote()->transact(CANCEL_BUFFER, data, &reply);
}
@@ -213,9 +218,10 @@
int buf;
sp<Fence> fence;
int result = dequeueBuffer(&buf, fence, w, h, format, usage);
+ bool hasFence = fence.get() && fence->isValid();
reply->writeInt32(buf);
- reply->writeInt32(fence.get() != NULL);
- if (fence.get() != NULL) {
+ reply->writeInt32(hasFence);
+ if (hasFence) {
reply->write(*fence.get());
}
reply->writeInt32(result);
@@ -224,20 +230,24 @@
case QUEUE_BUFFER: {
CHECK_INTERFACE(ISurfaceTexture, data, reply);
int buf = data.readInt32();
- QueueBufferInput const* const input =
- reinterpret_cast<QueueBufferInput const *>(
- data.readInplace(sizeof(QueueBufferInput)));
+ QueueBufferInput input(data);
QueueBufferOutput* const output =
reinterpret_cast<QueueBufferOutput *>(
reply->writeInplace(sizeof(QueueBufferOutput)));
- status_t result = queueBuffer(buf, *input, output);
+ status_t result = queueBuffer(buf, input, output);
reply->writeInt32(result);
return NO_ERROR;
} break;
case CANCEL_BUFFER: {
CHECK_INTERFACE(ISurfaceTexture, data, reply);
int buf = data.readInt32();
- cancelBuffer(buf);
+ sp<Fence> fence;
+ bool hasFence = data.readInt32();
+ if (hasFence) {
+ fence = new Fence();
+ data.read(*fence.get());
+ }
+ cancelBuffer(buf, fence);
return NO_ERROR;
} break;
case QUERY: {
@@ -279,4 +289,62 @@
// ----------------------------------------------------------------------------
+static bool isValid(const sp<Fence>& fence) {
+ return fence.get() && fence->isValid();
+}
+
+ISurfaceTexture::QueueBufferInput::QueueBufferInput(const Parcel& parcel) {
+ parcel.read(*this);
+}
+
+size_t ISurfaceTexture::QueueBufferInput::getFlattenedSize() const
+{
+ return sizeof(timestamp)
+ + sizeof(crop)
+ + sizeof(scalingMode)
+ + sizeof(transform)
+ + sizeof(bool)
+ + (isValid(fence) ? fence->getFlattenedSize() : 0);
+}
+
+size_t ISurfaceTexture::QueueBufferInput::getFdCount() const
+{
+ return isValid(fence) ? fence->getFdCount() : 0;
+}
+
+status_t ISurfaceTexture::QueueBufferInput::flatten(void* buffer, size_t size,
+ int fds[], size_t count) const
+{
+ status_t err = NO_ERROR;
+ bool haveFence = isValid(fence);
+ char* p = (char*)buffer;
+ memcpy(p, ×tamp, sizeof(timestamp)); p += sizeof(timestamp);
+ memcpy(p, &crop, sizeof(crop)); p += sizeof(crop);
+ memcpy(p, &scalingMode, sizeof(scalingMode)); p += sizeof(scalingMode);
+ memcpy(p, &transform, sizeof(transform)); p += sizeof(transform);
+ memcpy(p, &haveFence, sizeof(haveFence)); p += sizeof(haveFence);
+ if (haveFence) {
+ err = fence->flatten(p, size - (p - (char*)buffer), fds, count);
+ }
+ return err;
+}
+
+status_t ISurfaceTexture::QueueBufferInput::unflatten(void const* buffer,
+ size_t size, int fds[], size_t count)
+{
+ status_t err = NO_ERROR;
+ bool haveFence;
+ const char* p = (const char*)buffer;
+ memcpy(×tamp, p, sizeof(timestamp)); p += sizeof(timestamp);
+ memcpy(&crop, p, sizeof(crop)); p += sizeof(crop);
+ memcpy(&scalingMode, p, sizeof(scalingMode)); p += sizeof(scalingMode);
+ memcpy(&transform, p, sizeof(transform)); p += sizeof(transform);
+ memcpy(&haveFence, p, sizeof(haveFence)); p += sizeof(haveFence);
+ if (haveFence) {
+ fence = new Fence();
+ err = fence->unflatten(p, size - (p - (const char*)buffer), fds, count);
+ }
+ return err;
+}
+
}; // namespace android
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 8ef885b..ed6b73e 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -236,10 +236,7 @@
// not accept this buffer. this is used by SurfaceFlinger to
// reject buffers which have the wrong size
if (rejecter && rejecter->reject(mEGLSlots[buf].mGraphicBuffer, item)) {
- mBufferQueue->releaseBuffer(buf, dpy, mEGLSlots[buf].mFence,
- mEGLSlots[buf].mReleaseFence);
- mEGLSlots[buf].mFence = EGL_NO_SYNC_KHR;
- mEGLSlots[buf].mReleaseFence.clear();
+ mBufferQueue->releaseBuffer(buf, dpy, EGL_NO_SYNC_KHR, item.mFence);
glBindTexture(mTexTarget, mTexName);
return NO_ERROR;
}
@@ -286,10 +283,7 @@
if (err != NO_ERROR) {
// Release the buffer we just acquired. It's not safe to
// release the old buffer, so instead we just drop the new frame.
- mBufferQueue->releaseBuffer(buf, dpy, mEGLSlots[buf].mFence,
- mEGLSlots[buf].mReleaseFence);
- mEGLSlots[buf].mFence = EGL_NO_SYNC_KHR;
- mEGLSlots[buf].mReleaseFence.clear();
+ mBufferQueue->releaseBuffer(buf, dpy, EGL_NO_SYNC_KHR, item.mFence);
return err;
}
@@ -320,6 +314,7 @@
mCurrentTransform = item.mTransform;
mCurrentScalingMode = item.mScalingMode;
mCurrentTimestamp = item.mTimestamp;
+ mCurrentFence = item.mFence;
computeCurrentTransformMatrix();
} else {
if (err < 0) {
@@ -343,14 +338,14 @@
sp<Fence> mergedFence = Fence::merge(
String8("SurfaceTexture merged release"),
mEGLSlots[mCurrentTexture].mReleaseFence, fence);
- if (mergedFence.get()) {
+ if (!mergedFence.get()) {
ALOGE("failed to merge release fences");
// synchronization is broken, the best we can do is hope fences
// signal in order so the new fence will act like a union
mEGLSlots[mCurrentTexture].mReleaseFence = fence;
- } else {
- mEGLSlots[mCurrentTexture].mReleaseFence = mergedFence;
+ return;
}
+ mEGLSlots[mCurrentTexture].mReleaseFence = mergedFence;
}
}
@@ -731,6 +726,11 @@
return mCurrentScalingMode;
}
+sp<Fence> SurfaceTexture::getCurrentFence() const {
+ Mutex::Autolock lock(mMutex);
+ return mCurrentFence;
+}
+
bool SurfaceTexture::isSynchronousMode() const {
Mutex::Autolock lock(mMutex);
return mBufferQueue->isSynchronousMode();
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index 57bc604..718fe84 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -222,19 +222,23 @@
}
if (fence.get()) {
- status_t err = fence->wait(Fence::TIMEOUT_NEVER);
- if (err != OK) {
- ALOGE("dequeueBuffer: error waiting for fence: %d", err);
+ *fenceFd = fence->dup();
+ if (*fenceFd == -1) {
+ ALOGE("dequeueBuffer: error duping fence: %d", errno);
+ // dup() should never fail; something is badly wrong. Soldier on
+ // and hope for the best; the worst that should happen is some
+ // visible corruption that lasts until the next frame.
}
- fence.clear();
+ } else {
+ *fenceFd = -1;
}
*buffer = gbuf.get();
- *fenceFd = -1;
return OK;
}
-int SurfaceTextureClient::cancelBuffer(android_native_buffer_t* buffer, int fenceFd) {
+int SurfaceTextureClient::cancelBuffer(android_native_buffer_t* buffer,
+ int fenceFd) {
ATRACE_CALL();
ALOGV("SurfaceTextureClient::cancelBuffer");
Mutex::Autolock lock(mMutex);
@@ -242,13 +246,8 @@
if (i < 0) {
return i;
}
- sp<Fence> fence(new Fence(fenceFd));
- status_t err = fence->wait(Fence::TIMEOUT_NEVER);
- if (err != OK) {
- ALOGE("queueBuffer: Fence::wait returned an error: %d", err);
- return err;
- }
- mSurfaceTexture->cancelBuffer(i);
+ sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : NULL);
+ mSurfaceTexture->cancelBuffer(i, fence);
return OK;
}
@@ -288,21 +287,16 @@
return i;
}
- sp<Fence> fence(new Fence(fenceFd));
- status_t err = fence->wait(Fence::TIMEOUT_NEVER);
- if (err != OK) {
- ALOGE("queueBuffer: Fence::wait returned an error: %d", err);
- return err;
- }
// Make sure the crop rectangle is entirely inside the buffer.
Rect crop;
mCrop.intersect(Rect(buffer->width, buffer->height), &crop);
+ sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : NULL);
ISurfaceTexture::QueueBufferOutput output;
ISurfaceTexture::QueueBufferInput input(timestamp, crop, mScalingMode,
- mTransform);
- err = mSurfaceTexture->queueBuffer(i, input, &output);
+ mTransform, fence);
+ status_t err = mSurfaceTexture->queueBuffer(i, input, &output);
if (err != OK) {
ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err);
}
diff --git a/libs/ui/Fence.cpp b/libs/ui/Fence.cpp
index 5c17d10..932bcdd 100644
--- a/libs/ui/Fence.cpp
+++ b/libs/ui/Fence.cpp
@@ -62,6 +62,13 @@
return sp<Fence>(new Fence(result));
}
+int Fence::dup() const {
+ if (mFenceFd == -1) {
+ return -1;
+ }
+ return ::dup(mFenceFd);
+}
+
size_t Fence::getFlattenedSize() const {
return 0;
}
diff --git a/libs/utils/LinearTransform.cpp b/libs/utils/LinearTransform.cpp
index d752415..b7d28d4 100644
--- a/libs/utils/LinearTransform.cpp
+++ b/libs/utils/LinearTransform.cpp
@@ -114,6 +114,7 @@
int64_t basis1,
int32_t N,
uint32_t D,
+ bool invert_frac,
int64_t basis2,
int64_t* out) {
uint64_t scaled, res;
@@ -137,8 +138,8 @@
is_neg = !is_neg;
if (!scale_u64_to_u64(abs_val,
- ABS(N),
- D,
+ invert_frac ? D : ABS(N),
+ invert_frac ? ABS(N) : D,
&scaled,
is_neg))
return false; // overflow/undeflow
@@ -191,6 +192,7 @@
a_zero,
a_to_b_numer,
a_to_b_denom,
+ false,
b_zero,
b_out);
}
@@ -201,8 +203,9 @@
return linear_transform_s64_to_s64(b_in,
b_zero,
- a_to_b_denom,
a_to_b_numer,
+ a_to_b_denom,
+ true,
a_zero,
a_out);
}
diff --git a/services/sensorservice/Android.mk b/services/sensorservice/Android.mk
new file mode 100644
index 0000000..6a302c0
--- /dev/null
+++ b/services/sensorservice/Android.mk
@@ -0,0 +1,31 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ CorrectedGyroSensor.cpp \
+ Fusion.cpp \
+ GravitySensor.cpp \
+ LinearAccelerationSensor.cpp \
+ OrientationSensor.cpp \
+ RotationVectorSensor.cpp \
+ SensorDevice.cpp \
+ SensorFusion.cpp \
+ SensorInterface.cpp \
+ SensorService.cpp \
+
+
+LOCAL_CFLAGS:= -DLOG_TAG=\"SensorService\"
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libhardware \
+ libutils \
+ libbinder \
+ libui \
+ libgui
+
+
+
+LOCAL_MODULE:= libsensorservice
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/services/sensorservice/CorrectedGyroSensor.cpp b/services/sensorservice/CorrectedGyroSensor.cpp
new file mode 100644
index 0000000..1857443
--- /dev/null
+++ b/services/sensorservice/CorrectedGyroSensor.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2011 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 <math.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+
+#include <hardware/sensors.h>
+
+#include "CorrectedGyroSensor.h"
+#include "SensorDevice.h"
+#include "SensorFusion.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+CorrectedGyroSensor::CorrectedGyroSensor(sensor_t const* list, size_t count)
+ : mSensorDevice(SensorDevice::getInstance()),
+ mSensorFusion(SensorFusion::getInstance())
+{
+ for (size_t i=0 ; i<count ; i++) {
+ if (list[i].type == SENSOR_TYPE_GYROSCOPE) {
+ mGyro = Sensor(list + i);
+ break;
+ }
+ }
+}
+
+bool CorrectedGyroSensor::process(sensors_event_t* outEvent,
+ const sensors_event_t& event)
+{
+ if (event.type == SENSOR_TYPE_GYROSCOPE) {
+ const vec3_t bias(mSensorFusion.getGyroBias());
+ *outEvent = event;
+ outEvent->data[0] -= bias.x;
+ outEvent->data[1] -= bias.y;
+ outEvent->data[2] -= bias.z;
+ outEvent->sensor = '_cgy';
+ return true;
+ }
+ return false;
+}
+
+status_t CorrectedGyroSensor::activate(void* ident, bool enabled) {
+ mSensorDevice.activate(this, mGyro.getHandle(), enabled);
+ return mSensorFusion.activate(this, enabled);
+}
+
+status_t CorrectedGyroSensor::setDelay(void* ident, int handle, int64_t ns) {
+ mSensorDevice.setDelay(this, mGyro.getHandle(), ns);
+ return mSensorFusion.setDelay(this, ns);
+}
+
+Sensor CorrectedGyroSensor::getSensor() const {
+ sensor_t hwSensor;
+ hwSensor.name = "Corrected Gyroscope Sensor";
+ hwSensor.vendor = "Google Inc.";
+ hwSensor.version = 1;
+ hwSensor.handle = '_cgy';
+ hwSensor.type = SENSOR_TYPE_GYROSCOPE;
+ hwSensor.maxRange = mGyro.getMaxValue();
+ hwSensor.resolution = mGyro.getResolution();
+ hwSensor.power = mSensorFusion.getPowerUsage();
+ hwSensor.minDelay = mGyro.getMinDelay();
+ Sensor sensor(&hwSensor);
+ return sensor;
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
diff --git a/services/sensorservice/CorrectedGyroSensor.h b/services/sensorservice/CorrectedGyroSensor.h
new file mode 100644
index 0000000..3c49c08
--- /dev/null
+++ b/services/sensorservice/CorrectedGyroSensor.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2011 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_CORRECTED_GYRO_SENSOR_H
+#define ANDROID_CORRECTED_GYRO_SENSOR_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <gui/Sensor.h>
+
+#include "SensorInterface.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+// ---------------------------------------------------------------------------
+
+class SensorDevice;
+class SensorFusion;
+
+class CorrectedGyroSensor : public SensorInterface {
+ SensorDevice& mSensorDevice;
+ SensorFusion& mSensorFusion;
+ Sensor mGyro;
+
+public:
+ CorrectedGyroSensor(sensor_t const* list, size_t count);
+ virtual bool process(sensors_event_t* outEvent,
+ const sensors_event_t& event);
+ virtual status_t activate(void* ident, bool enabled);
+ virtual status_t setDelay(void* ident, int handle, int64_t ns);
+ virtual Sensor getSensor() const;
+ virtual bool isVirtual() const { return true; }
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_CORRECTED_GYRO_SENSOR_H
diff --git a/services/sensorservice/Fusion.cpp b/services/sensorservice/Fusion.cpp
new file mode 100644
index 0000000..93d6127
--- /dev/null
+++ b/services/sensorservice/Fusion.cpp
@@ -0,0 +1,497 @@
+/*
+ * Copyright (C) 2011 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 <stdio.h>
+
+#include <utils/Log.h>
+
+#include "Fusion.h"
+
+namespace android {
+
+// -----------------------------------------------------------------------
+
+/*
+ * gyroVAR gives the measured variance of the gyro's output per
+ * Hz (or variance at 1 Hz). This is an "intrinsic" parameter of the gyro,
+ * which is independent of the sampling frequency.
+ *
+ * The variance of gyro's output at a given sampling period can be
+ * calculated as:
+ * variance(T) = gyroVAR / T
+ *
+ * The variance of the INTEGRATED OUTPUT at a given sampling period can be
+ * calculated as:
+ * variance_integrate_output(T) = gyroVAR * T
+ *
+ */
+static const float gyroVAR = 1e-7; // (rad/s)^2 / Hz
+static const float biasVAR = 1e-8; // (rad/s)^2 / s (guessed)
+
+/*
+ * Standard deviations of accelerometer and magnetometer
+ */
+static const float accSTDEV = 0.05f; // m/s^2 (measured 0.08 / CDD 0.05)
+static const float magSTDEV = 0.5f; // uT (measured 0.7 / CDD 0.5)
+
+static const float SYMMETRY_TOLERANCE = 1e-10f;
+
+/*
+ * Accelerometer updates will not be performed near free fall to avoid
+ * ill-conditioning and div by zeros.
+ * Threshhold: 10% of g, in m/s^2
+ */
+static const float FREE_FALL_THRESHOLD = 0.981f;
+static const float FREE_FALL_THRESHOLD_SQ =
+ FREE_FALL_THRESHOLD*FREE_FALL_THRESHOLD;
+
+/*
+ * The geomagnetic-field should be between 30uT and 60uT.
+ * Fields strengths greater than this likely indicate a local magnetic
+ * disturbance which we do not want to update into the fused frame.
+ */
+static const float MAX_VALID_MAGNETIC_FIELD = 100; // uT
+static const float MAX_VALID_MAGNETIC_FIELD_SQ =
+ MAX_VALID_MAGNETIC_FIELD*MAX_VALID_MAGNETIC_FIELD;
+
+/*
+ * Values of the field smaller than this should be ignored in fusion to avoid
+ * ill-conditioning. This state can happen with anomalous local magnetic
+ * disturbances canceling the Earth field.
+ */
+static const float MIN_VALID_MAGNETIC_FIELD = 10; // uT
+static const float MIN_VALID_MAGNETIC_FIELD_SQ =
+ MIN_VALID_MAGNETIC_FIELD*MIN_VALID_MAGNETIC_FIELD;
+
+/*
+ * If the cross product of two vectors has magnitude squared less than this,
+ * we reject it as invalid due to alignment of the vectors.
+ * This threshold is used to check for the case where the magnetic field sample
+ * is parallel to the gravity field, which can happen in certain places due
+ * to magnetic field disturbances.
+ */
+static const float MIN_VALID_CROSS_PRODUCT_MAG = 1.0e-3;
+static const float MIN_VALID_CROSS_PRODUCT_MAG_SQ =
+ MIN_VALID_CROSS_PRODUCT_MAG*MIN_VALID_CROSS_PRODUCT_MAG;
+
+// -----------------------------------------------------------------------
+
+template <typename TYPE, size_t C, size_t R>
+static mat<TYPE, R, R> scaleCovariance(
+ const mat<TYPE, C, R>& A,
+ const mat<TYPE, C, C>& P) {
+ // A*P*transpose(A);
+ mat<TYPE, R, R> APAt;
+ for (size_t r=0 ; r<R ; r++) {
+ for (size_t j=r ; j<R ; j++) {
+ double apat(0);
+ for (size_t c=0 ; c<C ; c++) {
+ double v(A[c][r]*P[c][c]*0.5);
+ for (size_t k=c+1 ; k<C ; k++)
+ v += A[k][r] * P[c][k];
+ apat += 2 * v * A[c][j];
+ }
+ APAt[j][r] = apat;
+ APAt[r][j] = apat;
+ }
+ }
+ return APAt;
+}
+
+template <typename TYPE, typename OTHER_TYPE>
+static mat<TYPE, 3, 3> crossMatrix(const vec<TYPE, 3>& p, OTHER_TYPE diag) {
+ mat<TYPE, 3, 3> r;
+ r[0][0] = diag;
+ r[1][1] = diag;
+ r[2][2] = diag;
+ r[0][1] = p.z;
+ r[1][0] =-p.z;
+ r[0][2] =-p.y;
+ r[2][0] = p.y;
+ r[1][2] = p.x;
+ r[2][1] =-p.x;
+ return r;
+}
+
+
+template<typename TYPE, size_t SIZE>
+class Covariance {
+ mat<TYPE, SIZE, SIZE> mSumXX;
+ vec<TYPE, SIZE> mSumX;
+ size_t mN;
+public:
+ Covariance() : mSumXX(0.0f), mSumX(0.0f), mN(0) { }
+ void update(const vec<TYPE, SIZE>& x) {
+ mSumXX += x*transpose(x);
+ mSumX += x;
+ mN++;
+ }
+ mat<TYPE, SIZE, SIZE> operator()() const {
+ const float N = 1.0f / mN;
+ return mSumXX*N - (mSumX*transpose(mSumX))*(N*N);
+ }
+ void reset() {
+ mN = 0;
+ mSumXX = 0;
+ mSumX = 0;
+ }
+ size_t getCount() const {
+ return mN;
+ }
+};
+
+// -----------------------------------------------------------------------
+
+Fusion::Fusion() {
+ Phi[0][1] = 0;
+ Phi[1][1] = 1;
+
+ Ba.x = 0;
+ Ba.y = 0;
+ Ba.z = 1;
+
+ Bm.x = 0;
+ Bm.y = 1;
+ Bm.z = 0;
+
+ x0 = 0;
+ x1 = 0;
+
+ init();
+}
+
+void Fusion::init() {
+ mInitState = 0;
+
+ mGyroRate = 0;
+
+ mCount[0] = 0;
+ mCount[1] = 0;
+ mCount[2] = 0;
+
+ mData = 0;
+}
+
+void Fusion::initFusion(const vec4_t& q, float dT)
+{
+ // initial estimate: E{ x(t0) }
+ x0 = q;
+ x1 = 0;
+
+ // process noise covariance matrix: G.Q.Gt, with
+ //
+ // G = | -1 0 | Q = | q00 q10 |
+ // | 0 1 | | q01 q11 |
+ //
+ // q00 = sv^2.dt + 1/3.su^2.dt^3
+ // q10 = q01 = 1/2.su^2.dt^2
+ // q11 = su^2.dt
+ //
+
+ const float dT2 = dT*dT;
+ const float dT3 = dT2*dT;
+
+ // variance of integrated output at 1/dT Hz (random drift)
+ const float q00 = gyroVAR * dT + 0.33333f * biasVAR * dT3;
+
+ // variance of drift rate ramp
+ const float q11 = biasVAR * dT;
+ const float q10 = 0.5f * biasVAR * dT2;
+ const float q01 = q10;
+
+ GQGt[0][0] = q00; // rad^2
+ GQGt[1][0] = -q10;
+ GQGt[0][1] = -q01;
+ GQGt[1][1] = q11; // (rad/s)^2
+
+ // initial covariance: Var{ x(t0) }
+ // TODO: initialize P correctly
+ P = 0;
+
+ // it is unclear how to set the initial covariance. It does affect
+ // how quickly the fusion converges. Experimentally it would take
+ // about 10 seconds at 200 Hz to estimate the gyro-drift with an
+ // initial covariance of 0, and about a second with an initial covariance
+ // of about 1 deg/s.
+ const float covv = 0;
+ const float covu = 0.5f * (float(M_PI) / 180);
+ mat33_t& Pv = P[0][0];
+ Pv[0][0] = covv;
+ Pv[1][1] = covv;
+ Pv[2][2] = covv;
+ mat33_t& Pu = P[1][1];
+ Pu[0][0] = covu;
+ Pu[1][1] = covu;
+ Pu[2][2] = covu;
+}
+
+bool Fusion::hasEstimate() const {
+ return (mInitState == (MAG|ACC|GYRO));
+}
+
+bool Fusion::checkInitComplete(int what, const vec3_t& d, float dT) {
+ if (hasEstimate())
+ return true;
+
+ if (what == ACC) {
+ mData[0] += d * (1/length(d));
+ mCount[0]++;
+ mInitState |= ACC;
+ } else if (what == MAG) {
+ mData[1] += d * (1/length(d));
+ mCount[1]++;
+ mInitState |= MAG;
+ } else if (what == GYRO) {
+ mGyroRate = dT;
+ mData[2] += d*dT;
+ mCount[2]++;
+ if (mCount[2] == 64) {
+ // 64 samples is good enough to estimate the gyro drift and
+ // doesn't take too much time.
+ mInitState |= GYRO;
+ }
+ }
+
+ if (mInitState == (MAG|ACC|GYRO)) {
+ // Average all the values we collected so far
+ mData[0] *= 1.0f/mCount[0];
+ mData[1] *= 1.0f/mCount[1];
+ mData[2] *= 1.0f/mCount[2];
+
+ // calculate the MRPs from the data collection, this gives us
+ // a rough estimate of our initial state
+ mat33_t R;
+ vec3_t up(mData[0]);
+ vec3_t east(cross_product(mData[1], up));
+ east *= 1/length(east);
+ vec3_t north(cross_product(up, east));
+ R << east << north << up;
+ const vec4_t q = matrixToQuat(R);
+
+ initFusion(q, mGyroRate);
+ }
+
+ return false;
+}
+
+void Fusion::handleGyro(const vec3_t& w, float dT) {
+ if (!checkInitComplete(GYRO, w, dT))
+ return;
+
+ predict(w, dT);
+}
+
+status_t Fusion::handleAcc(const vec3_t& a) {
+ // ignore acceleration data if we're close to free-fall
+ if (length_squared(a) < FREE_FALL_THRESHOLD_SQ) {
+ return BAD_VALUE;
+ }
+
+ if (!checkInitComplete(ACC, a))
+ return BAD_VALUE;
+
+ const float l = 1/length(a);
+ update(a*l, Ba, accSTDEV*l);
+ return NO_ERROR;
+}
+
+status_t Fusion::handleMag(const vec3_t& m) {
+ // the geomagnetic-field should be between 30uT and 60uT
+ // reject if too large to avoid spurious magnetic sources
+ const float magFieldSq = length_squared(m);
+ if (magFieldSq > MAX_VALID_MAGNETIC_FIELD_SQ) {
+ return BAD_VALUE;
+ } else if (magFieldSq < MIN_VALID_MAGNETIC_FIELD_SQ) {
+ // Also reject if too small since we will get ill-defined (zero mag)
+ // cross-products below
+ return BAD_VALUE;
+ }
+
+ if (!checkInitComplete(MAG, m))
+ return BAD_VALUE;
+
+ // Orthogonalize the magnetic field to the gravity field, mapping it into
+ // tangent to Earth.
+ const vec3_t up( getRotationMatrix() * Ba );
+ const vec3_t east( cross_product(m, up) );
+
+ // If the m and up vectors align, the cross product magnitude will
+ // approach 0.
+ // Reject this case as well to avoid div by zero problems and
+ // ill-conditioning below.
+ if (length_squared(east) < MIN_VALID_CROSS_PRODUCT_MAG_SQ) {
+ return BAD_VALUE;
+ }
+
+ // If we have created an orthogonal magnetic field successfully,
+ // then pass it in as the update.
+ vec3_t north( cross_product(up, east) );
+
+ const float l = 1 / length(north);
+ north *= l;
+
+ update(north, Bm, magSTDEV*l);
+ return NO_ERROR;
+}
+
+void Fusion::checkState() {
+ // P needs to stay positive semidefinite or the fusion diverges. When we
+ // detect divergence, we reset the fusion.
+ // TODO(braun): Instead, find the reason for the divergence and fix it.
+
+ if (!isPositiveSemidefinite(P[0][0], SYMMETRY_TOLERANCE) ||
+ !isPositiveSemidefinite(P[1][1], SYMMETRY_TOLERANCE)) {
+ ALOGW("Sensor fusion diverged; resetting state.");
+ P = 0;
+ }
+}
+
+vec4_t Fusion::getAttitude() const {
+ return x0;
+}
+
+vec3_t Fusion::getBias() const {
+ return x1;
+}
+
+mat33_t Fusion::getRotationMatrix() const {
+ return quatToMatrix(x0);
+}
+
+mat34_t Fusion::getF(const vec4_t& q) {
+ mat34_t F;
+
+ // This is used to compute the derivative of q
+ // F = | [q.xyz]x |
+ // | -q.xyz |
+
+ F[0].x = q.w; F[1].x =-q.z; F[2].x = q.y;
+ F[0].y = q.z; F[1].y = q.w; F[2].y =-q.x;
+ F[0].z =-q.y; F[1].z = q.x; F[2].z = q.w;
+ F[0].w =-q.x; F[1].w =-q.y; F[2].w =-q.z;
+ return F;
+}
+
+void Fusion::predict(const vec3_t& w, float dT) {
+ const vec4_t q = x0;
+ const vec3_t b = x1;
+ const vec3_t we = w - b;
+
+ // q(k+1) = O(we)*q(k)
+ // --------------------
+ //
+ // O(w) = | cos(0.5*||w||*dT)*I33 - [psi]x psi |
+ // | -psi' cos(0.5*||w||*dT) |
+ //
+ // psi = sin(0.5*||w||*dT)*w / ||w||
+ //
+ //
+ // P(k+1) = Phi(k)*P(k)*Phi(k)' + G*Q(k)*G'
+ // ----------------------------------------
+ //
+ // G = | -I33 0 |
+ // | 0 I33 |
+ //
+ // Phi = | Phi00 Phi10 |
+ // | 0 1 |
+ //
+ // Phi00 = I33
+ // - [w]x * sin(||w||*dt)/||w||
+ // + [w]x^2 * (1-cos(||w||*dT))/||w||^2
+ //
+ // Phi10 = [w]x * (1 - cos(||w||*dt))/||w||^2
+ // - [w]x^2 * (||w||*dT - sin(||w||*dt))/||w||^3
+ // - I33*dT
+
+ const mat33_t I33(1);
+ const mat33_t I33dT(dT);
+ const mat33_t wx(crossMatrix(we, 0));
+ const mat33_t wx2(wx*wx);
+ const float lwedT = length(we)*dT;
+ const float hlwedT = 0.5f*lwedT;
+ const float ilwe = 1/length(we);
+ const float k0 = (1-cosf(lwedT))*(ilwe*ilwe);
+ const float k1 = sinf(lwedT);
+ const float k2 = cosf(hlwedT);
+ const vec3_t psi(sinf(hlwedT)*ilwe*we);
+ const mat33_t O33(crossMatrix(-psi, k2));
+ mat44_t O;
+ O[0].xyz = O33[0]; O[0].w = -psi.x;
+ O[1].xyz = O33[1]; O[1].w = -psi.y;
+ O[2].xyz = O33[2]; O[2].w = -psi.z;
+ O[3].xyz = psi; O[3].w = k2;
+
+ Phi[0][0] = I33 - wx*(k1*ilwe) + wx2*k0;
+ Phi[1][0] = wx*k0 - I33dT - wx2*(ilwe*ilwe*ilwe)*(lwedT-k1);
+
+ x0 = O*q;
+ if (x0.w < 0)
+ x0 = -x0;
+
+ P = Phi*P*transpose(Phi) + GQGt;
+
+ checkState();
+}
+
+void Fusion::update(const vec3_t& z, const vec3_t& Bi, float sigma) {
+ vec4_t q(x0);
+ // measured vector in body space: h(p) = A(p)*Bi
+ const mat33_t A(quatToMatrix(q));
+ const vec3_t Bb(A*Bi);
+
+ // Sensitivity matrix H = dh(p)/dp
+ // H = [ L 0 ]
+ const mat33_t L(crossMatrix(Bb, 0));
+
+ // gain...
+ // K = P*Ht / [H*P*Ht + R]
+ vec<mat33_t, 2> K;
+ const mat33_t R(sigma*sigma);
+ const mat33_t S(scaleCovariance(L, P[0][0]) + R);
+ const mat33_t Si(invert(S));
+ const mat33_t LtSi(transpose(L)*Si);
+ K[0] = P[0][0] * LtSi;
+ K[1] = transpose(P[1][0])*LtSi;
+
+ // update...
+ // P = (I-K*H) * P
+ // P -= K*H*P
+ // | K0 | * | L 0 | * P = | K0*L 0 | * | P00 P10 | = | K0*L*P00 K0*L*P10 |
+ // | K1 | | K1*L 0 | | P01 P11 | | K1*L*P00 K1*L*P10 |
+ // Note: the Joseph form is numerically more stable and given by:
+ // P = (I-KH) * P * (I-KH)' + K*R*R'
+ const mat33_t K0L(K[0] * L);
+ const mat33_t K1L(K[1] * L);
+ P[0][0] -= K0L*P[0][0];
+ P[1][1] -= K1L*P[1][0];
+ P[1][0] -= K0L*P[1][0];
+ P[0][1] = transpose(P[1][0]);
+
+ const vec3_t e(z - Bb);
+ const vec3_t dq(K[0]*e);
+ const vec3_t db(K[1]*e);
+
+ q += getF(q)*(0.5f*dq);
+ x0 = normalize_quat(q);
+ x1 += db;
+
+ checkState();
+}
+
+// -----------------------------------------------------------------------
+
+}; // namespace android
+
diff --git a/services/sensorservice/Fusion.h b/services/sensorservice/Fusion.h
new file mode 100644
index 0000000..7062999
--- /dev/null
+++ b/services/sensorservice/Fusion.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2011 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_FUSION_H
+#define ANDROID_FUSION_H
+
+#include <utils/Errors.h>
+
+#include "quat.h"
+#include "mat.h"
+#include "vec.h"
+
+namespace android {
+
+typedef mat<float, 3, 4> mat34_t;
+
+class Fusion {
+ /*
+ * the state vector is made of two sub-vector containing respectively:
+ * - modified Rodrigues parameters
+ * - the estimated gyro bias
+ */
+ quat_t x0;
+ vec3_t x1;
+
+ /*
+ * the predicated covariance matrix is made of 4 3x3 sub-matrices and it is
+ * semi-definite positive.
+ *
+ * P = | P00 P10 | = | P00 P10 |
+ * | P01 P11 | | P10t P11 |
+ *
+ * Since P01 = transpose(P10), the code below never calculates or
+ * stores P01.
+ */
+ mat<mat33_t, 2, 2> P;
+
+ /*
+ * the process noise covariance matrix
+ */
+ mat<mat33_t, 2, 2> GQGt;
+
+public:
+ Fusion();
+ void init();
+ void handleGyro(const vec3_t& w, float dT);
+ status_t handleAcc(const vec3_t& a);
+ status_t handleMag(const vec3_t& m);
+ vec4_t getAttitude() const;
+ vec3_t getBias() const;
+ mat33_t getRotationMatrix() const;
+ bool hasEstimate() const;
+
+private:
+ mat<mat33_t, 2, 2> Phi;
+ vec3_t Ba, Bm;
+ uint32_t mInitState;
+ float mGyroRate;
+ vec<vec3_t, 3> mData;
+ size_t mCount[3];
+ enum { ACC=0x1, MAG=0x2, GYRO=0x4 };
+ bool checkInitComplete(int, const vec3_t& w, float d = 0);
+ void initFusion(const vec4_t& q0, float dT);
+ void checkState();
+ void predict(const vec3_t& w, float dT);
+ void update(const vec3_t& z, const vec3_t& Bi, float sigma);
+ static mat34_t getF(const vec4_t& p);
+};
+
+}; // namespace android
+
+#endif // ANDROID_FUSION_H
diff --git a/services/sensorservice/GravitySensor.cpp b/services/sensorservice/GravitySensor.cpp
new file mode 100644
index 0000000..c57715f
--- /dev/null
+++ b/services/sensorservice/GravitySensor.cpp
@@ -0,0 +1,94 @@
+/*
+ * 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 <math.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+
+#include <hardware/sensors.h>
+
+#include "GravitySensor.h"
+#include "SensorDevice.h"
+#include "SensorFusion.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+GravitySensor::GravitySensor(sensor_t const* list, size_t count)
+ : mSensorDevice(SensorDevice::getInstance()),
+ mSensorFusion(SensorFusion::getInstance())
+{
+ for (size_t i=0 ; i<count ; i++) {
+ if (list[i].type == SENSOR_TYPE_ACCELEROMETER) {
+ mAccelerometer = Sensor(list + i);
+ break;
+ }
+ }
+}
+
+bool GravitySensor::process(sensors_event_t* outEvent,
+ const sensors_event_t& event)
+{
+ const static double NS2S = 1.0 / 1000000000.0;
+ if (event.type == SENSOR_TYPE_ACCELEROMETER) {
+ vec3_t g;
+ if (!mSensorFusion.hasEstimate())
+ return false;
+ const mat33_t R(mSensorFusion.getRotationMatrix());
+ // FIXME: we need to estimate the length of gravity because
+ // the accelerometer may have a small scaling error. This
+ // translates to an offset in the linear-acceleration sensor.
+ g = R[2] * GRAVITY_EARTH;
+
+ *outEvent = event;
+ outEvent->data[0] = g.x;
+ outEvent->data[1] = g.y;
+ outEvent->data[2] = g.z;
+ outEvent->sensor = '_grv';
+ outEvent->type = SENSOR_TYPE_GRAVITY;
+ return true;
+ }
+ return false;
+}
+
+status_t GravitySensor::activate(void* ident, bool enabled) {
+ return mSensorFusion.activate(this, enabled);
+}
+
+status_t GravitySensor::setDelay(void* ident, int handle, int64_t ns) {
+ return mSensorFusion.setDelay(this, ns);
+}
+
+Sensor GravitySensor::getSensor() const {
+ sensor_t hwSensor;
+ hwSensor.name = "Gravity Sensor";
+ hwSensor.vendor = "Google Inc.";
+ hwSensor.version = 3;
+ hwSensor.handle = '_grv';
+ hwSensor.type = SENSOR_TYPE_GRAVITY;
+ hwSensor.maxRange = GRAVITY_EARTH * 2;
+ hwSensor.resolution = mAccelerometer.getResolution();
+ hwSensor.power = mSensorFusion.getPowerUsage();
+ hwSensor.minDelay = mSensorFusion.getMinDelay();
+ Sensor sensor(&hwSensor);
+ return sensor;
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
diff --git a/services/sensorservice/GravitySensor.h b/services/sensorservice/GravitySensor.h
new file mode 100644
index 0000000..ac177c4
--- /dev/null
+++ b/services/sensorservice/GravitySensor.h
@@ -0,0 +1,52 @@
+/*
+ * 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_GRAVITY_SENSOR_H
+#define ANDROID_GRAVITY_SENSOR_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <gui/Sensor.h>
+
+#include "SensorInterface.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+// ---------------------------------------------------------------------------
+
+class SensorDevice;
+class SensorFusion;
+
+class GravitySensor : public SensorInterface {
+ SensorDevice& mSensorDevice;
+ SensorFusion& mSensorFusion;
+ Sensor mAccelerometer;
+
+public:
+ GravitySensor(sensor_t const* list, size_t count);
+ virtual bool process(sensors_event_t* outEvent,
+ const sensors_event_t& event);
+ virtual status_t activate(void* ident, bool enabled);
+ virtual status_t setDelay(void* ident, int handle, int64_t ns);
+ virtual Sensor getSensor() const;
+ virtual bool isVirtual() const { return true; }
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_GRAVITY_SENSOR_H
diff --git a/services/sensorservice/LinearAccelerationSensor.cpp b/services/sensorservice/LinearAccelerationSensor.cpp
new file mode 100644
index 0000000..f0054f2
--- /dev/null
+++ b/services/sensorservice/LinearAccelerationSensor.cpp
@@ -0,0 +1,79 @@
+/*
+ * 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 <math.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+
+#include <hardware/sensors.h>
+
+#include "LinearAccelerationSensor.h"
+#include "SensorDevice.h"
+#include "SensorFusion.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+LinearAccelerationSensor::LinearAccelerationSensor(sensor_t const* list, size_t count)
+ : mSensorDevice(SensorDevice::getInstance()),
+ mGravitySensor(list, count)
+{
+}
+
+bool LinearAccelerationSensor::process(sensors_event_t* outEvent,
+ const sensors_event_t& event)
+{
+ bool result = mGravitySensor.process(outEvent, event);
+ if (result && event.type == SENSOR_TYPE_ACCELEROMETER) {
+ outEvent->data[0] = event.acceleration.x - outEvent->data[0];
+ outEvent->data[1] = event.acceleration.y - outEvent->data[1];
+ outEvent->data[2] = event.acceleration.z - outEvent->data[2];
+ outEvent->sensor = '_lin';
+ outEvent->type = SENSOR_TYPE_LINEAR_ACCELERATION;
+ return true;
+ }
+ return false;
+}
+
+status_t LinearAccelerationSensor::activate(void* ident, bool enabled) {
+ return mGravitySensor.activate(this, enabled);
+}
+
+status_t LinearAccelerationSensor::setDelay(void* ident, int handle, int64_t ns) {
+ return mGravitySensor.setDelay(this, handle, ns);
+}
+
+Sensor LinearAccelerationSensor::getSensor() const {
+ Sensor gsensor(mGravitySensor.getSensor());
+ sensor_t hwSensor;
+ hwSensor.name = "Linear Acceleration Sensor";
+ hwSensor.vendor = "Google Inc.";
+ hwSensor.version = gsensor.getVersion();
+ hwSensor.handle = '_lin';
+ hwSensor.type = SENSOR_TYPE_LINEAR_ACCELERATION;
+ hwSensor.maxRange = gsensor.getMaxValue();
+ hwSensor.resolution = gsensor.getResolution();
+ hwSensor.power = gsensor.getPowerUsage();
+ hwSensor.minDelay = gsensor.getMinDelay();
+ Sensor sensor(&hwSensor);
+ return sensor;
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
diff --git a/services/sensorservice/LinearAccelerationSensor.h b/services/sensorservice/LinearAccelerationSensor.h
new file mode 100644
index 0000000..5deb24f
--- /dev/null
+++ b/services/sensorservice/LinearAccelerationSensor.h
@@ -0,0 +1,52 @@
+/*
+ * 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_LINEAR_ACCELERATION_SENSOR_H
+#define ANDROID_LINEAR_ACCELERATION_SENSOR_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <gui/Sensor.h>
+
+#include "SensorInterface.h"
+#include "GravitySensor.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+// ---------------------------------------------------------------------------
+
+class SensorDevice;
+class SensorFusion;
+
+class LinearAccelerationSensor : public SensorInterface {
+ SensorDevice& mSensorDevice;
+ GravitySensor mGravitySensor;
+
+ virtual bool process(sensors_event_t* outEvent,
+ const sensors_event_t& event);
+public:
+ LinearAccelerationSensor(sensor_t const* list, size_t count);
+ virtual status_t activate(void* ident, bool enabled);
+ virtual status_t setDelay(void* ident, int handle, int64_t ns);
+ virtual Sensor getSensor() const;
+ virtual bool isVirtual() const { return true; }
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_LINEAR_ACCELERATION_SENSOR_H
diff --git a/services/sensorservice/OrientationSensor.cpp b/services/sensorservice/OrientationSensor.cpp
new file mode 100644
index 0000000..037adaa
--- /dev/null
+++ b/services/sensorservice/OrientationSensor.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2011 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 <math.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+
+#include <hardware/sensors.h>
+
+#include "OrientationSensor.h"
+#include "SensorDevice.h"
+#include "SensorFusion.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+OrientationSensor::OrientationSensor()
+ : mSensorDevice(SensorDevice::getInstance()),
+ mSensorFusion(SensorFusion::getInstance())
+{
+}
+
+bool OrientationSensor::process(sensors_event_t* outEvent,
+ const sensors_event_t& event)
+{
+ if (event.type == SENSOR_TYPE_ACCELEROMETER) {
+ if (mSensorFusion.hasEstimate()) {
+ vec3_t g;
+ const float rad2deg = 180 / M_PI;
+ const mat33_t R(mSensorFusion.getRotationMatrix());
+ g[0] = atan2f(-R[1][0], R[0][0]) * rad2deg;
+ g[1] = atan2f(-R[2][1], R[2][2]) * rad2deg;
+ g[2] = asinf ( R[2][0]) * rad2deg;
+ if (g[0] < 0)
+ g[0] += 360;
+
+ *outEvent = event;
+ outEvent->orientation.azimuth = g.x;
+ outEvent->orientation.pitch = g.y;
+ outEvent->orientation.roll = g.z;
+ outEvent->orientation.status = SENSOR_STATUS_ACCURACY_HIGH;
+ outEvent->sensor = '_ypr';
+ outEvent->type = SENSOR_TYPE_ORIENTATION;
+ return true;
+ }
+ }
+ return false;
+}
+
+status_t OrientationSensor::activate(void* ident, bool enabled) {
+ return mSensorFusion.activate(this, enabled);
+}
+
+status_t OrientationSensor::setDelay(void* ident, int handle, int64_t ns) {
+ return mSensorFusion.setDelay(this, ns);
+}
+
+Sensor OrientationSensor::getSensor() const {
+ sensor_t hwSensor;
+ hwSensor.name = "Orientation Sensor";
+ hwSensor.vendor = "Google Inc.";
+ hwSensor.version = 1;
+ hwSensor.handle = '_ypr';
+ hwSensor.type = SENSOR_TYPE_ORIENTATION;
+ hwSensor.maxRange = 360.0f;
+ hwSensor.resolution = 1.0f/256.0f; // FIXME: real value here
+ hwSensor.power = mSensorFusion.getPowerUsage();
+ hwSensor.minDelay = mSensorFusion.getMinDelay();
+ Sensor sensor(&hwSensor);
+ return sensor;
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
diff --git a/services/sensorservice/OrientationSensor.h b/services/sensorservice/OrientationSensor.h
new file mode 100644
index 0000000..855949d
--- /dev/null
+++ b/services/sensorservice/OrientationSensor.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2011 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_ORIENTATION_SENSOR_H
+#define ANDROID_ORIENTATION_SENSOR_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <gui/Sensor.h>
+
+#include "SensorInterface.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+// ---------------------------------------------------------------------------
+
+class SensorDevice;
+class SensorFusion;
+
+class OrientationSensor : public SensorInterface {
+ SensorDevice& mSensorDevice;
+ SensorFusion& mSensorFusion;
+
+public:
+ OrientationSensor();
+ virtual bool process(sensors_event_t* outEvent,
+ const sensors_event_t& event);
+ virtual status_t activate(void* ident, bool enabled);
+ virtual status_t setDelay(void* ident, int handle, int64_t ns);
+ virtual Sensor getSensor() const;
+ virtual bool isVirtual() const { return true; }
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_ORIENTATION_SENSOR_H
diff --git a/services/sensorservice/RotationVectorSensor.cpp b/services/sensorservice/RotationVectorSensor.cpp
new file mode 100644
index 0000000..5ea9568
--- /dev/null
+++ b/services/sensorservice/RotationVectorSensor.cpp
@@ -0,0 +1,129 @@
+/*
+ * 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 <math.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+
+#include <hardware/sensors.h>
+
+#include "RotationVectorSensor.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+RotationVectorSensor::RotationVectorSensor()
+ : mSensorDevice(SensorDevice::getInstance()),
+ mSensorFusion(SensorFusion::getInstance())
+{
+}
+
+bool RotationVectorSensor::process(sensors_event_t* outEvent,
+ const sensors_event_t& event)
+{
+ if (event.type == SENSOR_TYPE_ACCELEROMETER) {
+ if (mSensorFusion.hasEstimate()) {
+ const vec4_t q(mSensorFusion.getAttitude());
+ *outEvent = event;
+ outEvent->data[0] = q.x;
+ outEvent->data[1] = q.y;
+ outEvent->data[2] = q.z;
+ outEvent->data[3] = q.w;
+ outEvent->sensor = '_rov';
+ outEvent->type = SENSOR_TYPE_ROTATION_VECTOR;
+ return true;
+ }
+ }
+ return false;
+}
+
+status_t RotationVectorSensor::activate(void* ident, bool enabled) {
+ return mSensorFusion.activate(this, enabled);
+}
+
+status_t RotationVectorSensor::setDelay(void* ident, int handle, int64_t ns) {
+ return mSensorFusion.setDelay(this, ns);
+}
+
+Sensor RotationVectorSensor::getSensor() const {
+ sensor_t hwSensor;
+ hwSensor.name = "Rotation Vector Sensor";
+ hwSensor.vendor = "Google Inc.";
+ hwSensor.version = 3;
+ hwSensor.handle = '_rov';
+ hwSensor.type = SENSOR_TYPE_ROTATION_VECTOR;
+ hwSensor.maxRange = 1;
+ hwSensor.resolution = 1.0f / (1<<24);
+ hwSensor.power = mSensorFusion.getPowerUsage();
+ hwSensor.minDelay = mSensorFusion.getMinDelay();
+ Sensor sensor(&hwSensor);
+ return sensor;
+}
+
+// ---------------------------------------------------------------------------
+
+GyroDriftSensor::GyroDriftSensor()
+ : mSensorDevice(SensorDevice::getInstance()),
+ mSensorFusion(SensorFusion::getInstance())
+{
+}
+
+bool GyroDriftSensor::process(sensors_event_t* outEvent,
+ const sensors_event_t& event)
+{
+ if (event.type == SENSOR_TYPE_ACCELEROMETER) {
+ if (mSensorFusion.hasEstimate()) {
+ const vec3_t b(mSensorFusion.getGyroBias());
+ *outEvent = event;
+ outEvent->data[0] = b.x;
+ outEvent->data[1] = b.y;
+ outEvent->data[2] = b.z;
+ outEvent->sensor = '_gbs';
+ outEvent->type = SENSOR_TYPE_ACCELEROMETER;
+ return true;
+ }
+ }
+ return false;
+}
+
+status_t GyroDriftSensor::activate(void* ident, bool enabled) {
+ return mSensorFusion.activate(this, enabled);
+}
+
+status_t GyroDriftSensor::setDelay(void* ident, int handle, int64_t ns) {
+ return mSensorFusion.setDelay(this, ns);
+}
+
+Sensor GyroDriftSensor::getSensor() const {
+ sensor_t hwSensor;
+ hwSensor.name = "Gyroscope Bias (debug)";
+ hwSensor.vendor = "Google Inc.";
+ hwSensor.version = 1;
+ hwSensor.handle = '_gbs';
+ hwSensor.type = SENSOR_TYPE_ACCELEROMETER;
+ hwSensor.maxRange = 1;
+ hwSensor.resolution = 1.0f / (1<<24);
+ hwSensor.power = mSensorFusion.getPowerUsage();
+ hwSensor.minDelay = mSensorFusion.getMinDelay();
+ Sensor sensor(&hwSensor);
+ return sensor;
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
diff --git a/services/sensorservice/RotationVectorSensor.h b/services/sensorservice/RotationVectorSensor.h
new file mode 100644
index 0000000..bb97fe1
--- /dev/null
+++ b/services/sensorservice/RotationVectorSensor.h
@@ -0,0 +1,66 @@
+/*
+ * 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_ROTATION_VECTOR_SENSOR_H
+#define ANDROID_ROTATION_VECTOR_SENSOR_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <gui/Sensor.h>
+
+#include "SensorDevice.h"
+#include "SensorInterface.h"
+
+#include "Fusion.h"
+#include "SensorFusion.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+// ---------------------------------------------------------------------------
+
+class RotationVectorSensor : public SensorInterface {
+ SensorDevice& mSensorDevice;
+ SensorFusion& mSensorFusion;
+
+public:
+ RotationVectorSensor();
+ virtual bool process(sensors_event_t* outEvent,
+ const sensors_event_t& event);
+ virtual status_t activate(void* ident, bool enabled);
+ virtual status_t setDelay(void* ident, int handle, int64_t ns);
+ virtual Sensor getSensor() const;
+ virtual bool isVirtual() const { return true; }
+};
+
+class GyroDriftSensor : public SensorInterface {
+ SensorDevice& mSensorDevice;
+ SensorFusion& mSensorFusion;
+
+public:
+ GyroDriftSensor();
+ virtual bool process(sensors_event_t* outEvent,
+ const sensors_event_t& event);
+ virtual status_t activate(void* ident, bool enabled);
+ virtual status_t setDelay(void* ident, int handle, int64_t ns);
+ virtual Sensor getSensor() const;
+ virtual bool isVirtual() const { return true; }
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_ROTATION_VECTOR_SENSOR_H
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
new file mode 100644
index 0000000..2244a86
--- /dev/null
+++ b/services/sensorservice/SensorDevice.cpp
@@ -0,0 +1,282 @@
+/*
+ * 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 <math.h>
+#include <sys/types.h>
+
+#include <utils/Atomic.h>
+#include <utils/Errors.h>
+#include <utils/Singleton.h>
+
+#include <binder/BinderService.h>
+#include <binder/Parcel.h>
+#include <binder/IServiceManager.h>
+
+#include <hardware/sensors.h>
+
+#include "SensorDevice.h"
+#include "SensorService.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+class BatteryService : public Singleton<BatteryService> {
+ static const int TRANSACTION_noteStartSensor = IBinder::FIRST_CALL_TRANSACTION + 3;
+ static const int TRANSACTION_noteStopSensor = IBinder::FIRST_CALL_TRANSACTION + 4;
+ static const String16 DESCRIPTOR;
+
+ friend class Singleton<BatteryService>;
+ sp<IBinder> mBatteryStatService;
+
+ BatteryService() {
+ const sp<IServiceManager> sm(defaultServiceManager());
+ if (sm != NULL) {
+ const String16 name("batteryinfo");
+ mBatteryStatService = sm->getService(name);
+ }
+ }
+
+ status_t noteStartSensor(int uid, int handle) {
+ Parcel data, reply;
+ data.writeInterfaceToken(DESCRIPTOR);
+ data.writeInt32(uid);
+ data.writeInt32(handle);
+ status_t err = mBatteryStatService->transact(
+ TRANSACTION_noteStartSensor, data, &reply, 0);
+ err = reply.readExceptionCode();
+ return err;
+ }
+
+ status_t noteStopSensor(int uid, int handle) {
+ Parcel data, reply;
+ data.writeInterfaceToken(DESCRIPTOR);
+ data.writeInt32(uid);
+ data.writeInt32(handle);
+ status_t err = mBatteryStatService->transact(
+ TRANSACTION_noteStopSensor, data, &reply, 0);
+ err = reply.readExceptionCode();
+ return err;
+ }
+
+public:
+ void enableSensor(int handle) {
+ if (mBatteryStatService != 0) {
+ int uid = IPCThreadState::self()->getCallingUid();
+ int64_t identity = IPCThreadState::self()->clearCallingIdentity();
+ noteStartSensor(uid, handle);
+ IPCThreadState::self()->restoreCallingIdentity(identity);
+ }
+ }
+ void disableSensor(int handle) {
+ if (mBatteryStatService != 0) {
+ int uid = IPCThreadState::self()->getCallingUid();
+ int64_t identity = IPCThreadState::self()->clearCallingIdentity();
+ noteStopSensor(uid, handle);
+ IPCThreadState::self()->restoreCallingIdentity(identity);
+ }
+ }
+};
+
+const String16 BatteryService::DESCRIPTOR("com.android.internal.app.IBatteryStats");
+
+ANDROID_SINGLETON_STATIC_INSTANCE(BatteryService)
+
+// ---------------------------------------------------------------------------
+
+ANDROID_SINGLETON_STATIC_INSTANCE(SensorDevice)
+
+SensorDevice::SensorDevice()
+ : mSensorDevice(0),
+ mSensorModule(0)
+{
+ status_t err = hw_get_module(SENSORS_HARDWARE_MODULE_ID,
+ (hw_module_t const**)&mSensorModule);
+
+ ALOGE_IF(err, "couldn't load %s module (%s)",
+ SENSORS_HARDWARE_MODULE_ID, strerror(-err));
+
+ if (mSensorModule) {
+ err = sensors_open(&mSensorModule->common, &mSensorDevice);
+
+ ALOGE_IF(err, "couldn't open device for module %s (%s)",
+ SENSORS_HARDWARE_MODULE_ID, strerror(-err));
+
+ if (mSensorDevice) {
+ sensor_t const* list;
+ ssize_t count = mSensorModule->get_sensors_list(mSensorModule, &list);
+ mActivationCount.setCapacity(count);
+ Info model;
+ for (size_t i=0 ; i<size_t(count) ; i++) {
+ mActivationCount.add(list[i].handle, model);
+ mSensorDevice->activate(mSensorDevice, list[i].handle, 0);
+ }
+ }
+ }
+}
+
+void SensorDevice::dump(String8& result, char* buffer, size_t SIZE)
+{
+ if (!mSensorModule) return;
+ sensor_t const* list;
+ ssize_t count = mSensorModule->get_sensors_list(mSensorModule, &list);
+
+ snprintf(buffer, SIZE, "%d h/w sensors:\n", int(count));
+ result.append(buffer);
+
+ Mutex::Autolock _l(mLock);
+ for (size_t i=0 ; i<size_t(count) ; i++) {
+ const Info& info = mActivationCount.valueFor(list[i].handle);
+ snprintf(buffer, SIZE, "handle=0x%08x, active-count=%d, rates(ms)={ ",
+ list[i].handle,
+ info.rates.size());
+ result.append(buffer);
+ for (size_t j=0 ; j<info.rates.size() ; j++) {
+ snprintf(buffer, SIZE, "%4.1f%s",
+ info.rates.valueAt(j) / 1e6f,
+ j<info.rates.size()-1 ? ", " : "");
+ result.append(buffer);
+ }
+ snprintf(buffer, SIZE, " }, selected=%4.1f ms\n", info.delay / 1e6f);
+ result.append(buffer);
+ }
+}
+
+ssize_t SensorDevice::getSensorList(sensor_t const** list) {
+ if (!mSensorModule) return NO_INIT;
+ ssize_t count = mSensorModule->get_sensors_list(mSensorModule, list);
+ return count;
+}
+
+status_t SensorDevice::initCheck() const {
+ return mSensorDevice && mSensorModule ? NO_ERROR : NO_INIT;
+}
+
+ssize_t SensorDevice::poll(sensors_event_t* buffer, size_t count) {
+ if (!mSensorDevice) return NO_INIT;
+ ssize_t c;
+ do {
+ c = mSensorDevice->poll(mSensorDevice, buffer, count);
+ } while (c == -EINTR);
+ return c;
+}
+
+status_t SensorDevice::activate(void* ident, int handle, int enabled)
+{
+ if (!mSensorDevice) return NO_INIT;
+ status_t err(NO_ERROR);
+ bool actuateHardware = false;
+
+ Info& info( mActivationCount.editValueFor(handle) );
+
+
+ ALOGD_IF(DEBUG_CONNECTIONS,
+ "SensorDevice::activate: ident=%p, handle=0x%08x, enabled=%d, count=%d",
+ ident, handle, enabled, info.rates.size());
+
+ if (enabled) {
+ Mutex::Autolock _l(mLock);
+ ALOGD_IF(DEBUG_CONNECTIONS, "... index=%ld",
+ info.rates.indexOfKey(ident));
+
+ if (info.rates.indexOfKey(ident) < 0) {
+ info.rates.add(ident, DEFAULT_EVENTS_PERIOD);
+ if (info.rates.size() == 1) {
+ actuateHardware = true;
+ }
+ } else {
+ // sensor was already activated for this ident
+ }
+ } else {
+ Mutex::Autolock _l(mLock);
+ ALOGD_IF(DEBUG_CONNECTIONS, "... index=%ld",
+ info.rates.indexOfKey(ident));
+
+ ssize_t idx = info.rates.removeItem(ident);
+ if (idx >= 0) {
+ if (info.rates.size() == 0) {
+ actuateHardware = true;
+ }
+ } else {
+ // sensor wasn't enabled for this ident
+ }
+ }
+
+ if (actuateHardware) {
+ ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w");
+
+ err = mSensorDevice->activate(mSensorDevice, handle, enabled);
+ if (enabled) {
+ ALOGE_IF(err, "Error activating sensor %d (%s)", handle, strerror(-err));
+ if (err == 0) {
+ BatteryService::getInstance().enableSensor(handle);
+ }
+ } else {
+ if (err == 0) {
+ BatteryService::getInstance().disableSensor(handle);
+ }
+ }
+ }
+
+ { // scope for the lock
+ Mutex::Autolock _l(mLock);
+ nsecs_t ns = info.selectDelay();
+ mSensorDevice->setDelay(mSensorDevice, handle, ns);
+ }
+
+ return err;
+}
+
+status_t SensorDevice::setDelay(void* ident, int handle, int64_t ns)
+{
+ if (!mSensorDevice) return NO_INIT;
+ Mutex::Autolock _l(mLock);
+ Info& info( mActivationCount.editValueFor(handle) );
+ status_t err = info.setDelayForIdent(ident, ns);
+ if (err < 0) return err;
+ ns = info.selectDelay();
+ return mSensorDevice->setDelay(mSensorDevice, handle, ns);
+}
+
+// ---------------------------------------------------------------------------
+
+status_t SensorDevice::Info::setDelayForIdent(void* ident, int64_t ns)
+{
+ ssize_t index = rates.indexOfKey(ident);
+ if (index < 0) {
+ ALOGE("Info::setDelayForIdent(ident=%p, ns=%lld) failed (%s)",
+ ident, ns, strerror(-index));
+ return BAD_INDEX;
+ }
+ rates.editValueAt(index) = ns;
+ return NO_ERROR;
+}
+
+nsecs_t SensorDevice::Info::selectDelay()
+{
+ nsecs_t ns = rates.valueAt(0);
+ for (size_t i=1 ; i<rates.size() ; i++) {
+ nsecs_t cur = rates.valueAt(i);
+ if (cur < ns) {
+ ns = cur;
+ }
+ }
+ delay = ns;
+ return ns;
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
new file mode 100644
index 0000000..728b6cb
--- /dev/null
+++ b/services/sensorservice/SensorDevice.h
@@ -0,0 +1,64 @@
+/*
+ * 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_DEVICE_H
+#define ANDROID_SENSOR_DEVICE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/KeyedVector.h>
+#include <utils/Singleton.h>
+#include <utils/String8.h>
+
+#include <gui/Sensor.h>
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+static const nsecs_t DEFAULT_EVENTS_PERIOD = 200000000; // 5 Hz
+
+class SensorDevice : public Singleton<SensorDevice> {
+ friend class Singleton<SensorDevice>;
+ struct sensors_poll_device_t* mSensorDevice;
+ struct sensors_module_t* mSensorModule;
+ mutable Mutex mLock; // protect mActivationCount[].rates
+ // fixed-size array after construction
+ struct Info {
+ Info() : delay(0) { }
+ KeyedVector<void*, nsecs_t> rates;
+ nsecs_t delay;
+ status_t setDelayForIdent(void* ident, int64_t ns);
+ nsecs_t selectDelay();
+ };
+ DefaultKeyedVector<int, Info> mActivationCount;
+
+ SensorDevice();
+public:
+ ssize_t getSensorList(sensor_t const** list);
+ status_t initCheck() const;
+ ssize_t poll(sensors_event_t* buffer, size_t count);
+ status_t activate(void* ident, int handle, int enabled);
+ status_t setDelay(void* ident, int handle, int64_t ns);
+ void dump(String8& result, char* buffer, size_t SIZE);
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_SENSOR_DEVICE_H
diff --git a/services/sensorservice/SensorFusion.cpp b/services/sensorservice/SensorFusion.cpp
new file mode 100644
index 0000000..d23906d
--- /dev/null
+++ b/services/sensorservice/SensorFusion.cpp
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2011 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 "SensorDevice.h"
+#include "SensorFusion.h"
+#include "SensorService.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+ANDROID_SINGLETON_STATIC_INSTANCE(SensorFusion)
+
+SensorFusion::SensorFusion()
+ : mSensorDevice(SensorDevice::getInstance()),
+ mEnabled(false), mGyroTime(0)
+{
+ sensor_t const* list;
+ ssize_t count = mSensorDevice.getSensorList(&list);
+ if (count > 0) {
+ for (size_t i=0 ; i<size_t(count) ; i++) {
+ if (list[i].type == SENSOR_TYPE_ACCELEROMETER) {
+ mAcc = Sensor(list + i);
+ }
+ if (list[i].type == SENSOR_TYPE_MAGNETIC_FIELD) {
+ mMag = Sensor(list + i);
+ }
+ if (list[i].type == SENSOR_TYPE_GYROSCOPE) {
+ mGyro = Sensor(list + i);
+ // 200 Hz for gyro events is a good compromise between precision
+ // and power/cpu usage.
+ mGyroRate = 200;
+ mTargetDelayNs = 1000000000LL/mGyroRate;
+ }
+ }
+ mFusion.init();
+ }
+}
+
+void SensorFusion::process(const sensors_event_t& event) {
+ if (event.type == SENSOR_TYPE_GYROSCOPE) {
+ if (mGyroTime != 0) {
+ const float dT = (event.timestamp - mGyroTime) / 1000000000.0f;
+ const float freq = 1 / dT;
+ if (freq >= 100 && freq<1000) { // filter values obviously wrong
+ const float alpha = 1 / (1 + dT); // 1s time-constant
+ mGyroRate = freq + (mGyroRate - freq)*alpha;
+ }
+ }
+ mGyroTime = event.timestamp;
+ mFusion.handleGyro(vec3_t(event.data), 1.0f/mGyroRate);
+ } else if (event.type == SENSOR_TYPE_MAGNETIC_FIELD) {
+ const vec3_t mag(event.data);
+ mFusion.handleMag(mag);
+ } else if (event.type == SENSOR_TYPE_ACCELEROMETER) {
+ const vec3_t acc(event.data);
+ mFusion.handleAcc(acc);
+ mAttitude = mFusion.getAttitude();
+ }
+}
+
+template <typename T> inline T min(T a, T b) { return a<b ? a : b; }
+template <typename T> inline T max(T a, T b) { return a>b ? a : b; }
+
+status_t SensorFusion::activate(void* ident, bool enabled) {
+
+ ALOGD_IF(DEBUG_CONNECTIONS,
+ "SensorFusion::activate(ident=%p, enabled=%d)",
+ ident, enabled);
+
+ const ssize_t idx = mClients.indexOf(ident);
+ if (enabled) {
+ if (idx < 0) {
+ mClients.add(ident);
+ }
+ } else {
+ if (idx >= 0) {
+ mClients.removeItemsAt(idx);
+ }
+ }
+
+ mSensorDevice.activate(ident, mAcc.getHandle(), enabled);
+ mSensorDevice.activate(ident, mMag.getHandle(), enabled);
+ mSensorDevice.activate(ident, mGyro.getHandle(), enabled);
+
+ const bool newState = mClients.size() != 0;
+ if (newState != mEnabled) {
+ mEnabled = newState;
+ if (newState) {
+ mFusion.init();
+ mGyroTime = 0;
+ }
+ }
+ return NO_ERROR;
+}
+
+status_t SensorFusion::setDelay(void* ident, int64_t ns) {
+ mSensorDevice.setDelay(ident, mAcc.getHandle(), ns);
+ mSensorDevice.setDelay(ident, mMag.getHandle(), ms2ns(20));
+ mSensorDevice.setDelay(ident, mGyro.getHandle(), mTargetDelayNs);
+ return NO_ERROR;
+}
+
+
+float SensorFusion::getPowerUsage() const {
+ float power = mAcc.getPowerUsage() +
+ mMag.getPowerUsage() +
+ mGyro.getPowerUsage();
+ return power;
+}
+
+int32_t SensorFusion::getMinDelay() const {
+ return mAcc.getMinDelay();
+}
+
+void SensorFusion::dump(String8& result, char* buffer, size_t SIZE) {
+ const Fusion& fusion(mFusion);
+ snprintf(buffer, SIZE, "9-axis fusion %s (%d clients), gyro-rate=%7.2fHz, "
+ "q=< %g, %g, %g, %g > (%g), "
+ "b=< %g, %g, %g >\n",
+ mEnabled ? "enabled" : "disabled",
+ mClients.size(),
+ mGyroRate,
+ fusion.getAttitude().x,
+ fusion.getAttitude().y,
+ fusion.getAttitude().z,
+ fusion.getAttitude().w,
+ length(fusion.getAttitude()),
+ fusion.getBias().x,
+ fusion.getBias().y,
+ fusion.getBias().z);
+ result.append(buffer);
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/services/sensorservice/SensorFusion.h b/services/sensorservice/SensorFusion.h
new file mode 100644
index 0000000..4c99bcb
--- /dev/null
+++ b/services/sensorservice/SensorFusion.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2011 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_FUSION_H
+#define ANDROID_SENSOR_FUSION_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/SortedVector.h>
+#include <utils/Singleton.h>
+#include <utils/String8.h>
+
+#include <gui/Sensor.h>
+
+#include "Fusion.h"
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+class SensorDevice;
+
+class SensorFusion : public Singleton<SensorFusion> {
+ friend class Singleton<SensorFusion>;
+
+ SensorDevice& mSensorDevice;
+ Sensor mAcc;
+ Sensor mMag;
+ Sensor mGyro;
+ Fusion mFusion;
+ bool mEnabled;
+ float mGyroRate;
+ nsecs_t mTargetDelayNs;
+ nsecs_t mGyroTime;
+ vec4_t mAttitude;
+ SortedVector<void*> mClients;
+
+ SensorFusion();
+
+public:
+ void process(const sensors_event_t& event);
+
+ bool isEnabled() const { return mEnabled; }
+ bool hasEstimate() const { return mFusion.hasEstimate(); }
+ mat33_t getRotationMatrix() const { return mFusion.getRotationMatrix(); }
+ vec4_t getAttitude() const { return mAttitude; }
+ vec3_t getGyroBias() const { return mFusion.getBias(); }
+ float getEstimatedRate() const { return mGyroRate; }
+
+ status_t activate(void* ident, bool enabled);
+ status_t setDelay(void* ident, int64_t ns);
+
+ float getPowerUsage() const;
+ int32_t getMinDelay() const;
+
+ void dump(String8& result, char* buffer, size_t SIZE);
+};
+
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_SENSOR_FUSION_H
diff --git a/services/sensorservice/SensorInterface.cpp b/services/sensorservice/SensorInterface.cpp
new file mode 100644
index 0000000..468aa61
--- /dev/null
+++ b/services/sensorservice/SensorInterface.cpp
@@ -0,0 +1,63 @@
+/*
+ * 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 <cutils/log.h>
+
+#include "SensorInterface.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+SensorInterface::~SensorInterface()
+{
+}
+
+// ---------------------------------------------------------------------------
+
+HardwareSensor::HardwareSensor(const sensor_t& sensor)
+ : mSensorDevice(SensorDevice::getInstance()),
+ mSensor(&sensor)
+{
+ ALOGI("%s", sensor.name);
+}
+
+HardwareSensor::~HardwareSensor() {
+}
+
+bool HardwareSensor::process(sensors_event_t* outEvent,
+ const sensors_event_t& event) {
+ *outEvent = event;
+ return true;
+}
+
+status_t HardwareSensor::activate(void* ident, bool enabled) {
+ return mSensorDevice.activate(ident, mSensor.getHandle(), enabled);
+}
+
+status_t HardwareSensor::setDelay(void* ident, int handle, int64_t ns) {
+ return mSensorDevice.setDelay(ident, handle, ns);
+}
+
+Sensor HardwareSensor::getSensor() const {
+ return mSensor;
+}
+
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/services/sensorservice/SensorInterface.h b/services/sensorservice/SensorInterface.h
new file mode 100644
index 0000000..fb357d7
--- /dev/null
+++ b/services/sensorservice/SensorInterface.h
@@ -0,0 +1,70 @@
+/*
+ * 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_INTERFACE_H
+#define ANDROID_SENSOR_INTERFACE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <gui/Sensor.h>
+
+#include "SensorDevice.h"
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+class SensorInterface {
+public:
+ virtual ~SensorInterface();
+
+ virtual bool process(sensors_event_t* outEvent,
+ const sensors_event_t& event) = 0;
+
+ virtual status_t activate(void* ident, bool enabled) = 0;
+ virtual status_t setDelay(void* ident, int handle, int64_t ns) = 0;
+ virtual Sensor getSensor() const = 0;
+ virtual bool isVirtual() const = 0;
+};
+
+// ---------------------------------------------------------------------------
+
+class HardwareSensor : public SensorInterface
+{
+ SensorDevice& mSensorDevice;
+ Sensor mSensor;
+
+public:
+ HardwareSensor(const sensor_t& sensor);
+
+ virtual ~HardwareSensor();
+
+ virtual bool process(sensors_event_t* outEvent,
+ const sensors_event_t& event);
+
+ virtual status_t activate(void* ident, bool enabled);
+ virtual status_t setDelay(void* ident, int handle, int64_t ns);
+ virtual Sensor getSensor() const;
+ virtual bool isVirtual() const { return false; }
+};
+
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_SENSOR_INTERFACE_H
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
new file mode 100644
index 0000000..7ab34c9
--- /dev/null
+++ b/services/sensorservice/SensorService.cpp
@@ -0,0 +1,657 @@
+/*
+ * 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 <math.h>
+#include <sys/types.h>
+
+#include <cutils/properties.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 <utils/Singleton.h>
+#include <utils/String16.h>
+
+#include <binder/BinderService.h>
+#include <binder/IServiceManager.h>
+#include <binder/PermissionCache.h>
+
+#include <gui/ISensorServer.h>
+#include <gui/ISensorEventConnection.h>
+#include <gui/SensorEventQueue.h>
+
+#include <hardware/sensors.h>
+
+#include "CorrectedGyroSensor.h"
+#include "GravitySensor.h"
+#include "LinearAccelerationSensor.h"
+#include "OrientationSensor.h"
+#include "RotationVectorSensor.h"
+#include "SensorFusion.h"
+#include "SensorService.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+/*
+ * Notes:
+ *
+ * - what about a gyro-corrected magnetic-field sensor?
+ * - run mag sensor from time to time to force calibration
+ * - gravity sensor length is wrong (=> drift in linear-acc sensor)
+ *
+ */
+
+SensorService::SensorService()
+ : mInitCheck(NO_INIT)
+{
+}
+
+void SensorService::onFirstRef()
+{
+ ALOGD("nuSensorService starting...");
+
+ SensorDevice& dev(SensorDevice::getInstance());
+
+ if (dev.initCheck() == NO_ERROR) {
+ sensor_t const* list;
+ ssize_t count = dev.getSensorList(&list);
+ if (count > 0) {
+ ssize_t orientationIndex = -1;
+ bool hasGyro = false;
+ uint32_t virtualSensorsNeeds =
+ (1<<SENSOR_TYPE_GRAVITY) |
+ (1<<SENSOR_TYPE_LINEAR_ACCELERATION) |
+ (1<<SENSOR_TYPE_ROTATION_VECTOR);
+
+ mLastEventSeen.setCapacity(count);
+ for (ssize_t i=0 ; i<count ; i++) {
+ registerSensor( new HardwareSensor(list[i]) );
+ switch (list[i].type) {
+ case SENSOR_TYPE_ORIENTATION:
+ orientationIndex = i;
+ break;
+ case SENSOR_TYPE_GYROSCOPE:
+ hasGyro = true;
+ break;
+ case SENSOR_TYPE_GRAVITY:
+ case SENSOR_TYPE_LINEAR_ACCELERATION:
+ case SENSOR_TYPE_ROTATION_VECTOR:
+ virtualSensorsNeeds &= ~(1<<list[i].type);
+ break;
+ }
+ }
+
+ // it's safe to instantiate the SensorFusion object here
+ // (it wants to be instantiated after h/w sensors have been
+ // registered)
+ const SensorFusion& fusion(SensorFusion::getInstance());
+
+ if (hasGyro) {
+ // Always instantiate Android's virtual sensors. Since they are
+ // instantiated behind sensors from the HAL, they won't
+ // interfere with applications, unless they looks specifically
+ // for them (by name).
+
+ registerVirtualSensor( new RotationVectorSensor() );
+ registerVirtualSensor( new GravitySensor(list, count) );
+ registerVirtualSensor( new LinearAccelerationSensor(list, count) );
+
+ // these are optional
+ registerVirtualSensor( new OrientationSensor() );
+ registerVirtualSensor( new CorrectedGyroSensor(list, count) );
+ }
+
+ // build the sensor list returned to users
+ mUserSensorList = mSensorList;
+
+ if (hasGyro) {
+ // virtual debugging sensors are not added to mUserSensorList
+ registerVirtualSensor( new GyroDriftSensor() );
+ }
+
+ if (hasGyro &&
+ (virtualSensorsNeeds & (1<<SENSOR_TYPE_ROTATION_VECTOR))) {
+ // if we have the fancy sensor fusion, and it's not provided by the
+ // HAL, use our own (fused) orientation sensor by removing the
+ // HAL supplied one form the user list.
+ if (orientationIndex >= 0) {
+ mUserSensorList.removeItemsAt(orientationIndex);
+ }
+ }
+
+ // debugging sensor list
+ for (size_t i=0 ; i<mSensorList.size() ; i++) {
+ switch (mSensorList[i].getType()) {
+ case SENSOR_TYPE_GRAVITY:
+ case SENSOR_TYPE_LINEAR_ACCELERATION:
+ case SENSOR_TYPE_ROTATION_VECTOR:
+ if (strstr(mSensorList[i].getVendor().string(), "Google")) {
+ mUserSensorListDebug.add(mSensorList[i]);
+ }
+ break;
+ default:
+ mUserSensorListDebug.add(mSensorList[i]);
+ break;
+ }
+ }
+
+ run("SensorService", PRIORITY_URGENT_DISPLAY);
+ mInitCheck = NO_ERROR;
+ }
+ }
+}
+
+void SensorService::registerSensor(SensorInterface* s)
+{
+ sensors_event_t event;
+ memset(&event, 0, sizeof(event));
+
+ const Sensor sensor(s->getSensor());
+ // add to the sensor list (returned to clients)
+ mSensorList.add(sensor);
+ // add to our handle->SensorInterface mapping
+ mSensorMap.add(sensor.getHandle(), s);
+ // create an entry in the mLastEventSeen array
+ mLastEventSeen.add(sensor.getHandle(), event);
+}
+
+void SensorService::registerVirtualSensor(SensorInterface* s)
+{
+ registerSensor(s);
+ mVirtualSensorList.add( s );
+}
+
+SensorService::~SensorService()
+{
+ for (size_t i=0 ; i<mSensorMap.size() ; i++)
+ delete mSensorMap.valueAt(i);
+}
+
+static const String16 sDump("android.permission.DUMP");
+
+status_t SensorService::dump(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 1024;
+ char buffer[SIZE];
+ String8 result;
+ if (!PermissionCache::checkCallingPermission(sDump)) {
+ 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, "Sensor List:\n");
+ result.append(buffer);
+ for (size_t i=0 ; i<mSensorList.size() ; i++) {
+ const Sensor& s(mSensorList[i]);
+ const sensors_event_t& e(mLastEventSeen.valueFor(s.getHandle()));
+ snprintf(buffer, SIZE,
+ "%-48s| %-32s | 0x%08x | maxRate=%7.2fHz | "
+ "last=<%5.1f,%5.1f,%5.1f>\n",
+ s.getName().string(),
+ s.getVendor().string(),
+ s.getHandle(),
+ s.getMinDelay() ? (1000000.0f / s.getMinDelay()) : 0.0f,
+ e.data[0], e.data[1], e.data[2]);
+ result.append(buffer);
+ }
+ SensorFusion::getInstance().dump(result, buffer, SIZE);
+ SensorDevice::getInstance().dump(result, buffer, SIZE);
+
+ snprintf(buffer, SIZE, "%d active connections\n",
+ mActiveConnections.size());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "Active sensors:\n");
+ result.append(buffer);
+ for (size_t i=0 ; i<mActiveSensors.size() ; i++) {
+ int handle = mActiveSensors.keyAt(i);
+ snprintf(buffer, SIZE, "%s (handle=0x%08x, connections=%d)\n",
+ getSensorName(handle).string(),
+ handle,
+ mActiveSensors.valueAt(i)->getNumConnections());
+ result.append(buffer);
+ }
+ }
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+bool SensorService::threadLoop()
+{
+ ALOGD("nuSensorService thread starting...");
+
+ const size_t numEventMax = 16;
+ const size_t minBufferSize = numEventMax + numEventMax * mVirtualSensorList.size();
+ sensors_event_t buffer[minBufferSize];
+ sensors_event_t scratch[minBufferSize];
+ SensorDevice& device(SensorDevice::getInstance());
+ const size_t vcount = mVirtualSensorList.size();
+
+ ssize_t count;
+ do {
+ count = device.poll(buffer, numEventMax);
+ if (count<0) {
+ ALOGE("sensor poll failed (%s)", strerror(-count));
+ break;
+ }
+
+ recordLastValue(buffer, count);
+
+ // handle virtual sensors
+ if (count && vcount) {
+ sensors_event_t const * const event = buffer;
+ const DefaultKeyedVector<int, SensorInterface*> virtualSensors(
+ getActiveVirtualSensors());
+ const size_t activeVirtualSensorCount = virtualSensors.size();
+ if (activeVirtualSensorCount) {
+ size_t k = 0;
+ SensorFusion& fusion(SensorFusion::getInstance());
+ if (fusion.isEnabled()) {
+ for (size_t i=0 ; i<size_t(count) ; i++) {
+ fusion.process(event[i]);
+ }
+ }
+ for (size_t i=0 ; i<size_t(count) && k<minBufferSize ; i++) {
+ for (size_t j=0 ; j<activeVirtualSensorCount ; j++) {
+ if (count + k >= minBufferSize) {
+ ALOGE("buffer too small to hold all events: "
+ "count=%u, k=%u, size=%u",
+ count, k, minBufferSize);
+ break;
+ }
+ sensors_event_t out;
+ SensorInterface* si = virtualSensors.valueAt(j);
+ if (si->process(&out, event[i])) {
+ buffer[count + k] = out;
+ k++;
+ }
+ }
+ }
+ if (k) {
+ // record the last synthesized values
+ recordLastValue(&buffer[count], k);
+ count += k;
+ // sort the buffer by time-stamps
+ sortEventBuffer(buffer, count);
+ }
+ }
+ }
+
+ // send our events to clients...
+ const SortedVector< wp<SensorEventConnection> > activeConnections(
+ getActiveConnections());
+ size_t numConnections = activeConnections.size();
+ for (size_t i=0 ; i<numConnections ; i++) {
+ sp<SensorEventConnection> connection(
+ activeConnections[i].promote());
+ if (connection != 0) {
+ connection->sendEvents(buffer, count, scratch);
+ }
+ }
+ } while (count >= 0 || Thread::exitPending());
+
+ ALOGW("Exiting SensorService::threadLoop => aborting...");
+ abort();
+ return false;
+}
+
+void SensorService::recordLastValue(
+ sensors_event_t const * buffer, size_t count)
+{
+ Mutex::Autolock _l(mLock);
+
+ // record the last event for each sensor
+ int32_t prev = buffer[0].sensor;
+ for (size_t i=1 ; i<count ; i++) {
+ // record the last event of each sensor type in this buffer
+ int32_t curr = buffer[i].sensor;
+ if (curr != prev) {
+ mLastEventSeen.editValueFor(prev) = buffer[i-1];
+ prev = curr;
+ }
+ }
+ mLastEventSeen.editValueFor(prev) = buffer[count-1];
+}
+
+void SensorService::sortEventBuffer(sensors_event_t* buffer, size_t count)
+{
+ struct compar {
+ static int cmp(void const* lhs, void const* rhs) {
+ sensors_event_t const* l = static_cast<sensors_event_t const*>(lhs);
+ sensors_event_t const* r = static_cast<sensors_event_t const*>(rhs);
+ return l->timestamp - r->timestamp;
+ }
+ };
+ qsort(buffer, count, sizeof(sensors_event_t), compar::cmp);
+}
+
+SortedVector< wp<SensorService::SensorEventConnection> >
+SensorService::getActiveConnections() const
+{
+ Mutex::Autolock _l(mLock);
+ return mActiveConnections;
+}
+
+DefaultKeyedVector<int, SensorInterface*>
+SensorService::getActiveVirtualSensors() const
+{
+ Mutex::Autolock _l(mLock);
+ return mActiveVirtualSensors;
+}
+
+String8 SensorService::getSensorName(int handle) const {
+ size_t count = mUserSensorList.size();
+ for (size_t i=0 ; i<count ; i++) {
+ const Sensor& sensor(mUserSensorList[i]);
+ if (sensor.getHandle() == handle) {
+ return sensor.getName();
+ }
+ }
+ String8 result("unknown");
+ return result;
+}
+
+Vector<Sensor> SensorService::getSensorList()
+{
+ char value[PROPERTY_VALUE_MAX];
+ property_get("debug.sensors", value, "0");
+ if (atoi(value)) {
+ return mUserSensorListDebug;
+ }
+ return mUserSensorList;
+}
+
+sp<ISensorEventConnection> SensorService::createSensorEventConnection()
+{
+ sp<SensorEventConnection> result(new SensorEventConnection(this));
+ return result;
+}
+
+void SensorService::cleanupConnection(SensorEventConnection* c)
+{
+ Mutex::Autolock _l(mLock);
+ const wp<SensorEventConnection> connection(c);
+ size_t size = mActiveSensors.size();
+ ALOGD_IF(DEBUG_CONNECTIONS, "%d active sensors", size);
+ for (size_t i=0 ; i<size ; ) {
+ int handle = mActiveSensors.keyAt(i);
+ if (c->hasSensor(handle)) {
+ ALOGD_IF(DEBUG_CONNECTIONS, "%i: disabling handle=0x%08x", i, handle);
+ SensorInterface* sensor = mSensorMap.valueFor( handle );
+ ALOGE_IF(!sensor, "mSensorMap[handle=0x%08x] is null!", handle);
+ if (sensor) {
+ sensor->activate(c, false);
+ }
+ }
+ SensorRecord* rec = mActiveSensors.valueAt(i);
+ ALOGE_IF(!rec, "mActiveSensors[%d] is null (handle=0x%08x)!", i, handle);
+ ALOGD_IF(DEBUG_CONNECTIONS,
+ "removing connection %p for sensor[%d].handle=0x%08x",
+ c, i, handle);
+
+ if (rec && rec->removeConnection(connection)) {
+ ALOGD_IF(DEBUG_CONNECTIONS, "... and it was the last connection");
+ mActiveSensors.removeItemsAt(i, 1);
+ mActiveVirtualSensors.removeItem(handle);
+ delete rec;
+ size--;
+ } else {
+ i++;
+ }
+ }
+ mActiveConnections.remove(connection);
+}
+
+status_t SensorService::enable(const sp<SensorEventConnection>& connection,
+ int handle)
+{
+ if (mInitCheck != NO_ERROR)
+ return mInitCheck;
+
+ Mutex::Autolock _l(mLock);
+ SensorInterface* sensor = mSensorMap.valueFor(handle);
+ status_t err = sensor ? sensor->activate(connection.get(), true) : status_t(BAD_VALUE);
+ if (err == NO_ERROR) {
+ SensorRecord* rec = mActiveSensors.valueFor(handle);
+ if (rec == 0) {
+ rec = new SensorRecord(connection);
+ mActiveSensors.add(handle, rec);
+ if (sensor->isVirtual()) {
+ mActiveVirtualSensors.add(handle, sensor);
+ }
+ } else {
+ if (rec->addConnection(connection)) {
+ // this sensor is already activated, but we are adding a
+ // connection that uses it. Immediately send down the last
+ // known value of the requested sensor if it's not a
+ // "continuous" sensor.
+ if (sensor->getSensor().getMinDelay() == 0) {
+ sensors_event_t scratch;
+ sensors_event_t& event(mLastEventSeen.editValueFor(handle));
+ if (event.version == sizeof(sensors_event_t)) {
+ connection->sendEvents(&event, 1);
+ }
+ }
+ }
+ }
+ if (err == NO_ERROR) {
+ // connection now active
+ if (connection->addSensor(handle)) {
+ // the sensor was added (which means it wasn't already there)
+ // so, see if this connection becomes active
+ if (mActiveConnections.indexOf(connection) < 0) {
+ mActiveConnections.add(connection);
+ }
+ }
+ }
+ }
+ return err;
+}
+
+status_t SensorService::disable(const sp<SensorEventConnection>& connection,
+ int handle)
+{
+ if (mInitCheck != NO_ERROR)
+ return mInitCheck;
+
+ status_t err = NO_ERROR;
+ Mutex::Autolock _l(mLock);
+ SensorRecord* rec = mActiveSensors.valueFor(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);
+ mActiveVirtualSensors.removeItem(handle);
+ delete rec;
+ }
+ SensorInterface* sensor = mSensorMap.valueFor(handle);
+ err = sensor ? sensor->activate(connection.get(), false) : status_t(BAD_VALUE);
+ }
+ return err;
+}
+
+status_t SensorService::setEventRate(const sp<SensorEventConnection>& connection,
+ int handle, nsecs_t ns)
+{
+ if (mInitCheck != NO_ERROR)
+ return mInitCheck;
+
+ SensorInterface* sensor = mSensorMap.valueFor(handle);
+ if (!sensor)
+ return BAD_VALUE;
+
+ if (ns < 0)
+ return BAD_VALUE;
+
+ nsecs_t minDelayNs = sensor->getSensor().getMinDelayNs();
+ if (ns < minDelayNs) {
+ ns = minDelayNs;
+ }
+
+ if (ns < MINIMUM_EVENTS_PERIOD)
+ ns = MINIMUM_EVENTS_PERIOD;
+
+ return sensor->setDelay(connection.get(), handle, ns);
+}
+
+// ---------------------------------------------------------------------------
+
+SensorService::SensorRecord::SensorRecord(
+ const sp<SensorEventConnection>& connection)
+{
+ mConnections.add(connection);
+}
+
+bool SensorService::SensorRecord::addConnection(
+ const sp<SensorEventConnection>& connection)
+{
+ if (mConnections.indexOf(connection) < 0) {
+ mConnections.add(connection);
+ return true;
+ }
+ return false;
+}
+
+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 BitTube())
+{
+}
+
+SensorService::SensorEventConnection::~SensorEventConnection()
+{
+ ALOGD_IF(DEBUG_CONNECTIONS, "~SensorEventConnection(%p)", this);
+ mService->cleanupConnection(this);
+}
+
+void SensorService::SensorEventConnection::onFirstRef()
+{
+}
+
+bool SensorService::SensorEventConnection::addSensor(int32_t handle) {
+ Mutex::Autolock _l(mConnectionLock);
+ if (mSensorInfo.indexOf(handle) <= 0) {
+ mSensorInfo.add(handle);
+ return true;
+ }
+ return false;
+}
+
+bool SensorService::SensorEventConnection::removeSensor(int32_t handle) {
+ Mutex::Autolock _l(mConnectionLock);
+ if (mSensorInfo.remove(handle) >= 0) {
+ return true;
+ }
+ return false;
+}
+
+bool SensorService::SensorEventConnection::hasSensor(int32_t handle) const {
+ Mutex::Autolock _l(mConnectionLock);
+ return mSensorInfo.indexOf(handle) >= 0;
+}
+
+bool SensorService::SensorEventConnection::hasAnySensor() const {
+ Mutex::Autolock _l(mConnectionLock);
+ return mSensorInfo.size() ? true : false;
+}
+
+status_t SensorService::SensorEventConnection::sendEvents(
+ sensors_event_t const* buffer, size_t numEvents,
+ sensors_event_t* scratch)
+{
+ // filter out events not for this connection
+ size_t count = 0;
+ if (scratch) {
+ Mutex::Autolock _l(mConnectionLock);
+ size_t i=0;
+ while (i<numEvents) {
+ const int32_t curr = buffer[i].sensor;
+ if (mSensorInfo.indexOf(curr) >= 0) {
+ do {
+ scratch[count++] = buffer[i++];
+ } while ((i<numEvents) && (buffer[i].sensor == curr));
+ } else {
+ i++;
+ }
+ }
+ } else {
+ scratch = const_cast<sensors_event_t *>(buffer);
+ count = numEvents;
+ }
+
+ // NOTE: ASensorEvent and sensors_event_t are the same type
+ ssize_t size = SensorEventQueue::write(mChannel,
+ reinterpret_cast<ASensorEvent const*>(scratch), count);
+ if (size == -EAGAIN) {
+ // the destination doesn't accept events anymore, it's probably
+ // full. For now, we just drop the events on the floor.
+ //ALOGW("dropping %d events on the floor", count);
+ return size;
+ }
+
+ return size < 0 ? status_t(size) : status_t(NO_ERROR);
+}
+
+sp<BitTube> 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->setEventRate(this, handle, ns);
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
new file mode 100644
index 0000000..54a76e8
--- /dev/null
+++ b/services/sensorservice/SensorService.h
@@ -0,0 +1,143 @@
+/*
+ * 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 <gui/Sensor.h>
+#include <gui/BitTube.h>
+#include <gui/ISensorServer.h>
+#include <gui/ISensorEventConnection.h>
+
+#include "SensorInterface.h"
+
+// ---------------------------------------------------------------------------
+
+#define DEBUG_CONNECTIONS false
+
+struct sensors_poll_device_t;
+struct sensors_module_t;
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+class SensorService :
+ public BinderService<SensorService>,
+ public BnSensorServer,
+ protected Thread
+{
+ friend class BinderService<SensorService>;
+
+ static const nsecs_t MINIMUM_EVENTS_PERIOD = 1000000; // 1000 Hz
+
+ 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 ~SensorEventConnection();
+ virtual void onFirstRef();
+ virtual sp<BitTube> getSensorChannel() const;
+ virtual status_t enableDisable(int handle, bool enabled);
+ virtual status_t setEventRate(int handle, nsecs_t ns);
+
+ sp<SensorService> const mService;
+ sp<BitTube> const mChannel;
+ mutable Mutex mConnectionLock;
+
+ // protected by SensorService::mLock
+ SortedVector<int> mSensorInfo;
+
+ public:
+ SensorEventConnection(const sp<SensorService>& service);
+
+ status_t sendEvents(sensors_event_t const* buffer, size_t count,
+ sensors_event_t* scratch = NULL);
+ bool hasSensor(int32_t handle) const;
+ bool hasAnySensor() const;
+ bool addSensor(int32_t handle);
+ bool removeSensor(int32_t handle);
+ };
+
+ class SensorRecord {
+ SortedVector< wp<SensorEventConnection> > mConnections;
+ public:
+ SensorRecord(const sp<SensorEventConnection>& connection);
+ bool addConnection(const sp<SensorEventConnection>& connection);
+ bool removeConnection(const wp<SensorEventConnection>& connection);
+ size_t getNumConnections() const { return mConnections.size(); }
+ };
+
+ SortedVector< wp<SensorEventConnection> > getActiveConnections() const;
+ DefaultKeyedVector<int, SensorInterface*> getActiveVirtualSensors() const;
+
+ String8 getSensorName(int handle) const;
+ void recordLastValue(sensors_event_t const * buffer, size_t count);
+ static void sortEventBuffer(sensors_event_t* buffer, size_t count);
+ void registerSensor(SensorInterface* sensor);
+ void registerVirtualSensor(SensorInterface* sensor);
+
+ // constants
+ Vector<Sensor> mSensorList;
+ Vector<Sensor> mUserSensorListDebug;
+ Vector<Sensor> mUserSensorList;
+ DefaultKeyedVector<int, SensorInterface*> mSensorMap;
+ Vector<SensorInterface *> mVirtualSensorList;
+ status_t mInitCheck;
+
+ // protected by mLock
+ mutable Mutex mLock;
+ DefaultKeyedVector<int, SensorRecord*> mActiveSensors;
+ DefaultKeyedVector<int, SensorInterface*> mActiveVirtualSensors;
+ SortedVector< wp<SensorEventConnection> > mActiveConnections;
+
+ // The size of this vector is constant, only the items are mutable
+ KeyedVector<int32_t, sensors_event_t> mLastEventSeen;
+
+public:
+ static char const* getServiceName() { return "sensorservice"; }
+
+ void cleanupConnection(SensorEventConnection* connection);
+ status_t enable(const sp<SensorEventConnection>& connection, int handle);
+ status_t disable(const sp<SensorEventConnection>& connection, int handle);
+ status_t setEventRate(const sp<SensorEventConnection>& connection, int handle, nsecs_t ns);
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_SENSOR_SERVICE_H
diff --git a/services/sensorservice/mat.h b/services/sensorservice/mat.h
new file mode 100644
index 0000000..a76fc91
--- /dev/null
+++ b/services/sensorservice/mat.h
@@ -0,0 +1,393 @@
+/*
+ * Copyright (C) 2011 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_MAT_H
+#define ANDROID_MAT_H
+
+#include "vec.h"
+#include "traits.h"
+
+// -----------------------------------------------------------------------
+
+namespace android {
+
+template <typename TYPE, size_t C, size_t R>
+class mat;
+
+namespace helpers {
+
+template <typename TYPE, size_t C, size_t R>
+mat<TYPE, C, R>& doAssign(
+ mat<TYPE, C, R>& lhs,
+ typename TypeTraits<TYPE>::ParameterType rhs) {
+ for (size_t i=0 ; i<C ; i++)
+ for (size_t j=0 ; j<R ; j++)
+ lhs[i][j] = (i==j) ? rhs : 0;
+ return lhs;
+}
+
+template <typename TYPE, size_t C, size_t R, size_t D>
+mat<TYPE, C, R> PURE doMul(
+ const mat<TYPE, D, R>& lhs,
+ const mat<TYPE, C, D>& rhs)
+{
+ mat<TYPE, C, R> res;
+ for (size_t c=0 ; c<C ; c++) {
+ for (size_t r=0 ; r<R ; r++) {
+ TYPE v(0);
+ for (size_t k=0 ; k<D ; k++) {
+ v += lhs[k][r] * rhs[c][k];
+ }
+ res[c][r] = v;
+ }
+ }
+ return res;
+}
+
+template <typename TYPE, size_t R, size_t D>
+vec<TYPE, R> PURE doMul(
+ const mat<TYPE, D, R>& lhs,
+ const vec<TYPE, D>& rhs)
+{
+ vec<TYPE, R> res;
+ for (size_t r=0 ; r<R ; r++) {
+ TYPE v(0);
+ for (size_t k=0 ; k<D ; k++) {
+ v += lhs[k][r] * rhs[k];
+ }
+ res[r] = v;
+ }
+ return res;
+}
+
+template <typename TYPE, size_t C, size_t R>
+mat<TYPE, C, R> PURE doMul(
+ const vec<TYPE, R>& lhs,
+ const mat<TYPE, C, 1>& rhs)
+{
+ mat<TYPE, C, R> res;
+ for (size_t c=0 ; c<C ; c++) {
+ for (size_t r=0 ; r<R ; r++) {
+ res[c][r] = lhs[r] * rhs[c][0];
+ }
+ }
+ return res;
+}
+
+template <typename TYPE, size_t C, size_t R>
+mat<TYPE, C, R> PURE doMul(
+ const mat<TYPE, C, R>& rhs,
+ typename TypeTraits<TYPE>::ParameterType v)
+{
+ mat<TYPE, C, R> res;
+ for (size_t c=0 ; c<C ; c++) {
+ for (size_t r=0 ; r<R ; r++) {
+ res[c][r] = rhs[c][r] * v;
+ }
+ }
+ return res;
+}
+
+template <typename TYPE, size_t C, size_t R>
+mat<TYPE, C, R> PURE doMul(
+ typename TypeTraits<TYPE>::ParameterType v,
+ const mat<TYPE, C, R>& rhs)
+{
+ mat<TYPE, C, R> res;
+ for (size_t c=0 ; c<C ; c++) {
+ for (size_t r=0 ; r<R ; r++) {
+ res[c][r] = v * rhs[c][r];
+ }
+ }
+ return res;
+}
+
+
+}; // namespace helpers
+
+// -----------------------------------------------------------------------
+
+template <typename TYPE, size_t C, size_t R>
+class mat : public vec< vec<TYPE, R>, C > {
+ typedef typename TypeTraits<TYPE>::ParameterType pTYPE;
+ typedef vec< vec<TYPE, R>, C > base;
+public:
+ // STL-like interface.
+ typedef TYPE value_type;
+ typedef TYPE& reference;
+ typedef TYPE const& const_reference;
+ typedef size_t size_type;
+ size_type size() const { return R*C; }
+ enum { ROWS = R, COLS = C };
+
+
+ // -----------------------------------------------------------------------
+ // default constructors
+
+ mat() { }
+ mat(const mat& rhs) : base(rhs) { }
+ mat(const base& rhs) : base(rhs) { }
+
+ // -----------------------------------------------------------------------
+ // conversion constructors
+
+ // sets the diagonal to the value, off-diagonal to zero
+ mat(pTYPE rhs) {
+ helpers::doAssign(*this, rhs);
+ }
+
+ // -----------------------------------------------------------------------
+ // Assignment
+
+ mat& operator=(const mat& rhs) {
+ base::operator=(rhs);
+ return *this;
+ }
+
+ mat& operator=(const base& rhs) {
+ base::operator=(rhs);
+ return *this;
+ }
+
+ mat& operator=(pTYPE rhs) {
+ return helpers::doAssign(*this, rhs);
+ }
+
+ // -----------------------------------------------------------------------
+ // non-member function declaration and definition
+
+ friend inline mat PURE operator + (const mat& lhs, const mat& rhs) {
+ return helpers::doAdd(
+ static_cast<const base&>(lhs),
+ static_cast<const base&>(rhs));
+ }
+ friend inline mat PURE operator - (const mat& lhs, const mat& rhs) {
+ return helpers::doSub(
+ static_cast<const base&>(lhs),
+ static_cast<const base&>(rhs));
+ }
+
+ // matrix*matrix
+ template <size_t D>
+ friend mat PURE operator * (
+ const mat<TYPE, D, R>& lhs,
+ const mat<TYPE, C, D>& rhs) {
+ return helpers::doMul(lhs, rhs);
+ }
+
+ // matrix*vector
+ friend vec<TYPE, R> PURE operator * (
+ const mat& lhs, const vec<TYPE, C>& rhs) {
+ return helpers::doMul(lhs, rhs);
+ }
+
+ // vector*matrix
+ friend mat PURE operator * (
+ const vec<TYPE, R>& lhs, const mat<TYPE, C, 1>& rhs) {
+ return helpers::doMul(lhs, rhs);
+ }
+
+ // matrix*scalar
+ friend inline mat PURE operator * (const mat& lhs, pTYPE v) {
+ return helpers::doMul(lhs, v);
+ }
+
+ // scalar*matrix
+ friend inline mat PURE operator * (pTYPE v, const mat& rhs) {
+ return helpers::doMul(v, rhs);
+ }
+
+ // -----------------------------------------------------------------------
+ // streaming operator to set the columns of the matrix:
+ // example:
+ // mat33_t m;
+ // m << v0 << v1 << v2;
+
+ // column_builder<> stores the matrix and knows which column to set
+ template<size_t PREV_COLUMN>
+ struct column_builder {
+ mat& matrix;
+ column_builder(mat& matrix) : matrix(matrix) { }
+ };
+
+ // operator << is not a method of column_builder<> so we can
+ // overload it for unauthorized values (partial specialization
+ // not allowed in class-scope).
+ // we just set the column and return the next column_builder<>
+ template<size_t PREV_COLUMN>
+ friend column_builder<PREV_COLUMN+1> operator << (
+ const column_builder<PREV_COLUMN>& lhs,
+ const vec<TYPE, R>& rhs) {
+ lhs.matrix[PREV_COLUMN+1] = rhs;
+ return column_builder<PREV_COLUMN+1>(lhs.matrix);
+ }
+
+ // we return void here so we get a compile-time error if the
+ // user tries to set too many columns
+ friend void operator << (
+ const column_builder<C-2>& lhs,
+ const vec<TYPE, R>& rhs) {
+ lhs.matrix[C-1] = rhs;
+ }
+
+ // this is where the process starts. we set the first columns and
+ // return the next column_builder<>
+ column_builder<0> operator << (const vec<TYPE, R>& rhs) {
+ (*this)[0] = rhs;
+ return column_builder<0>(*this);
+ }
+};
+
+// Specialize column matrix so they're exactly equivalent to a vector
+template <typename TYPE, size_t R>
+class mat<TYPE, 1, R> : public vec<TYPE, R> {
+ typedef vec<TYPE, R> base;
+public:
+ // STL-like interface.
+ typedef TYPE value_type;
+ typedef TYPE& reference;
+ typedef TYPE const& const_reference;
+ typedef size_t size_type;
+ size_type size() const { return R; }
+ enum { ROWS = R, COLS = 1 };
+
+ mat() { }
+ mat(const base& rhs) : base(rhs) { }
+ mat(const mat& rhs) : base(rhs) { }
+ mat(const TYPE& rhs) { helpers::doAssign(*this, rhs); }
+ mat& operator=(const mat& rhs) { base::operator=(rhs); return *this; }
+ mat& operator=(const base& rhs) { base::operator=(rhs); return *this; }
+ mat& operator=(const TYPE& rhs) { return helpers::doAssign(*this, rhs); }
+ // we only have one column, so ignore the index
+ const base& operator[](size_t) const { return *this; }
+ base& operator[](size_t) { return *this; }
+ void operator << (const vec<TYPE, R>& rhs) { base::operator[](0) = rhs; }
+};
+
+// -----------------------------------------------------------------------
+// matrix functions
+
+// transpose. this handles matrices of matrices
+inline int PURE transpose(int v) { return v; }
+inline float PURE transpose(float v) { return v; }
+inline double PURE transpose(double v) { return v; }
+
+// Transpose a matrix
+template <typename TYPE, size_t C, size_t R>
+mat<TYPE, R, C> PURE transpose(const mat<TYPE, C, R>& m) {
+ mat<TYPE, R, C> r;
+ for (size_t i=0 ; i<R ; i++)
+ for (size_t j=0 ; j<C ; j++)
+ r[i][j] = transpose(m[j][i]);
+ return r;
+}
+
+// Calculate the trace of a matrix
+template <typename TYPE, size_t C> static TYPE trace(const mat<TYPE, C, C>& m) {
+ TYPE t;
+ for (size_t i=0 ; i<C ; i++)
+ t += m[i][i];
+ return t;
+}
+
+// Test positive-semidefiniteness of a matrix
+template <typename TYPE, size_t C>
+static bool isPositiveSemidefinite(const mat<TYPE, C, C>& m, TYPE tolerance) {
+ for (size_t i=0 ; i<C ; i++)
+ if (m[i][i] < 0)
+ return false;
+
+ for (size_t i=0 ; i<C ; i++)
+ for (size_t j=i+1 ; j<C ; j++)
+ if (fabs(m[i][j] - m[j][i]) > tolerance)
+ return false;
+
+ return true;
+}
+
+// Transpose a vector
+template <
+ template<typename T, size_t S> class VEC,
+ typename TYPE,
+ size_t SIZE
+>
+mat<TYPE, SIZE, 1> PURE transpose(const VEC<TYPE, SIZE>& v) {
+ mat<TYPE, SIZE, 1> r;
+ for (size_t i=0 ; i<SIZE ; i++)
+ r[i][0] = transpose(v[i]);
+ return r;
+}
+
+// -----------------------------------------------------------------------
+// "dumb" matrix inversion
+template<typename T, size_t N>
+mat<T, N, N> PURE invert(const mat<T, N, N>& src) {
+ T t;
+ size_t swap;
+ mat<T, N, N> tmp(src);
+ mat<T, N, N> inverse(1);
+
+ for (size_t i=0 ; i<N ; i++) {
+ // look for largest element in column
+ swap = i;
+ for (size_t j=i+1 ; j<N ; j++) {
+ if (fabs(tmp[j][i]) > fabs(tmp[i][i])) {
+ swap = j;
+ }
+ }
+
+ if (swap != i) {
+ /* swap rows. */
+ for (size_t k=0 ; k<N ; k++) {
+ t = tmp[i][k];
+ tmp[i][k] = tmp[swap][k];
+ tmp[swap][k] = t;
+
+ t = inverse[i][k];
+ inverse[i][k] = inverse[swap][k];
+ inverse[swap][k] = t;
+ }
+ }
+
+ t = 1 / tmp[i][i];
+ for (size_t k=0 ; k<N ; k++) {
+ tmp[i][k] *= t;
+ inverse[i][k] *= t;
+ }
+ for (size_t j=0 ; j<N ; j++) {
+ if (j != i) {
+ t = tmp[j][i];
+ for (size_t k=0 ; k<N ; k++) {
+ tmp[j][k] -= tmp[i][k] * t;
+ inverse[j][k] -= inverse[i][k] * t;
+ }
+ }
+ }
+ }
+ return inverse;
+}
+
+// -----------------------------------------------------------------------
+
+typedef mat<float, 2, 2> mat22_t;
+typedef mat<float, 3, 3> mat33_t;
+typedef mat<float, 4, 4> mat44_t;
+
+// -----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif /* ANDROID_MAT_H */
diff --git a/services/sensorservice/quat.h b/services/sensorservice/quat.h
new file mode 100644
index 0000000..fea1afe
--- /dev/null
+++ b/services/sensorservice/quat.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2011 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_QUAT_H
+#define ANDROID_QUAT_H
+
+#include <math.h>
+
+#include "vec.h"
+#include "mat.h"
+
+// -----------------------------------------------------------------------
+namespace android {
+// -----------------------------------------------------------------------
+
+template <typename TYPE>
+mat<TYPE, 3, 3> quatToMatrix(const vec<TYPE, 4>& q) {
+ mat<TYPE, 3, 3> R;
+ TYPE q0(q.w);
+ TYPE q1(q.x);
+ TYPE q2(q.y);
+ TYPE q3(q.z);
+ TYPE sq_q1 = 2 * q1 * q1;
+ TYPE sq_q2 = 2 * q2 * q2;
+ TYPE sq_q3 = 2 * q3 * q3;
+ TYPE q1_q2 = 2 * q1 * q2;
+ TYPE q3_q0 = 2 * q3 * q0;
+ TYPE q1_q3 = 2 * q1 * q3;
+ TYPE q2_q0 = 2 * q2 * q0;
+ TYPE q2_q3 = 2 * q2 * q3;
+ TYPE q1_q0 = 2 * q1 * q0;
+ R[0][0] = 1 - sq_q2 - sq_q3;
+ R[0][1] = q1_q2 - q3_q0;
+ R[0][2] = q1_q3 + q2_q0;
+ R[1][0] = q1_q2 + q3_q0;
+ R[1][1] = 1 - sq_q1 - sq_q3;
+ R[1][2] = q2_q3 - q1_q0;
+ R[2][0] = q1_q3 - q2_q0;
+ R[2][1] = q2_q3 + q1_q0;
+ R[2][2] = 1 - sq_q1 - sq_q2;
+ return R;
+}
+
+template <typename TYPE>
+vec<TYPE, 4> matrixToQuat(const mat<TYPE, 3, 3>& R) {
+ // matrix to quaternion
+
+ struct {
+ inline TYPE operator()(TYPE v) {
+ return v < 0 ? 0 : v;
+ }
+ } clamp;
+
+ vec<TYPE, 4> q;
+ const float Hx = R[0].x;
+ const float My = R[1].y;
+ const float Az = R[2].z;
+ q.x = sqrtf( clamp( Hx - My - Az + 1) * 0.25f );
+ q.y = sqrtf( clamp(-Hx + My - Az + 1) * 0.25f );
+ q.z = sqrtf( clamp(-Hx - My + Az + 1) * 0.25f );
+ q.w = sqrtf( clamp( Hx + My + Az + 1) * 0.25f );
+ q.x = copysignf(q.x, R[2].y - R[1].z);
+ q.y = copysignf(q.y, R[0].z - R[2].x);
+ q.z = copysignf(q.z, R[1].x - R[0].y);
+ // guaranteed to be unit-quaternion
+ return q;
+}
+
+template <typename TYPE>
+vec<TYPE, 4> normalize_quat(const vec<TYPE, 4>& q) {
+ vec<TYPE, 4> r(q);
+ if (r.w < 0) {
+ r = -r;
+ }
+ return normalize(r);
+}
+
+// -----------------------------------------------------------------------
+
+typedef vec4_t quat_t;
+
+// -----------------------------------------------------------------------
+}; // namespace android
+
+#endif /* ANDROID_QUAT_H */
diff --git a/services/sensorservice/tests/Android.mk b/services/sensorservice/tests/Android.mk
new file mode 100644
index 0000000..45296dd
--- /dev/null
+++ b/services/sensorservice/tests/Android.mk
@@ -0,0 +1,14 @@
+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)
diff --git a/services/sensorservice/tests/sensorservicetest.cpp b/services/sensorservice/tests/sensorservicetest.cpp
new file mode 100644
index 0000000..1025fa8
--- /dev/null
+++ b/services/sensorservice/tests/sensorservicetest.cpp
@@ -0,0 +1,110 @@
+/*
+ * 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/Looper.h>
+
+using namespace android;
+
+static nsecs_t sStartTime = 0;
+
+
+int receiver(int fd, int events, void* data)
+{
+ sp<SensorEventQueue> q((SensorEventQueue*)data);
+ ssize_t n;
+ ASensorEvent buffer[8];
+
+ static nsecs_t oldTimeStamp = 0;
+
+ while ((n = q->read(buffer, 8)) > 0) {
+ for (int i=0 ; i<n ; i++) {
+ float t;
+ if (oldTimeStamp) {
+ t = float(buffer[i].timestamp - oldTimeStamp) / s2ns(1);
+ } else {
+ t = float(buffer[i].timestamp - sStartTime) / s2ns(1);
+ }
+ oldTimeStamp = buffer[i].timestamp;
+
+ if (buffer[i].type == Sensor::TYPE_ACCELEROMETER) {
+ printf("%lld\t%8f\t%8f\t%8f\t%f\n",
+ buffer[i].timestamp,
+ buffer[i].data[0], buffer[i].data[1], buffer[i].data[2],
+ 1.0/t);
+ }
+
+ }
+ }
+ if (n<0 && n != -EAGAIN) {
+ printf("error reading events (%s)\n", strerror(-n));
+ }
+ return 1;
+}
+
+
+int main(int argc, char** argv)
+{
+ SensorManager& mgr(SensorManager::getInstance());
+
+ Sensor const* const* list;
+ ssize_t count = mgr.getSensorList(&list);
+ printf("numSensors=%d\n", int(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());
+
+ sStartTime = systemTime();
+
+ q->enableSensor(accelerometer);
+
+ q->setEventRate(accelerometer, ms2ns(10));
+
+ sp<Looper> loop = new Looper(false);
+ loop->addFd(q->getFd(), 0, ALOOPER_EVENT_INPUT, receiver, q.get());
+
+ do {
+ //printf("about to poll...\n");
+ int32_t ret = loop->pollOnce(-1);
+ switch (ret) {
+ case ALOOPER_POLL_WAKE:
+ //("ALOOPER_POLL_WAKE\n");
+ break;
+ 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;
+}
diff --git a/services/sensorservice/traits.h b/services/sensorservice/traits.h
new file mode 100644
index 0000000..da4c599
--- /dev/null
+++ b/services/sensorservice/traits.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2011 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_TRAITS_H
+#define ANDROID_TRAITS_H
+
+// -----------------------------------------------------------------------
+// Typelists
+
+namespace android {
+
+// end-of-list marker
+class NullType {};
+
+// type-list node
+template <typename T, typename U>
+struct TypeList {
+ typedef T Head;
+ typedef U Tail;
+};
+
+// helpers to build typelists
+#define TYPELIST_1(T1) TypeList<T1, NullType>
+#define TYPELIST_2(T1, T2) TypeList<T1, TYPELIST_1(T2)>
+#define TYPELIST_3(T1, T2, T3) TypeList<T1, TYPELIST_2(T2, T3)>
+#define TYPELIST_4(T1, T2, T3, T4) TypeList<T1, TYPELIST_3(T2, T3, T4)>
+
+// typelists algorithms
+namespace TL {
+template <typename TList, typename T> struct IndexOf;
+
+template <typename T>
+struct IndexOf<NullType, T> {
+ enum { value = -1 };
+};
+
+template <typename T, typename Tail>
+struct IndexOf<TypeList<T, Tail>, T> {
+ enum { value = 0 };
+};
+
+template <typename Head, typename Tail, typename T>
+struct IndexOf<TypeList<Head, Tail>, T> {
+private:
+ enum { temp = IndexOf<Tail, T>::value };
+public:
+ enum { value = temp == -1 ? -1 : 1 + temp };
+};
+
+}; // namespace TL
+
+// type selection based on a boolean
+template <bool flag, typename T, typename U>
+struct Select {
+ typedef T Result;
+};
+template <typename T, typename U>
+struct Select<false, T, U> {
+ typedef U Result;
+};
+
+// -----------------------------------------------------------------------
+// Type traits
+
+template <typename T>
+class TypeTraits {
+ typedef TYPELIST_4(
+ unsigned char, unsigned short,
+ unsigned int, unsigned long int) UnsignedInts;
+
+ typedef TYPELIST_4(
+ signed char, signed short,
+ signed int, signed long int) SignedInts;
+
+ typedef TYPELIST_1(
+ bool) OtherInts;
+
+ typedef TYPELIST_3(
+ float, double, long double) Floats;
+
+ template<typename U> struct PointerTraits {
+ enum { result = false };
+ typedef NullType PointeeType;
+ };
+ template<typename U> struct PointerTraits<U*> {
+ enum { result = true };
+ typedef U PointeeType;
+ };
+
+public:
+ enum { isStdUnsignedInt = TL::IndexOf<UnsignedInts, T>::value >= 0 };
+ enum { isStdSignedInt = TL::IndexOf<SignedInts, T>::value >= 0 };
+ enum { isStdIntegral = TL::IndexOf<OtherInts, T>::value >= 0 || isStdUnsignedInt || isStdSignedInt };
+ enum { isStdFloat = TL::IndexOf<Floats, T>::value >= 0 };
+ enum { isPointer = PointerTraits<T>::result };
+ enum { isStdArith = isStdIntegral || isStdFloat };
+
+ // best parameter type for given type
+ typedef typename Select<isStdArith || isPointer, T, const T&>::Result ParameterType;
+};
+
+// -----------------------------------------------------------------------
+}; // namespace android
+
+#endif /* ANDROID_TRAITS_H */
diff --git a/services/sensorservice/vec.h b/services/sensorservice/vec.h
new file mode 100644
index 0000000..24f30ff
--- /dev/null
+++ b/services/sensorservice/vec.h
@@ -0,0 +1,438 @@
+/*
+ * Copyright (C) 2011 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_VEC_H
+#define ANDROID_VEC_H
+
+#include <math.h>
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include "traits.h"
+
+// -----------------------------------------------------------------------
+
+#define PURE __attribute__((pure))
+
+namespace android {
+
+// -----------------------------------------------------------------------
+// non-inline helpers
+
+template <typename TYPE, size_t SIZE>
+class vec;
+
+template <typename TYPE, size_t SIZE>
+class vbase;
+
+namespace helpers {
+
+template <typename T> inline T min(T a, T b) { return a<b ? a : b; }
+template <typename T> inline T max(T a, T b) { return a>b ? a : b; }
+
+template < template<typename T, size_t S> class VEC,
+ typename TYPE, size_t SIZE, size_t S>
+vec<TYPE, SIZE>& doAssign(
+ vec<TYPE, SIZE>& lhs, const VEC<TYPE, S>& rhs) {
+ const size_t minSize = min(SIZE, S);
+ const size_t maxSize = max(SIZE, S);
+ for (size_t i=0 ; i<minSize ; i++)
+ lhs[i] = rhs[i];
+ for (size_t i=minSize ; i<maxSize ; i++)
+ lhs[i] = 0;
+ return lhs;
+}
+
+
+template <
+ template<typename T, size_t S> class VLHS,
+ template<typename T, size_t S> class VRHS,
+ typename TYPE,
+ size_t SIZE
+>
+VLHS<TYPE, SIZE> PURE doAdd(
+ const VLHS<TYPE, SIZE>& lhs,
+ const VRHS<TYPE, SIZE>& rhs) {
+ VLHS<TYPE, SIZE> r;
+ for (size_t i=0 ; i<SIZE ; i++)
+ r[i] = lhs[i] + rhs[i];
+ return r;
+}
+
+template <
+ template<typename T, size_t S> class VLHS,
+ template<typename T, size_t S> class VRHS,
+ typename TYPE,
+ size_t SIZE
+>
+VLHS<TYPE, SIZE> PURE doSub(
+ const VLHS<TYPE, SIZE>& lhs,
+ const VRHS<TYPE, SIZE>& rhs) {
+ VLHS<TYPE, SIZE> r;
+ for (size_t i=0 ; i<SIZE ; i++)
+ r[i] = lhs[i] - rhs[i];
+ return r;
+}
+
+template <
+ template<typename T, size_t S> class VEC,
+ typename TYPE,
+ size_t SIZE
+>
+VEC<TYPE, SIZE> PURE doMulScalar(
+ const VEC<TYPE, SIZE>& lhs,
+ typename TypeTraits<TYPE>::ParameterType rhs) {
+ VEC<TYPE, SIZE> r;
+ for (size_t i=0 ; i<SIZE ; i++)
+ r[i] = lhs[i] * rhs;
+ return r;
+}
+
+template <
+ template<typename T, size_t S> class VEC,
+ typename TYPE,
+ size_t SIZE
+>
+VEC<TYPE, SIZE> PURE doScalarMul(
+ typename TypeTraits<TYPE>::ParameterType lhs,
+ const VEC<TYPE, SIZE>& rhs) {
+ VEC<TYPE, SIZE> r;
+ for (size_t i=0 ; i<SIZE ; i++)
+ r[i] = lhs * rhs[i];
+ return r;
+}
+
+}; // namespace helpers
+
+// -----------------------------------------------------------------------
+// Below we define the mathematical operators for vectors.
+// We use template template arguments so we can generically
+// handle the case where the right-hand-size and left-hand-side are
+// different vector types (but with same value_type and size).
+// This is needed for performance when using ".xy{z}" element access
+// on vec<>. Without this, an extra conversion to vec<> would be needed.
+//
+// example:
+// vec4_t a;
+// vec3_t b;
+// vec3_t c = a.xyz + b;
+//
+// "a.xyz + b" is a mixed-operation between a vbase<> and a vec<>, requiring
+// a conversion of vbase<> to vec<>. The template gunk below avoids this,
+// by allowing the addition on these different vector types directly
+//
+
+template <
+ template<typename T, size_t S> class VLHS,
+ template<typename T, size_t S> class VRHS,
+ typename TYPE,
+ size_t SIZE
+>
+inline VLHS<TYPE, SIZE> PURE operator + (
+ const VLHS<TYPE, SIZE>& lhs,
+ const VRHS<TYPE, SIZE>& rhs) {
+ return helpers::doAdd(lhs, rhs);
+}
+
+template <
+ template<typename T, size_t S> class VLHS,
+ template<typename T, size_t S> class VRHS,
+ typename TYPE,
+ size_t SIZE
+>
+inline VLHS<TYPE, SIZE> PURE operator - (
+ const VLHS<TYPE, SIZE>& lhs,
+ const VRHS<TYPE, SIZE>& rhs) {
+ return helpers::doSub(lhs, rhs);
+}
+
+template <
+ template<typename T, size_t S> class VEC,
+ typename TYPE,
+ size_t SIZE
+>
+inline VEC<TYPE, SIZE> PURE operator * (
+ const VEC<TYPE, SIZE>& lhs,
+ typename TypeTraits<TYPE>::ParameterType rhs) {
+ return helpers::doMulScalar(lhs, rhs);
+}
+
+template <
+ template<typename T, size_t S> class VEC,
+ typename TYPE,
+ size_t SIZE
+>
+inline VEC<TYPE, SIZE> PURE operator * (
+ typename TypeTraits<TYPE>::ParameterType lhs,
+ const VEC<TYPE, SIZE>& rhs) {
+ return helpers::doScalarMul(lhs, rhs);
+}
+
+
+template <
+ template<typename T, size_t S> class VLHS,
+ template<typename T, size_t S> class VRHS,
+ typename TYPE,
+ size_t SIZE
+>
+TYPE PURE dot_product(
+ const VLHS<TYPE, SIZE>& lhs,
+ const VRHS<TYPE, SIZE>& rhs) {
+ TYPE r(0);
+ for (size_t i=0 ; i<SIZE ; i++)
+ r += lhs[i] * rhs[i];
+ return r;
+}
+
+template <
+ template<typename T, size_t S> class V,
+ typename TYPE,
+ size_t SIZE
+>
+TYPE PURE length(const V<TYPE, SIZE>& v) {
+ return sqrt(dot_product(v, v));
+}
+
+template <
+ template<typename T, size_t S> class V,
+ typename TYPE,
+ size_t SIZE
+>
+TYPE PURE length_squared(const V<TYPE, SIZE>& v) {
+ return dot_product(v, v);
+}
+
+template <
+ template<typename T, size_t S> class V,
+ typename TYPE,
+ size_t SIZE
+>
+V<TYPE, SIZE> PURE normalize(const V<TYPE, SIZE>& v) {
+ return v * (1/length(v));
+}
+
+template <
+ template<typename T, size_t S> class VLHS,
+ template<typename T, size_t S> class VRHS,
+ typename TYPE
+>
+VLHS<TYPE, 3> PURE cross_product(
+ const VLHS<TYPE, 3>& u,
+ const VRHS<TYPE, 3>& v) {
+ VLHS<TYPE, 3> r;
+ r.x = u.y*v.z - u.z*v.y;
+ r.y = u.z*v.x - u.x*v.z;
+ r.z = u.x*v.y - u.y*v.x;
+ return r;
+}
+
+
+template <typename TYPE, size_t SIZE>
+vec<TYPE, SIZE> PURE operator - (const vec<TYPE, SIZE>& lhs) {
+ vec<TYPE, SIZE> r;
+ for (size_t i=0 ; i<SIZE ; i++)
+ r[i] = -lhs[i];
+ return r;
+}
+
+// -----------------------------------------------------------------------
+
+// This our basic vector type, it just implements the data storage
+// and accessors.
+
+template <typename TYPE, size_t SIZE>
+struct vbase {
+ TYPE v[SIZE];
+ inline const TYPE& operator[](size_t i) const { return v[i]; }
+ inline TYPE& operator[](size_t i) { return v[i]; }
+};
+template<> struct vbase<float, 2> {
+ union {
+ float v[2];
+ struct { float x, y; };
+ struct { float s, t; };
+ };
+ inline const float& operator[](size_t i) const { return v[i]; }
+ inline float& operator[](size_t i) { return v[i]; }
+};
+template<> struct vbase<float, 3> {
+ union {
+ float v[3];
+ struct { float x, y, z; };
+ struct { float s, t, r; };
+ vbase<float, 2> xy;
+ vbase<float, 2> st;
+ };
+ inline const float& operator[](size_t i) const { return v[i]; }
+ inline float& operator[](size_t i) { return v[i]; }
+};
+template<> struct vbase<float, 4> {
+ union {
+ float v[4];
+ struct { float x, y, z, w; };
+ struct { float s, t, r, q; };
+ vbase<float, 3> xyz;
+ vbase<float, 3> str;
+ vbase<float, 2> xy;
+ vbase<float, 2> st;
+ };
+ inline const float& operator[](size_t i) const { return v[i]; }
+ inline float& operator[](size_t i) { return v[i]; }
+};
+
+// -----------------------------------------------------------------------
+
+template <typename TYPE, size_t SIZE>
+class vec : public vbase<TYPE, SIZE>
+{
+ typedef typename TypeTraits<TYPE>::ParameterType pTYPE;
+ typedef vbase<TYPE, SIZE> base;
+
+public:
+ // STL-like interface.
+ typedef TYPE value_type;
+ typedef TYPE& reference;
+ typedef TYPE const& const_reference;
+ typedef size_t size_type;
+
+ typedef TYPE* iterator;
+ typedef TYPE const* const_iterator;
+ iterator begin() { return base::v; }
+ iterator end() { return base::v + SIZE; }
+ const_iterator begin() const { return base::v; }
+ const_iterator end() const { return base::v + SIZE; }
+ size_type size() const { return SIZE; }
+
+ // -----------------------------------------------------------------------
+ // default constructors
+
+ vec() { }
+ vec(const vec& rhs) : base(rhs) { }
+ vec(const base& rhs) : base(rhs) { }
+
+ // -----------------------------------------------------------------------
+ // conversion constructors
+
+ vec(pTYPE rhs) {
+ for (size_t i=0 ; i<SIZE ; i++)
+ base::operator[](i) = rhs;
+ }
+
+ template < template<typename T, size_t S> class VEC, size_t S>
+ explicit vec(const VEC<TYPE, S>& rhs) {
+ helpers::doAssign(*this, rhs);
+ }
+
+ explicit vec(TYPE const* array) {
+ for (size_t i=0 ; i<SIZE ; i++)
+ base::operator[](i) = array[i];
+ }
+
+ // -----------------------------------------------------------------------
+ // Assignment
+
+ vec& operator = (const vec& rhs) {
+ base::operator=(rhs);
+ return *this;
+ }
+
+ vec& operator = (const base& rhs) {
+ base::operator=(rhs);
+ return *this;
+ }
+
+ vec& operator = (pTYPE rhs) {
+ for (size_t i=0 ; i<SIZE ; i++)
+ base::operator[](i) = rhs;
+ return *this;
+ }
+
+ template < template<typename T, size_t S> class VEC, size_t S>
+ vec& operator = (const VEC<TYPE, S>& rhs) {
+ return helpers::doAssign(*this, rhs);
+ }
+
+ // -----------------------------------------------------------------------
+ // operation-assignment
+
+ vec& operator += (const vec& rhs);
+ vec& operator -= (const vec& rhs);
+ vec& operator *= (pTYPE rhs);
+
+ // -----------------------------------------------------------------------
+ // non-member function declaration and definition
+ // NOTE: we declare the non-member function as friend inside the class
+ // so that they are known to the compiler when the class is instantiated.
+ // This helps the compiler doing template argument deduction when the
+ // passed types are not identical. Essentially this helps with
+ // type conversion so that you can multiply a vec<float> by an scalar int
+ // (for instance).
+
+ friend inline vec PURE operator + (const vec& lhs, const vec& rhs) {
+ return helpers::doAdd(lhs, rhs);
+ }
+ friend inline vec PURE operator - (const vec& lhs, const vec& rhs) {
+ return helpers::doSub(lhs, rhs);
+ }
+ friend inline vec PURE operator * (const vec& lhs, pTYPE v) {
+ return helpers::doMulScalar(lhs, v);
+ }
+ friend inline vec PURE operator * (pTYPE v, const vec& rhs) {
+ return helpers::doScalarMul(v, rhs);
+ }
+ friend inline TYPE PURE dot_product(const vec& lhs, const vec& rhs) {
+ return android::dot_product(lhs, rhs);
+ }
+};
+
+// -----------------------------------------------------------------------
+
+template <typename TYPE, size_t SIZE>
+vec<TYPE, SIZE>& vec<TYPE, SIZE>::operator += (const vec<TYPE, SIZE>& rhs) {
+ vec<TYPE, SIZE>& lhs(*this);
+ for (size_t i=0 ; i<SIZE ; i++)
+ lhs[i] += rhs[i];
+ return lhs;
+}
+
+template <typename TYPE, size_t SIZE>
+vec<TYPE, SIZE>& vec<TYPE, SIZE>::operator -= (const vec<TYPE, SIZE>& rhs) {
+ vec<TYPE, SIZE>& lhs(*this);
+ for (size_t i=0 ; i<SIZE ; i++)
+ lhs[i] -= rhs[i];
+ return lhs;
+}
+
+template <typename TYPE, size_t SIZE>
+vec<TYPE, SIZE>& vec<TYPE, SIZE>::operator *= (vec<TYPE, SIZE>::pTYPE rhs) {
+ vec<TYPE, SIZE>& lhs(*this);
+ for (size_t i=0 ; i<SIZE ; i++)
+ lhs[i] *= rhs;
+ return lhs;
+}
+
+// -----------------------------------------------------------------------
+
+typedef vec<float, 2> vec2_t;
+typedef vec<float, 3> vec3_t;
+typedef vec<float, 4> vec4_t;
+
+// -----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif /* ANDROID_VEC_H */
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index f4bf9ef..e4fd291 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -3,12 +3,12 @@
LOCAL_SRC_FILES:= \
Client.cpp \
+ DisplayHardware.cpp \
EventThread.cpp \
Layer.cpp \
LayerBase.cpp \
LayerDim.cpp \
LayerScreenshot.cpp \
- DisplayHardware/DisplayHardware.cpp \
DisplayHardware/DisplayHardwareBase.cpp \
DisplayHardware/FramebufferSurface.cpp \
DisplayHardware/HWComposer.cpp \
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware.cpp
similarity index 81%
rename from services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
rename to services/surfaceflinger/DisplayHardware.cpp
index e1c4f62..eac9e04 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/services/surfaceflinger/DisplayHardware.cpp
@@ -30,14 +30,14 @@
#include <EGL/egl.h>
#include <EGL/eglext.h>
-#include "DisplayHardware/DisplayHardware.h"
-#include "DisplayHardware/FramebufferSurface.h"
-
#include <hardware/gralloc.h>
-#include "DisplayHardwareBase.h"
+#include "DisplayHardware/FramebufferSurface.h"
+#include "DisplayHardware/DisplayHardwareBase.h"
+#include "DisplayHardware/HWComposer.h"
+
+#include "DisplayHardware.h"
#include "GLExtensions.h"
-#include "HWComposer.h"
#include "SurfaceFlinger.h"
using namespace android;
@@ -111,8 +111,8 @@
float DisplayHardware::getDpiY() const { return mDpiY; }
float DisplayHardware::getDensity() const { return mDensity; }
float DisplayHardware::getRefreshRate() const { return mRefreshRate; }
-int DisplayHardware::getWidth() const { return mWidth; }
-int DisplayHardware::getHeight() const { return mHeight; }
+int DisplayHardware::getWidth() const { return mDisplayWidth; }
+int DisplayHardware::getHeight() const { return mDisplayHeight; }
PixelFormat DisplayHardware::getFormat() const { return mFormat; }
uint32_t DisplayHardware::getMaxTextureSize() const { return mMaxTextureSize; }
@@ -224,21 +224,11 @@
// initialize EGL
EGLint attribs[] = {
- EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
- EGL_NONE, 0,
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RECORDABLE_ANDROID, EGL_TRUE,
EGL_NONE
};
- // debug: disable h/w rendering
- char property[PROPERTY_VALUE_MAX];
- if (property_get("debug.sf.hw", property, NULL) > 0) {
- if (atoi(property) == 0) {
- ALOGW("H/W composition disabled");
- attribs[2] = EGL_CONFIG_CAVEAT;
- attribs[3] = EGL_SLOW_CONFIG;
- }
- }
-
// TODO: all the extensions below should be queried through
// eglGetProcAddress().
@@ -248,6 +238,13 @@
EGLConfig config = NULL;
err = selectConfigForPixelFormat(display, attribs, format, &config);
+ if (err) {
+ // maybe we failed because of EGL_RECORDABLE_ANDROID
+ ALOGW("couldn't find an EGLConfig with EGL_RECORDABLE_ANDROID");
+ attribs[2] = EGL_NONE;
+ err = selectConfigForPixelFormat(display, attribs, format, &config);
+ }
+
ALOGE_IF(err, "couldn't find an EGLConfig matching the screen format");
EGLint r,g,b,a;
@@ -270,8 +267,8 @@
*/
surface = eglCreateWindowSurface(display, config, mNativeWindow.get(), NULL);
- eglQuerySurface(display, surface, EGL_WIDTH, &mWidth);
- eglQuerySurface(display, surface, EGL_HEIGHT, &mHeight);
+ eglQuerySurface(display, surface, EGL_WIDTH, &mDisplayWidth);
+ eglQuerySurface(display, surface, EGL_HEIGHT, &mDisplayHeight);
if (mFlags & PARTIAL_UPDATES) {
// if we have partial updates, we definitely don't need to
@@ -351,6 +348,36 @@
if (mHwc->initCheck() == NO_ERROR) {
mHwc->setFrameBuffer(mDisplay, mSurface);
}
+
+
+ // initialize the display orientation transform.
+ // it's a constant that should come from the display driver.
+ int displayOrientation = ISurfaceComposer::eOrientationDefault;
+ char property[PROPERTY_VALUE_MAX];
+ if (property_get("ro.sf.hwrotation", property, NULL) > 0) {
+ //displayOrientation
+ switch (atoi(property)) {
+ case 90:
+ displayOrientation = ISurfaceComposer::eOrientation90;
+ break;
+ case 270:
+ displayOrientation = ISurfaceComposer::eOrientation270;
+ break;
+ }
+ }
+
+ w = mDisplayWidth;
+ h = mDisplayHeight;
+ DisplayHardware::orientationToTransfrom(displayOrientation, w, h,
+ &mDisplayTransform);
+ if (displayOrientation & ISurfaceComposer::eOrientationSwapMask) {
+ mLogicalDisplayWidth = h;
+ mLogicalDisplayHeight = w;
+ } else {
+ mLogicalDisplayWidth = w;
+ mLogicalDisplayHeight = h;
+ }
+ DisplayHardware::setOrientation(ISurfaceComposer::eOrientationDefault);
}
void DisplayHardware::setVSyncHandler(const sp<VSyncHandler>& handler) {
@@ -479,3 +506,52 @@
{
mNativeWindow->dump(res);
}
+
+// ----------------------------------------------------------------------------
+
+status_t DisplayHardware::orientationToTransfrom(
+ int orientation, int w, int h, Transform* tr)
+{
+ uint32_t flags = 0;
+ switch (orientation) {
+ case ISurfaceComposer::eOrientationDefault:
+ flags = Transform::ROT_0;
+ break;
+ case ISurfaceComposer::eOrientation90:
+ flags = Transform::ROT_90;
+ break;
+ case ISurfaceComposer::eOrientation180:
+ flags = Transform::ROT_180;
+ break;
+ case ISurfaceComposer::eOrientation270:
+ flags = Transform::ROT_270;
+ break;
+ default:
+ return BAD_VALUE;
+ }
+ tr->set(flags, w, h);
+ return NO_ERROR;
+}
+
+status_t DisplayHardware::setOrientation(int orientation)
+{
+ // If the rotation can be handled in hardware, this is where
+ // the magic should happen.
+
+ const int w = mLogicalDisplayWidth;
+ const int h = mLogicalDisplayHeight;
+ mUserDisplayWidth = w;
+ mUserDisplayHeight = h;
+
+ Transform orientationTransform;
+ DisplayHardware::orientationToTransfrom(orientation, w, h,
+ &orientationTransform);
+ if (orientation & ISurfaceComposer::eOrientationSwapMask) {
+ mUserDisplayWidth = h;
+ mUserDisplayHeight = w;
+ }
+
+ mOrientation = orientation;
+ mGlobalTransform = mDisplayTransform * orientationTransform;
+ return NO_ERROR;
+}
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.h b/services/surfaceflinger/DisplayHardware.h
similarity index 76%
rename from services/surfaceflinger/DisplayHardware/DisplayHardware.h
rename to services/surfaceflinger/DisplayHardware.h
index f029a0a..3da9f16 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/services/surfaceflinger/DisplayHardware.h
@@ -28,10 +28,11 @@
#include <EGL/eglext.h>
#include "GLExtensions.h"
+#include "Transform.h"
#include "DisplayHardware/DisplayHardwareBase.h"
-#include "HWComposer.h"
-#include "PowerHAL.h"
+#include "DisplayHardware/HWComposer.h"
+#include "DisplayHardware/PowerHAL.h"
namespace android {
@@ -84,6 +85,11 @@
nsecs_t getRefreshTimestamp() const;
void makeCurrent() const;
+ status_t setOrientation(int orientation);
+ int getOrientation() const { return mOrientation; }
+ const Transform& getTransform() const { return mGlobalTransform; }
+ int getUserWidth() const { return mUserDisplayWidth; }
+ int getUserHeight() const { return mUserDisplayHeight; }
void setVSyncHandler(const sp<VSyncHandler>& handler);
@@ -96,6 +102,7 @@
uint32_t getPageFlipCount() const;
EGLDisplay getEGLDisplay() const { return mDisplay; }
+ EGLConfig getEGLConfig() const { return mConfig; }
void dump(String8& res) const;
@@ -105,14 +112,14 @@
status_t compositionComplete() const;
Rect getBounds() const {
- return Rect(mWidth, mHeight);
+ return Rect(mDisplayWidth, mDisplayHeight);
}
inline Rect bounds() const { return getBounds(); }
private:
virtual void onVSyncReceived(int dpy, nsecs_t timestamp);
- void init(uint32_t displayIndex) __attribute__((noinline));
- void fini() __attribute__((noinline));
+ void init(uint32_t displayIndex);
+ void fini();
sp<SurfaceFlinger> mFlinger;
EGLDisplay mDisplay;
@@ -123,8 +130,8 @@
float mDpiY;
float mRefreshRate;
float mDensity;
- int mWidth;
- int mHeight;
+ int mDisplayWidth;
+ int mDisplayHeight;
PixelFormat mFormat;
uint32_t mFlags;
mutable uint32_t mPageFlipCount;
@@ -139,6 +146,18 @@
PowerHAL mPowerHAL;
+ // this used to be in GraphicPlane
+ static status_t orientationToTransfrom(int orientation, int w, int h,
+ Transform* tr);
+ Transform mGlobalTransform;
+ Transform mDisplayTransform;
+ int mOrientation;
+ int mLogicalDisplayWidth;
+ int mLogicalDisplayHeight;
+ int mUserDisplayWidth;
+ int mUserDisplayHeight;
+
+
mutable Mutex mLock;
// protected by mLock
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 02d2b10..6cfb190 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -106,6 +106,16 @@
if (item.mGraphicBuffer != 0) {
self->mBuffers[item.mBuf] = item.mGraphicBuffer;
}
+ if (item.mFence.get()) {
+ err = item.mFence->wait(Fence::TIMEOUT_NEVER);
+ if (err) {
+ ALOGE("failed waiting for buffer's fence: %d", err);
+ self->mBufferQueue->releaseBuffer(item.mBuf,
+ EGL_NO_DISPLAY, EGL_NO_SYNC_KHR,
+ item.mFence);
+ return;
+ }
+ }
self->fbDev->post(self->fbDev, self->mBuffers[item.mBuf]->handle);
if (self->mCurrentBufferIndex >= 0) {
self->mBufferQueue->releaseBuffer(self->mCurrentBufferIndex,
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 7c09ab2..4ed692f 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -350,6 +350,12 @@
// not supported on VERSION_03
return -1;
}
+ virtual void setAcquireFenceFd(int fenceFd) {
+ if (fenceFd != -1) {
+ ALOGE("HWC 0.x can't handle acquire fences");
+ close(fenceFd);
+ }
+ }
virtual void setDefaultState() {
getLayer()->compositionType = HWC_FRAMEBUFFER;
@@ -416,6 +422,9 @@
getLayer()->releaseFenceFd = -1;
return fd;
}
+ virtual void setAcquireFenceFd(int fenceFd) {
+ getLayer()->acquireFenceFd = fenceFd;
+ }
virtual void setDefaultState() {
getLayer()->compositionType = HWC_FRAMEBUFFER;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index cb4c2db..a662b25 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -109,6 +109,7 @@
virtual void setCrop(const Rect& crop) = 0;
virtual void setVisibleRegionScreen(const Region& reg) = 0;
virtual void setBuffer(const sp<GraphicBuffer>& buffer) = 0;
+ virtual void setAcquireFenceFd(int fenceFd) = 0;
};
/*
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
index 7c1aebe..0f11377 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/EventThread.cpp
@@ -26,7 +26,7 @@
#include <utils/Errors.h>
#include <utils/Trace.h>
-#include "DisplayHardware/DisplayHardware.h"
+#include "DisplayHardware.h"
#include "EventThread.h"
#include "SurfaceFlinger.h"
@@ -38,7 +38,7 @@
EventThread::EventThread(const sp<SurfaceFlinger>& flinger)
: mFlinger(flinger),
- mHw(flinger->graphicPlane(0).editDisplayHardware()),
+ mHw(const_cast<DisplayHardware&>(flinger->getDefaultDisplayHardware())), // XXX: eventthread will need rework
mLastVSyncTimestamp(0),
mVSyncTimestamp(0),
mUseSoftwareVSync(false),
diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h
index b42cab6..04c8f53 100644
--- a/services/surfaceflinger/EventThread.h
+++ b/services/surfaceflinger/EventThread.h
@@ -27,7 +27,7 @@
#include <utils/threads.h>
#include <utils/SortedVector.h>
-#include "DisplayHardware/DisplayHardware.h"
+#include "DisplayHardware.h"
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 64e4b5f..0d1cb45 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -36,13 +36,14 @@
#include <gui/Surface.h>
#include "clz.h"
-#include "DisplayHardware/DisplayHardware.h"
-#include "DisplayHardware/HWComposer.h"
+#include "DisplayHardware.h"
#include "GLExtensions.h"
#include "Layer.h"
#include "SurfaceFlinger.h"
#include "SurfaceTextureLayer.h"
+#include "DisplayHardware/HWComposer.h"
+
#define DEBUG_RESIZE 0
namespace android {
@@ -59,11 +60,11 @@
mCurrentOpacity(true),
mRefreshPending(false),
mFrameLatencyNeeded(false),
+ mNeedHwcFence(false),
mFrameLatencyOffset(0),
mFormat(PIXEL_FORMAT_NONE),
mGLExtensions(GLExtensions::getInstance()),
mOpaqueLayer(true),
- mNeedsDithering(false),
mSecure(false),
mProtectedByApp(false)
{
@@ -77,7 +78,9 @@
}
if (mFrameLatencyNeeded) {
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ // we need a DisplayHardware for debugging only right now
+ // XXX: should this be called per DisplayHardware?
+ const DisplayHardware& hw(mFlinger->getDefaultDisplayHardware());
mFrameStats[mFrameLatencyOffset].timestamp = mSurfaceTexture->getTimestamp();
mFrameStats[mFrameLatencyOffset].set = systemTime();
mFrameStats[mFrameLatencyOffset].vsync = hw.getRefreshTimestamp();
@@ -142,8 +145,8 @@
mSurfaceTexture->setName(name);
}
-void Layer::validateVisibility(const Transform& globalTransform) {
- LayerBase::validateVisibility(globalTransform);
+void Layer::validateVisibility(const Transform& globalTransform, const DisplayHardware& hw) {
+ LayerBase::validateVisibility(globalTransform, hw);
// This optimization allows the SurfaceTexture to bake in
// the rotation so hardware overlays can be used
@@ -188,7 +191,8 @@
}
// the display's pixel format
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ // XXX: we shouldn't rely on the DisplayHardware to do this
+ const DisplayHardware& hw(mFlinger->getDefaultDisplayHardware());
uint32_t const maxSurfaceDims = min(
hw.getMaxTextureSize(), hw.getMaxViewportDims());
@@ -199,10 +203,6 @@
return BAD_VALUE;
}
- PixelFormatInfo displayInfo;
- getPixelFormatInfo(hw.getFormat(), &displayInfo);
- const uint32_t hwFlags = hw.getFlags();
-
mFormat = format;
mSecure = (flags & ISurfaceComposer::eSecure) ? true : false;
@@ -214,11 +214,6 @@
mSurfaceTexture->setDefaultBufferFormat(format);
mSurfaceTexture->setConsumerUsageBits(getEffectiveUsage(0));
- // we use the red index
- int displayRedSize = displayInfo.getSize(PixelFormatInfo::INDEX_RED);
- int layerRedsize = info.getSize(PixelFormatInfo::INDEX_RED);
- mNeedsDithering = layerRedsize > displayRedSize;
-
return NO_ERROR;
}
@@ -307,7 +302,22 @@
layer.setBuffer(buffer);
}
-void Layer::onDraw(const Region& clip) const
+void Layer::setAcquireFence(HWComposer::HWCLayerInterface& layer) {
+ int fenceFd = -1;
+ if (mNeedHwcFence) {
+ sp<Fence> fence = mSurfaceTexture->getCurrentFence();
+ if (fence.get()) {
+ fenceFd = fence->dup();
+ if (fenceFd == -1) {
+ ALOGW("failed to dup layer fence, skipping sync: %d", errno);
+ }
+ }
+ mNeedHwcFence = false;
+ }
+ layer.setAcquireFenceFd(fenceFd);
+}
+
+void Layer::onDraw(const DisplayHardware& hw, const Region& clip) const
{
ATRACE_CALL();
@@ -334,11 +344,20 @@
// if not everything below us is covered, we plug the holes!
Region holes(clip.subtract(under));
if (!holes.isEmpty()) {
- clearWithOpenGL(holes, 0, 0, 0, 1);
+ clearWithOpenGL(hw, holes, 0, 0, 0, 1);
}
return;
}
+ // TODO: replace this with a server-side wait
+ sp<Fence> fence = mSurfaceTexture->getCurrentFence();
+ if (fence.get()) {
+ status_t err = fence->wait(Fence::TIMEOUT_NEVER);
+ ALOGW_IF(err != OK, "Layer::onDraw: failed waiting for fence: %d", err);
+ // Go ahead and draw the buffer anyway; no matter what we do the screen
+ // is probably going to have something visibly wrong.
+ }
+
if (!isProtected()) {
// TODO: we could be more subtle with isFixedSize()
const bool useFiltering = getFiltering() || needsFiltering() || isFixedSize();
@@ -370,7 +389,7 @@
glEnable(GL_TEXTURE_2D);
}
- drawWithOpenGL(clip);
+ drawWithOpenGL(hw, clip);
glDisable(GL_TEXTURE_EXTERNAL_OES);
glDisable(GL_TEXTURE_2D);
@@ -633,6 +652,7 @@
mRefreshPending = true;
mFrameLatencyNeeded = true;
+ mNeedHwcFence = true;
if (oldActiveBuffer == NULL) {
// the first time we receive a buffer, we need to trigger a
// geometry invalidation.
@@ -730,7 +750,7 @@
{
LayerBaseClient::dumpStats(result, buffer, SIZE);
const size_t o = mFrameLatencyOffset;
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ const DisplayHardware& hw(mFlinger->getDefaultDisplayHardware());
const nsecs_t period = hw.getRefreshPeriod();
result.appendFormat("%lld\n", period);
for (size_t i=0 ; i<128 ; i++) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 32456f4..b6ae0ae 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -66,18 +66,18 @@
// LayerBase interface
virtual void setGeometry(HWComposer::HWCLayerInterface& layer);
virtual void setPerFrameData(HWComposer::HWCLayerInterface& layer);
- virtual void onDraw(const Region& clip) const;
+ virtual void setAcquireFence(HWComposer::HWCLayerInterface& layer);
+ virtual void onDraw(const DisplayHardware& hw, const Region& clip) const;
virtual uint32_t doTransaction(uint32_t transactionFlags);
virtual void lockPageFlip(bool& recomputeVisibleRegions);
virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
virtual bool isOpaque() const;
- virtual bool needsDithering() const { return mNeedsDithering; }
virtual bool isSecure() const { return mSecure; }
virtual bool isProtected() const;
virtual void onRemoved();
virtual sp<Layer> getLayer() const { return const_cast<Layer*>(this); }
virtual void setName(const String8& name);
- virtual void validateVisibility(const Transform& globalTransform);
+ virtual void validateVisibility(const Transform& globalTransform, const DisplayHardware& hw);
// LayerBaseClient interface
virtual wp<IBinder> getSurfaceTextureBinder() const;
@@ -121,6 +121,7 @@
bool mCurrentOpacity;
bool mRefreshPending;
bool mFrameLatencyNeeded;
+ bool mNeedHwcFence;
int mFrameLatencyOffset;
struct Statistics {
@@ -137,7 +138,6 @@
PixelFormat mFormat;
const GLExtensions& mGLExtensions;
bool mOpaqueLayer;
- bool mNeedsDithering;
// page-flip thread (currently main thread)
bool mSecure; // no screenshots
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index 893dcb9..8350d27 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -32,7 +32,7 @@
#include "Client.h"
#include "LayerBase.h"
#include "SurfaceFlinger.h"
-#include "DisplayHardware/DisplayHardware.h"
+#include "DisplayHardware.h"
namespace android {
@@ -50,8 +50,6 @@
mTransactionFlags(0),
mPremultipliedAlpha(true), mName("unnamed"), mDebug(false)
{
- const DisplayHardware& hw(flinger->graphicPlane(0).displayHardware());
- mFlags = hw.getFlags();
}
LayerBase::~LayerBase()
@@ -66,16 +64,6 @@
return mName;
}
-const GraphicPlane& LayerBase::graphicPlane(int dpy) const
-{
- return mFlinger->graphicPlane(dpy);
-}
-
-GraphicPlane& LayerBase::graphicPlane(int dpy)
-{
- return mFlinger->graphicPlane(dpy);
-}
-
void LayerBase::initStates(uint32_t w, uint32_t h, uint32_t flags)
{
uint32_t layerFlags = 0;
@@ -231,12 +219,11 @@
return flags;
}
-void LayerBase::validateVisibility(const Transform& planeTransform)
+void LayerBase::validateVisibility(const Transform& planeTransform, const DisplayHardware& hw)
{
const Layer::State& s(drawingState());
const Transform tr(planeTransform * s.transform);
const bool transformed = tr.transformed();
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
const uint32_t hw_h = hw.getHeight();
const Rect& crop(s.active.crop);
@@ -312,6 +299,10 @@
layer.setBuffer(0);
}
+void LayerBase::setAcquireFence(HWComposer::HWCLayerInterface& layer) {
+ layer.setAcquireFenceFd(-1);
+}
+
void LayerBase::setFiltering(bool filtering)
{
mFiltering = filtering;
@@ -322,24 +313,21 @@
return mFiltering;
}
-void LayerBase::draw(const Region& clip) const
+void LayerBase::draw(const DisplayHardware& hw, const Region& clip) const
{
- onDraw(clip);
+ onDraw(hw, clip);
}
-void LayerBase::drawForSreenShot()
+void LayerBase::drawForSreenShot(const DisplayHardware& hw)
{
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
setFiltering(true);
- onDraw( Region(hw.bounds()) );
+ onDraw( hw, Region(hw.bounds()) );
setFiltering(false);
}
-void LayerBase::clearWithOpenGL(const Region& clip, GLclampf red,
- GLclampf green, GLclampf blue,
- GLclampf alpha) const
+void LayerBase::clearWithOpenGL(const DisplayHardware& hw, const Region& clip,
+ GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) const
{
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
const uint32_t fbHeight = hw.getHeight();
glColor4f(red,green,blue,alpha);
@@ -351,14 +339,13 @@
glDrawArrays(GL_TRIANGLE_FAN, 0, mNumVertices);
}
-void LayerBase::clearWithOpenGL(const Region& clip) const
+void LayerBase::clearWithOpenGL(const DisplayHardware& hw, const Region& clip) const
{
- clearWithOpenGL(clip,0,0,0,0);
+ clearWithOpenGL(hw, clip, 0,0,0,0);
}
-void LayerBase::drawWithOpenGL(const Region& clip) const
+void LayerBase::drawWithOpenGL(const DisplayHardware& hw, const Region& clip) const
{
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
const uint32_t fbHeight = hw.getHeight();
const State& s(drawingState());
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index 698cdb8..83e871c 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -32,7 +32,7 @@
#include <private/gui/LayerState.h>
-#include "DisplayHardware/DisplayHardware.h"
+#include "DisplayHardware.h"
#include "Transform.h"
namespace android {
@@ -42,7 +42,6 @@
class Client;
class DisplayHardware;
class GraphicBuffer;
-class GraphicPlane;
class Layer;
class LayerBaseClient;
class SurfaceFlinger;
@@ -116,7 +115,7 @@
virtual void setGeometry(HWComposer::HWCLayerInterface& layer);
virtual void setPerFrameData(HWComposer::HWCLayerInterface& layer);
-
+ virtual void setAcquireFence(HWComposer::HWCLayerInterface& layer);
/**
* draw - performs some global clipping optimizations
@@ -124,13 +123,13 @@
* Typically this method is not overridden, instead implement onDraw()
* to perform the actual drawing.
*/
- virtual void draw(const Region& clip) const;
- virtual void drawForSreenShot();
+ virtual void draw(const DisplayHardware& hw, const Region& clip) const;
+ virtual void drawForSreenShot(const DisplayHardware& hw);
/**
* onDraw - draws the surface.
*/
- virtual void onDraw(const Region& clip) const = 0;
+ virtual void onDraw(const DisplayHardware& hw, const Region& clip) const = 0;
/**
* initStates - called just after construction
@@ -159,7 +158,7 @@
/**
* validateVisibility - cache a bunch of things
*/
- virtual void validateVisibility(const Transform& globalTransform);
+ virtual void validateVisibility(const Transform& globalTransform, const DisplayHardware& hw);
/**
* lockPageFlip - called each time the screen is redrawn and returns whether
@@ -237,21 +236,17 @@
int32_t getOrientation() const { return mOrientation; }
int32_t getPlaneOrientation() const { return mPlaneOrientation; }
- void clearWithOpenGL(const Region& clip) const;
+ void clearWithOpenGL(const DisplayHardware& hw, const Region& clip) const;
protected:
- const GraphicPlane& graphicPlane(int dpy) const;
- GraphicPlane& graphicPlane(int dpy);
-
- void clearWithOpenGL(const Region& clip, GLclampf r, GLclampf g,
- GLclampf b, GLclampf alpha) const;
- void drawWithOpenGL(const Region& clip) const;
+ void clearWithOpenGL(const DisplayHardware& hw, const Region& clip,
+ GLclampf r, GLclampf g, GLclampf b, GLclampf alpha) const;
+ void drawWithOpenGL(const DisplayHardware& hw, const Region& clip) const;
void setFiltering(bool filtering);
bool getFiltering() const;
sp<SurfaceFlinger> mFlinger;
- uint32_t mFlags;
private:
// accessed only in the main thread
diff --git a/services/surfaceflinger/LayerDim.cpp b/services/surfaceflinger/LayerDim.cpp
index 96a310f..ceead45 100644
--- a/services/surfaceflinger/LayerDim.cpp
+++ b/services/surfaceflinger/LayerDim.cpp
@@ -25,7 +25,7 @@
#include "LayerDim.h"
#include "SurfaceFlinger.h"
-#include "DisplayHardware/DisplayHardware.h"
+#include "DisplayHardware.h"
namespace android {
// ---------------------------------------------------------------------------
@@ -40,11 +40,10 @@
{
}
-void LayerDim::onDraw(const Region& clip) const
+void LayerDim::onDraw(const DisplayHardware& hw, const Region& clip) const
{
const State& s(drawingState());
if (s.alpha>0) {
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
const GLfloat alpha = s.alpha/255.0f;
const uint32_t fbHeight = hw.getHeight();
glDisable(GL_TEXTURE_EXTERNAL_OES);
diff --git a/services/surfaceflinger/LayerDim.h b/services/surfaceflinger/LayerDim.h
index 8770e6d..2d9eaef 100644
--- a/services/surfaceflinger/LayerDim.h
+++ b/services/surfaceflinger/LayerDim.h
@@ -36,7 +36,7 @@
const sp<Client>& client);
virtual ~LayerDim();
- virtual void onDraw(const Region& clip) const;
+ virtual void onDraw(const DisplayHardware& hw, const Region& clip) const;
virtual bool isOpaque() const { return false; }
virtual bool isSecure() const { return false; }
virtual bool isProtectedByApp() const { return false; }
diff --git a/services/surfaceflinger/LayerScreenshot.cpp b/services/surfaceflinger/LayerScreenshot.cpp
index b42353c..d046879 100644
--- a/services/surfaceflinger/LayerScreenshot.cpp
+++ b/services/surfaceflinger/LayerScreenshot.cpp
@@ -25,7 +25,7 @@
#include "LayerScreenshot.h"
#include "SurfaceFlinger.h"
-#include "DisplayHardware/DisplayHardware.h"
+#include "DisplayHardware.h"
namespace android {
@@ -106,11 +106,10 @@
return LayerBaseClient::doTransaction(flags);
}
-void LayerScreenshot::onDraw(const Region& clip) const
+void LayerScreenshot::onDraw(const DisplayHardware& hw, const Region& clip) const
{
const State& s(drawingState());
if (s.alpha>0) {
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
const GLfloat alpha = s.alpha/255.0f;
const uint32_t fbHeight = hw.getHeight();
diff --git a/services/surfaceflinger/LayerScreenshot.h b/services/surfaceflinger/LayerScreenshot.h
index ab90047..0ddb376 100644
--- a/services/surfaceflinger/LayerScreenshot.h
+++ b/services/surfaceflinger/LayerScreenshot.h
@@ -43,7 +43,7 @@
virtual void initStates(uint32_t w, uint32_t h, uint32_t flags);
virtual uint32_t doTransaction(uint32_t flags);
- virtual void onDraw(const Region& clip) const;
+ virtual void onDraw(const DisplayHardware& hw, const Region& clip) const;
virtual bool isOpaque() const { return false; }
virtual bool isSecure() const { return false; }
virtual bool isProtectedByApp() const { return false; }
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 981d694..3b2bf00 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -50,6 +50,7 @@
#include "clz.h"
#include "DdmConnection.h"
+#include "DisplayHardware.h"
#include "Client.h"
#include "EventThread.h"
#include "GLExtensions.h"
@@ -58,12 +59,12 @@
#include "LayerScreenshot.h"
#include "SurfaceFlinger.h"
-#include "DisplayHardware/DisplayHardware.h"
#include "DisplayHardware/HWComposer.h"
#include <private/android_filesystem_config.h>
#include <private/gui/SharedBufferStack.h>
#include <gui/BitTube.h>
+#include <gui/SurfaceTextureClient.h>
#define EGL_VERSION_HW_ANDROID 0x3143
@@ -97,7 +98,8 @@
mDebugInTransaction(0),
mLastTransactionTime(0),
mBootFinished(false),
- mSecureFrameBuffer(0)
+ mSecureFrameBuffer(0),
+ mExternalDisplaySurface(EGL_NO_SURFACE)
{
init();
}
@@ -176,19 +178,6 @@
return gba;
}
-const GraphicPlane& SurfaceFlinger::graphicPlane(int dpy) const
-{
- ALOGE_IF(uint32_t(dpy) >= DISPLAY_COUNT, "Invalid DisplayID %d", dpy);
- const GraphicPlane& plane(mGraphicPlanes[dpy]);
- return plane;
-}
-
-GraphicPlane& SurfaceFlinger::graphicPlane(int dpy)
-{
- return const_cast<GraphicPlane&>(
- const_cast<SurfaceFlinger const *>(this)->graphicPlane(dpy));
-}
-
void SurfaceFlinger::bootFinished()
{
const nsecs_t now = systemTime();
@@ -215,7 +204,7 @@
status_t SurfaceFlinger::readyToRun()
{
- ALOGI( "SurfaceFlinger's main thread ready to run. "
+ ALOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
// we only support one display currently
@@ -223,9 +212,9 @@
{
// initialize the main display
- GraphicPlane& plane(graphicPlane(dpy));
+ // TODO: initialize all displays
DisplayHardware* const hw = new DisplayHardware(this, dpy);
- plane.setDisplayHardware(hw);
+ mDisplayHardwares[0] = hw;
}
// create the shared control-block
@@ -242,8 +231,7 @@
// (other display should be initialized in the same manner, but
// asynchronously, as they could come and go. None of this is supported
// yet).
- const GraphicPlane& plane(graphicPlane(dpy));
- const DisplayHardware& hw = plane.displayHardware();
+ const DisplayHardware& hw(getDefaultDisplayHardware());
const uint32_t w = hw.getWidth();
const uint32_t h = hw.getHeight();
const uint32_t f = hw.getFormat();
@@ -253,8 +241,8 @@
mServerCblk->connected |= 1<<dpy;
display_cblk_t* dcblk = mServerCblk->displays + dpy;
memset(dcblk, 0, sizeof(display_cblk_t));
- dcblk->w = plane.getWidth();
- dcblk->h = plane.getHeight();
+ dcblk->w = w; // XXX: plane.getWidth();
+ dcblk->h = h; // XXX: plane.getHeight();
dcblk->format = f;
dcblk->orientation = ISurfaceComposer::eOrientationDefault;
dcblk->xdpi = hw.getDpiX();
@@ -370,6 +358,41 @@
return mEventThread->createEventConnection();
}
+void SurfaceFlinger::connectDisplay(const sp<ISurfaceTexture> display) {
+ const DisplayHardware& hw(getDefaultDisplayHardware());
+ EGLSurface result = EGL_NO_SURFACE;
+ EGLSurface old_surface = EGL_NO_SURFACE;
+ sp<SurfaceTextureClient> stc;
+
+ if (display != NULL) {
+ stc = new SurfaceTextureClient(display);
+ result = eglCreateWindowSurface(hw.getEGLDisplay(),
+ hw.getEGLConfig(), (EGLNativeWindowType)stc.get(), NULL);
+ ALOGE_IF(result == EGL_NO_SURFACE,
+ "eglCreateWindowSurface failed (ISurfaceTexture=%p)",
+ display.get());
+ }
+
+ { // scope for the lock
+ Mutex::Autolock _l(mStateLock);
+ old_surface = mExternalDisplaySurface;
+ mExternalDisplayNativeWindow = stc;
+ mExternalDisplaySurface = result;
+ ALOGD("mExternalDisplaySurface = %p", result);
+ }
+
+ if (old_surface != EGL_NO_SURFACE) {
+ // Note: EGL allows to destroy an object while its current
+ // it will fail to become current next time though.
+ eglDestroySurface(hw.getEGLDisplay(), old_surface);
+ }
+}
+
+EGLSurface SurfaceFlinger::getExternalDisplaySurface() const {
+ Mutex::Autolock _l(mStateLock);
+ return mExternalDisplaySurface;
+}
+
// ----------------------------------------------------------------------------
void SurfaceFlinger::waitForEvent() {
@@ -432,7 +455,8 @@
handleRefresh();
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ // TODO: iterate through all displays
+ const DisplayHardware& hw(getDisplayHardware(0));
// if (mDirtyRegion.isEmpty()) {
// return;
@@ -440,12 +464,12 @@
if (CC_UNLIKELY(mHwWorkListDirty)) {
// build the h/w work list
- handleWorkList();
+ handleWorkList(hw);
}
if (CC_LIKELY(hw.canDraw())) {
// repaint the framebuffer (if needed)
- handleRepaint();
+ handleRepaint(hw);
// inform the h/w that we're done compositing
hw.compositionComplete();
postFramebuffer();
@@ -454,6 +478,43 @@
hw.compositionComplete();
}
+ // render to the external display if we have one
+ EGLSurface externalDisplaySurface = getExternalDisplaySurface();
+ if (externalDisplaySurface != EGL_NO_SURFACE) {
+ EGLSurface cur = eglGetCurrentSurface(EGL_DRAW);
+ EGLBoolean success = eglMakeCurrent(eglGetCurrentDisplay(),
+ externalDisplaySurface, externalDisplaySurface,
+ eglGetCurrentContext());
+
+ ALOGE_IF(!success, "eglMakeCurrent -> external failed");
+
+ if (success) {
+ // redraw the screen entirely...
+ glDisable(GL_TEXTURE_EXTERNAL_OES);
+ glDisable(GL_TEXTURE_2D);
+ glClearColor(0,0,0,1);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
+ const size_t count = layers.size();
+ for (size_t i=0 ; i<count ; ++i) {
+ const sp<LayerBase>& layer(layers[i]);
+ layer->drawForSreenShot(hw);
+ }
+
+ success = eglSwapBuffers(eglGetCurrentDisplay(), externalDisplaySurface);
+ ALOGE_IF(!success, "external display eglSwapBuffers failed");
+
+ hw.compositionComplete();
+ }
+
+ success = eglMakeCurrent(eglGetCurrentDisplay(),
+ cur, cur, eglGetCurrentContext());
+
+ ALOGE_IF(!success, "eglMakeCurrent -> internal failed");
+ }
+
} break;
}
}
@@ -466,13 +527,26 @@
// in that case, we need to flip anyways to not risk a deadlock with
// h/w composer.
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ const DisplayHardware& hw(getDefaultDisplayHardware());
+ HWComposer& hwc(hw.getHwComposer());
+ size_t numLayers = mVisibleLayersSortedByZ.size();
const nsecs_t now = systemTime();
mDebugInSwapBuffers = now;
+
+ if (hwc.initCheck() == NO_ERROR) {
+ HWComposer::LayerListIterator cur = hwc.begin();
+ const HWComposer::LayerListIterator end = hwc.end();
+ for (size_t i = 0; cur != end && i < numLayers; ++i, ++cur) {
+ if (cur->getCompositionType() == HWC_OVERLAY) {
+ mVisibleLayersSortedByZ[i]->setAcquireFence(*cur);
+ } else {
+ cur->setAcquireFenceFd(-1);
+ }
+ }
+ }
+
hw.flip(mSwapRegion);
- size_t numLayers = mVisibleLayersSortedByZ.size();
- HWComposer& hwc(graphicPlane(0).displayHardware().getHwComposer());
if (hwc.initCheck() == NO_ERROR) {
HWComposer::LayerListIterator cur = hwc.begin();
const HWComposer::LayerListIterator end = hwc.end();
@@ -546,19 +620,18 @@
// the orientation has changed, recompute all visible regions
// and invalidate everything.
- const int dpy = 0;
+ const int dpy = 0; // TODO: should be a parameter
+ DisplayHardware& hw(const_cast<DisplayHardware&>(getDisplayHardware(dpy)));
const int orientation = mCurrentState.orientation;
- // Currently unused: const uint32_t flags = mCurrentState.orientationFlags;
- GraphicPlane& plane(graphicPlane(dpy));
- plane.setOrientation(orientation);
+ hw.setOrientation(orientation);
// update the shared control block
- const DisplayHardware& hw(plane.displayHardware());
volatile display_cblk_t* dcblk = mServerCblk->displays + dpy;
dcblk->orientation = orientation;
- dcblk->w = plane.getWidth();
- dcblk->h = plane.getHeight();
+ dcblk->w = hw.getUserWidth();
+ dcblk->h = hw.getUserHeight();
+ // FIXME: mVisibleRegionsDirty & mDirtyRegion should this be per DisplayHardware?
mVisibleRegionsDirty = true;
mDirtyRegion.set(hw.bounds());
}
@@ -593,9 +666,8 @@
{
ATRACE_CALL();
- const GraphicPlane& plane(graphicPlane(0));
- const Transform& planeTransform(plane.transform());
- const DisplayHardware& hw(plane.displayHardware());
+ const DisplayHardware& hw(getDefaultDisplayHardware()); // FIXME: we shouldn't rely on DisplayHardware here
+ const Transform& planeTransform(hw.getTransform());
const Region screenRegion(hw.bounds());
Region aboveOpaqueLayers;
@@ -607,7 +679,7 @@
size_t i = currentLayers.size();
while (i--) {
const sp<LayerBase>& layer = currentLayers[i];
- layer->validateVisibility(planeTransform);
+ layer->validateVisibility(planeTransform, hw);
// start with the whole surface at its current location
const Layer::State& s(layer->drawingState());
@@ -734,7 +806,7 @@
void SurfaceFlinger::handlePageFlip()
{
ATRACE_CALL();
- const DisplayHardware& hw = graphicPlane(0).displayHardware();
+ const DisplayHardware& hw(getDefaultDisplayHardware()); // FIXME: it's a problem we need DisplayHardware here
const Region screenRegion(hw.bounds());
const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
@@ -785,8 +857,8 @@
void SurfaceFlinger::unlockPageFlip(const LayerVector& currentLayers)
{
- const GraphicPlane& plane(graphicPlane(0));
- const Transform& planeTransform(plane.transform());
+ const DisplayHardware& hw(getDefaultDisplayHardware()); // FIXME: it's a problem we need DisplayHardware here
+ const Transform& planeTransform(hw.getTransform());
const size_t count = currentLayers.size();
sp<LayerBase> const* layers = currentLayers.array();
for (size_t i=0 ; i<count ; i++) {
@@ -812,10 +884,10 @@
}
-void SurfaceFlinger::handleWorkList()
+void SurfaceFlinger::handleWorkList(const DisplayHardware& hw)
{
mHwWorkListDirty = false;
- HWComposer& hwc(graphicPlane(0).displayHardware().getHwComposer());
+ HWComposer& hwc(hw.getHwComposer());
if (hwc.initCheck() == NO_ERROR) {
const Vector< sp<LayerBase> >& currentLayers(mVisibleLayersSortedByZ);
const size_t count = currentLayers.size();
@@ -832,7 +904,7 @@
}
}
-void SurfaceFlinger::handleRepaint()
+void SurfaceFlinger::handleRepaint(const DisplayHardware& hw)
{
ATRACE_CALL();
@@ -840,11 +912,10 @@
mSwapRegion.orSelf(mDirtyRegion);
if (CC_UNLIKELY(mDebugRegion)) {
- debugFlashRegions();
+ debugFlashRegions(hw);
}
// set the frame buffer
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
@@ -868,19 +939,17 @@
}
}
- setupHardwareComposer();
- composeSurfaces(mDirtyRegion);
+ setupHardwareComposer(hw);
+ composeSurfaces(hw, mDirtyRegion);
// update the swap region and clear the dirty region
mSwapRegion.orSelf(mDirtyRegion);
mDirtyRegion.clear();
}
-void SurfaceFlinger::setupHardwareComposer()
+void SurfaceFlinger::setupHardwareComposer(const DisplayHardware& hw)
{
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
HWComposer& hwc(hw.getHwComposer());
-
HWComposer::LayerListIterator cur = hwc.begin();
const HWComposer::LayerListIterator end = hwc.end();
if (cur == end) {
@@ -911,9 +980,8 @@
ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
}
-void SurfaceFlinger::composeSurfaces(const Region& dirty)
+void SurfaceFlinger::composeSurfaces(const DisplayHardware& hw, const Region& dirty)
{
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
HWComposer& hwc(hw.getHwComposer());
HWComposer::LayerListIterator cur = hwc.begin();
const HWComposer::LayerListIterator end = hwc.end();
@@ -953,20 +1021,19 @@
&& layer->isOpaque()) {
// never clear the very first layer since we're
// guaranteed the FB is already cleared
- layer->clearWithOpenGL(clip);
+ layer->clearWithOpenGL(hw, clip);
}
continue;
}
// render the layer
- layer->draw(clip);
+ layer->draw(hw, clip);
}
}
}
}
-void SurfaceFlinger::debugFlashRegions()
+void SurfaceFlinger::debugFlashRegions(const DisplayHardware& hw)
{
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
const uint32_t flags = hw.getFlags();
const int32_t height = hw.getHeight();
if (mSwapRegion.isEmpty()) {
@@ -976,7 +1043,7 @@
if (!(flags & DisplayHardware::SWAP_RECTANGLE)) {
const Region repaint((flags & DisplayHardware::PARTIAL_UPDATES) ?
mDirtyRegion.bounds() : hw.bounds());
- composeSurfaces(repaint);
+ composeSurfaces(hw, repaint);
}
glDisable(GL_TEXTURE_EXTERNAL_OES);
@@ -1386,7 +1453,7 @@
void SurfaceFlinger::onScreenAcquired() {
ALOGD("Screen about to return, flinger = %p", this);
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ const DisplayHardware& hw(getDefaultDisplayHardware()); // XXX: this should be per DisplayHardware
hw.acquireScreen();
mEventThread->onScreenAcquired();
// this is a temporary work-around, eventually this should be called
@@ -1398,7 +1465,7 @@
void SurfaceFlinger::onScreenReleased() {
ALOGD("About to give-up screen, flinger = %p", this);
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ const DisplayHardware& hw(getDefaultDisplayHardware()); // XXX: this should be per DisplayHardware
if (hw.isScreenAcquired()) {
mEventThread->onScreenReleased();
hw.releaseScreen();
@@ -1597,6 +1664,7 @@
snprintf(buffer, SIZE, "SurfaceFlinger global state:\n");
result.append(buffer);
+ const DisplayHardware& hw(getDefaultDisplayHardware());
const GLExtensions& extensions(GLExtensions::getInstance());
snprintf(buffer, SIZE, "GLES: %s, %s, %s\n",
extensions.getVendor(),
@@ -1605,7 +1673,7 @@
result.append(buffer);
snprintf(buffer, SIZE, "EGL : %s\n",
- eglQueryString(graphicPlane(0).getEGLDisplay(),
+ eglQueryString(hw.getEGLDisplay(),
EGL_VERSION_HW_ANDROID));
result.append(buffer);
@@ -1613,7 +1681,6 @@
result.append(buffer);
mWormholeRegion.dump(result, "WormholeRegion");
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
snprintf(buffer, SIZE,
" orientation=%d, canDraw=%d\n",
mCurrentState.orientation, hw.canDraw());
@@ -1764,7 +1831,7 @@
return NO_ERROR;
case 1013: {
Mutex::Autolock _l(mStateLock);
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ const DisplayHardware& hw(getDefaultDisplayHardware());
reply->writeInt32(hw.getPageFlipCount());
}
return NO_ERROR;
@@ -1774,7 +1841,7 @@
}
void SurfaceFlinger::repaintEverything() {
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ const DisplayHardware& hw(getDefaultDisplayHardware()); // FIXME: this cannot be bound the default display
const Rect bounds(hw.getBounds());
setInvalidateRegion(Region(bounds));
signalTransaction();
@@ -1810,7 +1877,7 @@
return INVALID_OPERATION;
// get screen geometry
- const DisplayHardware& hw(graphicPlane(dpy).displayHardware());
+ const DisplayHardware& hw(getDisplayHardware(dpy));
const uint32_t hw_w = hw.getWidth();
const uint32_t hw_h = hw.getHeight();
GLfloat u = 1;
@@ -1852,7 +1919,7 @@
const size_t count = layers.size();
for (size_t i=0 ; i<count ; ++i) {
const sp<LayerBase>& layer(layers[i]);
- layer->drawForSreenShot();
+ layer->drawForSreenShot(hw);
}
hw.compositionComplete();
@@ -1901,7 +1968,7 @@
status_t SurfaceFlinger::electronBeamOffAnimationImplLocked()
{
// get screen geometry
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ const DisplayHardware& hw(getDefaultDisplayHardware());
const uint32_t hw_w = hw.getWidth();
const uint32_t hw_h = hw.getHeight();
const Region screenBounds(hw.getBounds());
@@ -2083,7 +2150,7 @@
// get screen geometry
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ const DisplayHardware& hw(getDefaultDisplayHardware());
const uint32_t hw_w = hw.getWidth();
const uint32_t hw_h = hw.getHeight();
const Region screenBounds(hw.bounds());
@@ -2232,7 +2299,7 @@
{
ATRACE_CALL();
- DisplayHardware& hw(graphicPlane(0).editDisplayHardware());
+ DisplayHardware& hw(const_cast<DisplayHardware&>(getDefaultDisplayHardware()));
if (!hw.canDraw()) {
// we're already off
return NO_ERROR;
@@ -2292,7 +2359,7 @@
status_t SurfaceFlinger::turnElectronBeamOnImplLocked(int32_t mode)
{
- DisplayHardware& hw(graphicPlane(0).editDisplayHardware());
+ DisplayHardware& hw(const_cast<DisplayHardware&>(getDefaultDisplayHardware()));
if (hw.canDraw()) {
// we're already on
return NO_ERROR;
@@ -2352,7 +2419,7 @@
return INVALID_OPERATION;
// get screen geometry
- const DisplayHardware& hw(graphicPlane(dpy).displayHardware());
+ const DisplayHardware& hw(getDisplayHardware(dpy));
const uint32_t hw_w = hw.getWidth();
const uint32_t hw_h = hw.getHeight();
@@ -2404,7 +2471,7 @@
if (!(flags & ISurfaceComposer::eLayerHidden)) {
const uint32_t z = layer->drawingState().z;
if (z >= minLayerZ && z <= maxLayerZ) {
- layer->drawForSreenShot();
+ layer->drawForSreenShot(hw);
}
}
}
@@ -2552,126 +2619,4 @@
// ---------------------------------------------------------------------------
-GraphicPlane::GraphicPlane()
- : mHw(0)
-{
-}
-
-GraphicPlane::~GraphicPlane() {
- delete mHw;
-}
-
-bool GraphicPlane::initialized() const {
- return mHw ? true : false;
-}
-
-int GraphicPlane::getWidth() const {
- return mWidth;
-}
-
-int GraphicPlane::getHeight() const {
- return mHeight;
-}
-
-void GraphicPlane::setDisplayHardware(DisplayHardware *hw)
-{
- mHw = hw;
-
- // initialize the display orientation transform.
- // it's a constant that should come from the display driver.
- int displayOrientation = ISurfaceComposer::eOrientationDefault;
- char property[PROPERTY_VALUE_MAX];
- if (property_get("ro.sf.hwrotation", property, NULL) > 0) {
- //displayOrientation
- switch (atoi(property)) {
- case 90:
- displayOrientation = ISurfaceComposer::eOrientation90;
- break;
- case 270:
- displayOrientation = ISurfaceComposer::eOrientation270;
- break;
- }
- }
-
- const float w = hw->getWidth();
- const float h = hw->getHeight();
- GraphicPlane::orientationToTransfrom(displayOrientation, w, h,
- &mDisplayTransform);
- if (displayOrientation & ISurfaceComposer::eOrientationSwapMask) {
- mDisplayWidth = h;
- mDisplayHeight = w;
- } else {
- mDisplayWidth = w;
- mDisplayHeight = h;
- }
-
- setOrientation(ISurfaceComposer::eOrientationDefault);
-}
-
-status_t GraphicPlane::orientationToTransfrom(
- int orientation, int w, int h, Transform* tr)
-{
- uint32_t flags = 0;
- switch (orientation) {
- case ISurfaceComposer::eOrientationDefault:
- flags = Transform::ROT_0;
- break;
- case ISurfaceComposer::eOrientation90:
- flags = Transform::ROT_90;
- break;
- case ISurfaceComposer::eOrientation180:
- flags = Transform::ROT_180;
- break;
- case ISurfaceComposer::eOrientation270:
- flags = Transform::ROT_270;
- break;
- default:
- return BAD_VALUE;
- }
- tr->set(flags, w, h);
- return NO_ERROR;
-}
-
-status_t GraphicPlane::setOrientation(int orientation)
-{
- // If the rotation can be handled in hardware, this is where
- // the magic should happen.
-
- const DisplayHardware& hw(displayHardware());
- const float w = mDisplayWidth;
- const float h = mDisplayHeight;
- mWidth = int(w);
- mHeight = int(h);
-
- Transform orientationTransform;
- GraphicPlane::orientationToTransfrom(orientation, w, h,
- &orientationTransform);
- if (orientation & ISurfaceComposer::eOrientationSwapMask) {
- mWidth = int(h);
- mHeight = int(w);
- }
-
- mOrientation = orientation;
- mGlobalTransform = mDisplayTransform * orientationTransform;
- return NO_ERROR;
-}
-
-const DisplayHardware& GraphicPlane::displayHardware() const {
- return *mHw;
-}
-
-DisplayHardware& GraphicPlane::editDisplayHardware() {
- return *mHw;
-}
-
-const Transform& GraphicPlane::transform() const {
- return mGlobalTransform;
-}
-
-EGLDisplay GraphicPlane::getEGLDisplay() const {
- return mHw->getEGLDisplay();
-}
-
-// ---------------------------------------------------------------------------
-
}; // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index c3efdbc..3e27564 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -68,44 +68,6 @@
// ---------------------------------------------------------------------------
-class GraphicPlane
-{
-public:
- static status_t orientationToTransfrom(int orientation, int w, int h,
- Transform* tr);
-
- GraphicPlane();
- ~GraphicPlane();
-
- bool initialized() const;
-
- void setDisplayHardware(DisplayHardware *);
- status_t setOrientation(int orientation);
- int getOrientation() const { return mOrientation; }
- int getWidth() const;
- int getHeight() const;
-
- const DisplayHardware& displayHardware() const;
- DisplayHardware& editDisplayHardware();
- const Transform& transform() const;
- EGLDisplay getEGLDisplay() const;
-
-private:
- GraphicPlane(const GraphicPlane&);
- GraphicPlane operator = (const GraphicPlane&);
-
- DisplayHardware* mHw;
- Transform mGlobalTransform;
- Transform mDisplayTransform;
- int mOrientation;
- float mDisplayWidth;
- float mDisplayHeight;
- int mWidth;
- int mHeight;
-};
-
-// ---------------------------------------------------------------------------
-
enum {
eTransactionNeeded = 0x01,
eTraversalNeeded = 0x02
@@ -153,6 +115,8 @@
// called when screen is turning back on
virtual void unblank();
+ virtual void connectDisplay(const sp<ISurfaceTexture> display);
+
// called on the main thread in response to screenReleased()
void onScreenReleased();
// called on the main thread in response to screenAcquired()
@@ -258,8 +222,13 @@
virtual void onFirstRef();
public: // hack to work around gcc 4.0.3 bug
- const GraphicPlane& graphicPlane(int dpy) const;
- GraphicPlane& graphicPlane(int dpy);
+
+ const DisplayHardware& getDisplayHardware(DisplayID dpy) const {
+ return *mDisplayHardwares[dpy];
+ }
+ const DisplayHardware& getDefaultDisplayHardware() const {
+ return getDisplayHardware(0);
+ }
void signalTransaction();
void signalLayerUpdate();
@@ -280,11 +249,11 @@
bool lockPageFlip(const LayerVector& currentLayers);
void unlockPageFlip(const LayerVector& currentLayers);
void handleRefresh();
- void handleWorkList();
- void handleRepaint();
+ void handleWorkList(const DisplayHardware& hw);
+ void handleRepaint(const DisplayHardware& hw);
void postFramebuffer();
- void setupHardwareComposer();
- void composeSurfaces(const Region& dirty);
+ void setupHardwareComposer(const DisplayHardware& hw);
+ void composeSurfaces(const DisplayHardware& hw, const Region& dirty);
void setInvalidateRegion(const Region& reg);
@@ -313,7 +282,7 @@
status_t electronBeamOffAnimationImplLocked();
status_t electronBeamOnAnimationImplLocked();
- void debugFlashRegions();
+ void debugFlashRegions(const DisplayHardware& hw);
void drawWormhole() const;
void startBootAnim();
@@ -338,7 +307,7 @@
Vector< sp<LayerBase> > mLayersPendingRemoval;
// protected by mStateLock (but we could use another lock)
- GraphicPlane mGraphicPlanes[1];
+ DisplayHardware* mDisplayHardwares[1];
bool mLayersRemoved;
DefaultKeyedVector< wp<IBinder>, wp<Layer> > mLayerMap;
@@ -388,6 +357,11 @@
// only written in the main thread, only read in other threads
volatile int32_t mSecureFrameBuffer;
+
+
+ EGLSurface getExternalDisplaySurface() const;
+ sp<SurfaceTextureClient> mExternalDisplayNativeWindow;
+ EGLSurface mExternalDisplaySurface;
};
// ---------------------------------------------------------------------------