diff options
Diffstat (limited to 'include')
30 files changed, 2995 insertions, 365 deletions
diff --git a/include/binder/IInterface.h b/include/binder/IInterface.h index 273d922..5f9f69c 100644 --- a/include/binder/IInterface.h +++ b/include/binder/IInterface.h @@ -72,21 +72,24 @@ protected: // ---------------------------------------------------------------------- #define DECLARE_META_INTERFACE(INTERFACE) \ - static const String16 descriptor; \ - static sp<I##INTERFACE> asInterface(const sp<IBinder>& obj); \ - virtual const String16& getInterfaceDescriptor() const; \ + static const android::String16 descriptor; \ + static android::sp<I##INTERFACE> asInterface( \ + const android::sp<android::IBinder>& obj); \ + virtual const android::String16& getInterfaceDescriptor() const; \ I##INTERFACE(); \ virtual ~I##INTERFACE(); \ #define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \ - const String16 I##INTERFACE::descriptor(NAME); \ - const String16& I##INTERFACE::getInterfaceDescriptor() const { \ + const android::String16 I##INTERFACE::descriptor(NAME); \ + const android::String16& \ + I##INTERFACE::getInterfaceDescriptor() const { \ return I##INTERFACE::descriptor; \ } \ - sp<I##INTERFACE> I##INTERFACE::asInterface(const sp<IBinder>& obj) \ + android::sp<I##INTERFACE> I##INTERFACE::asInterface( \ + const android::sp<android::IBinder>& obj) \ { \ - sp<I##INTERFACE> intr; \ + android::sp<I##INTERFACE> intr; \ if (obj != NULL) { \ intr = static_cast<I##INTERFACE*>( \ obj->queryLocalInterface( \ diff --git a/include/private/surfaceflinger/SharedBufferStack.h b/include/private/surfaceflinger/SharedBufferStack.h index 9b5a1e0..633b543 100644 --- a/include/private/surfaceflinger/SharedBufferStack.h +++ b/include/private/surfaceflinger/SharedBufferStack.h @@ -43,24 +43,9 @@ namespace android { * unless they are in use by the server, which is only the case for the last * dequeue-able buffer. When these various conditions are not met, the caller * waits until the condition is met. - * - * - * CAVEATS: - * - * In the current implementation there are several limitations: - * - buffers must be locked in the same order they've been dequeued - * - buffers must be enqueued in the same order they've been locked - * - dequeue() is not reentrant - * - no error checks are done on the condition above * */ -// When changing these values, the COMPILE_TIME_ASSERT at the end of this -// file need to be updated. -const unsigned int NUM_LAYERS_MAX = 31; -const unsigned int NUM_BUFFER_MAX = 4; -const unsigned int NUM_DISPLAY_MAX = 4; - // ---------------------------------------------------------------------------- class Region; @@ -69,7 +54,11 @@ class SharedClient; // ---------------------------------------------------------------------------- -// should be 128 bytes (32 longs) +// 4 * (11 + 7 + (1 + 2*NUM_RECT_MAX) * NUM_BUFFER_MAX) * NUM_LAYERS_MAX +// 4 * (11 + 7 + (1 + 2*7)*16) * 31 +// 1032 * 31 +// = ~27 KiB (31992) + class SharedBufferStack { friend class SharedClient; @@ -78,21 +67,38 @@ class SharedBufferStack friend class SharedBufferServer; public: - struct FlatRegion { // 12 bytes - static const unsigned int NUM_RECT_MAX = 1; - uint32_t count; - uint16_t rects[4*NUM_RECT_MAX]; - }; - + // When changing these values, the COMPILE_TIME_ASSERT at the end of this + // file need to be updated. + static const unsigned int NUM_LAYERS_MAX = 31; + static const unsigned int NUM_BUFFER_MAX = 16; + static const unsigned int NUM_BUFFER_MIN = 2; + static const unsigned int NUM_DISPLAY_MAX = 4; + struct Statistics { // 4 longs typedef int32_t usecs_t; usecs_t totalTime; usecs_t reserved[3]; }; + + struct SmallRect { + uint16_t l, t, r, b; + }; + + struct FlatRegion { // 52 bytes = 4 * (1 + 2*N) + static const unsigned int NUM_RECT_MAX = 6; + uint32_t count; + SmallRect rects[NUM_RECT_MAX]; + }; + + struct BufferData { + FlatRegion dirtyRegion; + SmallRect crop; + }; SharedBufferStack(); void init(int32_t identity); status_t setDirtyRegion(int buffer, const Region& reg); + status_t setCrop(int buffer, const Rect& reg); Region getDirtyRegion(int buffer) const; // these attributes are part of the conditions/updates @@ -104,24 +110,25 @@ public: // not part of the conditions volatile int32_t reallocMask; + volatile int8_t index[NUM_BUFFER_MAX]; int32_t identity; // surface's identity (const) - int32_t reserved32[9]; + int32_t token; // surface's token (for debugging) + int32_t reserved32[1]; Statistics stats; - FlatRegion dirtyRegion[NUM_BUFFER_MAX]; // 12*4=48 bytes + int32_t reserved; + BufferData buffers[NUM_BUFFER_MAX]; // 960 bytes }; // ---------------------------------------------------------------------------- -// 4 KB max +// 32 KB max class SharedClient { public: SharedClient(); ~SharedClient(); - status_t validate(size_t token) const; - uint32_t getIdentity(size_t token) const; private: friend class SharedBufferBase; @@ -131,7 +138,7 @@ private: // FIXME: this should be replaced by a lock-less primitive Mutex lock; Condition cv; - SharedBufferStack surfaces[ NUM_LAYERS_MAX ]; + SharedBufferStack surfaces[ SharedBufferStack::NUM_LAYERS_MAX ]; }; // ============================================================================ @@ -139,18 +146,17 @@ private: class SharedBufferBase { public: - SharedBufferBase(SharedClient* sharedClient, int surface, int num, + SharedBufferBase(SharedClient* sharedClient, int surface, int32_t identity); ~SharedBufferBase(); - uint32_t getIdentity(); status_t getStatus() const; + int32_t getIdentity() const; size_t getFrontBuffer() const; String8 dump(char const* prefix) const; protected: SharedClient* const mSharedClient; SharedBufferStack* const mSharedStack; - const int mNumBuffers; const int mIdentity; friend struct Update; @@ -160,61 +166,22 @@ protected: SharedBufferStack& stack; inline ConditionBase(SharedBufferBase* sbc) : stack(*sbc->mSharedStack) { } + virtual ~ConditionBase() { }; + virtual bool operator()() const = 0; + virtual const char* name() const = 0; }; + status_t waitForCondition(const ConditionBase& condition); struct UpdateBase { SharedBufferStack& stack; inline UpdateBase(SharedBufferBase* sbb) : stack(*sbb->mSharedStack) { } }; - - template <typename T> - status_t waitForCondition(T condition); - template <typename T> status_t updateCondition(T update); }; template <typename T> -status_t SharedBufferBase::waitForCondition(T condition) -{ - const SharedBufferStack& stack( *mSharedStack ); - SharedClient& client( *mSharedClient ); - const nsecs_t TIMEOUT = s2ns(1); - Mutex::Autolock _l(client.lock); - while ((condition()==false) && - (stack.identity == mIdentity) && - (stack.status == NO_ERROR)) - { - status_t err = client.cv.waitRelative(client.lock, TIMEOUT); - - // handle errors and timeouts - if (CC_UNLIKELY(err != NO_ERROR)) { - if (err == TIMED_OUT) { - if (condition()) { - LOGE("waitForCondition(%s) timed out (identity=%d), " - "but condition is true! We recovered but it " - "shouldn't happen." , T::name(), - stack.identity); - break; - } else { - LOGW("waitForCondition(%s) timed out " - "(identity=%d, status=%d). " - "CPU may be pegged. trying again.", T::name(), - stack.identity, stack.status); - } - } else { - LOGE("waitForCondition(%s) error (%s) ", - T::name(), strerror(-err)); - return err; - } - } - } - return (stack.identity != mIdentity) ? status_t(BAD_INDEX) : stack.status; -} - - -template <typename T> status_t SharedBufferBase::updateCondition(T update) { SharedClient& client( *mSharedClient ); Mutex::Autolock _l(client.lock); @@ -238,13 +205,21 @@ public: status_t queue(int buf); bool needNewBuffer(int buffer) const; status_t setDirtyRegion(int buffer, const Region& reg); + status_t setCrop(int buffer, const Rect& reg); + + class SetBufferCountCallback { + friend class SharedBufferClient; + virtual status_t operator()(int bufferCount) const = 0; + protected: + virtual ~SetBufferCountCallback() { } + }; + status_t setBufferCount(int bufferCount, const SetBufferCountCallback& ipc); + private: friend struct Condition; friend struct DequeueCondition; friend struct LockCondition; - - int32_t computeTail() const; struct QueueUpdate : public UpdateBase { inline QueueUpdate(SharedBufferBase* sbb); @@ -260,25 +235,34 @@ private: struct DequeueCondition : public ConditionBase { inline DequeueCondition(SharedBufferClient* sbc); - inline bool operator()(); - static inline const char* name() { return "DequeueCondition"; } + inline bool operator()() const; + inline const char* name() const { return "DequeueCondition"; } }; struct LockCondition : public ConditionBase { int buf; inline LockCondition(SharedBufferClient* sbc, int buf); - inline bool operator()(); - static inline const char* name() { return "LockCondition"; } + inline bool operator()() const; + inline const char* name() const { return "LockCondition"; } }; + int32_t computeTail() const; + + mutable RWLock mLock; + int mNumBuffers; + int32_t tail; + int32_t undoDequeueTail; + int32_t queued_head; // statistics... - nsecs_t mDequeueTime[NUM_BUFFER_MAX]; + nsecs_t mDequeueTime[SharedBufferStack::NUM_BUFFER_MAX]; }; // ---------------------------------------------------------------------------- -class SharedBufferServer : public SharedBufferBase +class SharedBufferServer + : public SharedBufferBase, + public LightRefBase<SharedBufferServer> { public: SharedBufferServer(SharedClient* sharedClient, int surface, int num, @@ -287,16 +271,74 @@ public: ssize_t retireAndLock(); status_t unlock(int buffer); void setStatus(status_t status); - status_t reallocate(); + status_t reallocateAll(); + status_t reallocateAllExcept(int buffer); status_t assertReallocate(int buffer); int32_t getQueuedCount() const; - Region getDirtyRegion(int buffer) const; + status_t resize(int newNumBuffers); + SharedBufferStack::Statistics getStats() const; private: + friend class LightRefBase<SharedBufferServer>; + ~SharedBufferServer(); + + /* + * BufferList is basically a fixed-capacity sorted-vector of + * unsigned 5-bits ints using a 32-bits int as storage. + * it has efficient iterators to find items in the list and not in the list. + */ + class BufferList { + size_t mCapacity; + uint32_t mList; + public: + BufferList(size_t c = SharedBufferStack::NUM_BUFFER_MAX) + : mCapacity(c), mList(0) { } + status_t add(int value); + status_t remove(int value); + uint32_t getMask() const { return mList; } + + class const_iterator { + friend class BufferList; + uint32_t mask, curr; + const_iterator(uint32_t mask) : + mask(mask), curr(__builtin_clz(mask)) { + } + public: + inline bool operator == (const const_iterator& rhs) const { + return mask == rhs.mask; + } + inline bool operator != (const const_iterator& rhs) const { + return mask != rhs.mask; + } + inline int operator *() const { return curr; } + inline const const_iterator& operator ++() { + mask &= ~(1<<(31-curr)); + curr = __builtin_clz(mask); + return *this; + } + }; + + inline const_iterator begin() const { + return const_iterator(mList); + } + inline const_iterator end() const { + return const_iterator(0); + } + inline const_iterator free_begin() const { + uint32_t mask = (1 << (32-mCapacity)) - 1; + return const_iterator( ~(mList | mask) ); + } + }; + + // this protects mNumBuffers and mBufferList + mutable RWLock mLock; + int mNumBuffers; + BufferList mBufferList; + struct UnlockUpdate : public UpdateBase { const int lockedBuffer; inline UnlockUpdate(SharedBufferBase* sbb, int lockedBuffer); @@ -318,8 +360,8 @@ private: struct ReallocateCondition : public ConditionBase { int buf; inline ReallocateCondition(SharedBufferBase* sbb, int buf); - inline bool operator()(); - static inline const char* name() { return "ReallocateCondition"; } + inline bool operator()() const; + inline const char* name() const { return "ReallocateCondition"; } }; }; @@ -344,13 +386,12 @@ struct surface_flinger_cblk_t // 4KB max uint8_t connected; uint8_t reserved[3]; uint32_t pad[7]; - display_cblk_t displays[NUM_DISPLAY_MAX]; + display_cblk_t displays[SharedBufferStack::NUM_DISPLAY_MAX]; }; // --------------------------------------------------------------------------- -COMPILE_TIME_ASSERT(sizeof(SharedClient) <= 4096) -COMPILE_TIME_ASSERT(sizeof(SharedBufferStack) == 128) +COMPILE_TIME_ASSERT(sizeof(SharedClient) <= 32768) COMPILE_TIME_ASSERT(sizeof(surface_flinger_cblk_t) <= 4096) // --------------------------------------------------------------------------- diff --git a/include/surfaceflinger/ISurface.h b/include/surfaceflinger/ISurface.h index 472f759..ddbe03d 100644 --- a/include/surfaceflinger/ISurface.h +++ b/include/surfaceflinger/ISurface.h @@ -47,13 +47,30 @@ protected: POST_BUFFER, // one-way transaction CREATE_OVERLAY, REQUEST_BUFFER, + SET_BUFFER_COUNT, }; public: DECLARE_META_INTERFACE(Surface); - virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, int usage) = 0; + /* + * requests a new buffer for the given index. If w, h, or format are + * null the buffer is created with the parameters assigned to the + * surface it is bound to. Otherwise the buffer's parameters are + * set to those specified. + */ + virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, + uint32_t w, uint32_t h, uint32_t format, uint32_t usage) = 0; + + /* + * sets the number of buffers dequeuable for this surface. + */ + virtual status_t setBufferCount(int bufferCount) = 0; + // ------------------------------------------------------------------------ + // Deprecated... + // ------------------------------------------------------------------------ + class BufferHeap { public: enum { diff --git a/include/surfaceflinger/ISurfaceComposer.h b/include/surfaceflinger/ISurfaceComposer.h index d1e7785..dd44aa5 100644 --- a/include/surfaceflinger/ISurfaceComposer.h +++ b/include/surfaceflinger/ISurfaceComposer.h @@ -27,7 +27,7 @@ #include <ui/PixelFormat.h> -#include <surfaceflinger/ISurfaceFlingerClient.h> +#include <surfaceflinger/ISurfaceComposerClient.h> namespace android { // ---------------------------------------------------------------------------- @@ -85,8 +85,11 @@ public: /* create connection with surface flinger, requires * ACCESS_SURFACE_FLINGER permission */ + virtual sp<ISurfaceComposerClient> createConnection() = 0; - virtual sp<ISurfaceFlingerClient> createConnection() = 0; + /* create a client connection with surface flinger + */ + virtual sp<ISurfaceComposerClient> createClientConnection() = 0; /* retrieve the control block */ virtual sp<IMemoryHeap> getCblk() const = 0; @@ -123,6 +126,7 @@ public: // Java by ActivityManagerService. BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION, CREATE_CONNECTION, + CREATE_CLIENT_CONNECTION, GET_CBLK, OPEN_GLOBAL_TRANSACTION, CLOSE_GLOBAL_TRANSACTION, diff --git a/include/surfaceflinger/ISurfaceFlingerClient.h b/include/surfaceflinger/ISurfaceComposerClient.h index d257645..a1e9e04 100644 --- a/include/surfaceflinger/ISurfaceFlingerClient.h +++ b/include/surfaceflinger/ISurfaceComposerClient.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ANDROID_SF_ISURFACE_FLINGER_CLIENT_H -#define ANDROID_SF_ISURFACE_FLINGER_CLIENT_H +#ifndef ANDROID_SF_ISURFACE_COMPOSER_CLIENT_H +#define ANDROID_SF_ISURFACE_COMPOSER_CLIENT_H #include <stdint.h> #include <sys/types.h> @@ -26,7 +26,7 @@ #include <binder/IInterface.h> #include <ui/PixelFormat.h> - + #include <surfaceflinger/ISurface.h> namespace android { @@ -42,10 +42,10 @@ typedef int32_t DisplayID; class layer_state_t; -class ISurfaceFlingerClient : public IInterface +class ISurfaceComposerClient : public IInterface { -public: - DECLARE_META_INTERFACE(SurfaceFlingerClient); +public: + DECLARE_META_INTERFACE(SurfaceComposerClient); struct surface_data_t { int32_t token; @@ -56,26 +56,36 @@ public: status_t readFromParcel(const Parcel& parcel); status_t writeToParcel(Parcel* parcel) const; }; - + virtual sp<IMemoryHeap> getControlBlock() const = 0; + virtual ssize_t getTokenForSurface(const sp<ISurface>& sur) const = 0; + /* + * Requires ACCESS_SURFACE_FLINGER permission + */ virtual sp<ISurface> createSurface( surface_data_t* data, - int pid, + int pid, const String8& name, DisplayID display, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags) = 0; - + + /* + * Requires ACCESS_SURFACE_FLINGER permission + */ virtual status_t destroySurface(SurfaceID sid) = 0; + /* + * Requires ACCESS_SURFACE_FLINGER permission + */ virtual status_t setState(int32_t count, const layer_state_t* states) = 0; }; // ---------------------------------------------------------------------------- -class BnSurfaceFlingerClient : public BnInterface<ISurfaceFlingerClient> +class BnSurfaceComposerClient : public BnInterface<ISurfaceComposerClient> { public: virtual status_t onTransact( uint32_t code, @@ -88,4 +98,4 @@ public: }; // namespace android -#endif // ANDROID_SF_ISURFACE_FLINGER_CLIENT_H +#endif // ANDROID_SF_ISURFACE_COMPOSER_CLIENT_H diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h index 0279d84..f333911 100644 --- a/include/surfaceflinger/Surface.h +++ b/include/surfaceflinger/Surface.h @@ -28,12 +28,15 @@ #include <ui/egl/android_natives.h> #include <surfaceflinger/ISurface.h> -#include <surfaceflinger/ISurfaceFlingerClient.h> +#include <surfaceflinger/ISurfaceComposerClient.h> + +#define ANDROID_VIEW_SURFACE_JNI_ID "mNativeSurface" namespace android { // --------------------------------------------------------------------------- +class GraphicBuffer; class GraphicBufferMapper; class IOMX; class Rect; @@ -41,6 +44,7 @@ class Surface; class SurfaceComposerClient; class SharedClient; class SharedBufferClient; +class SurfaceClient; // --------------------------------------------------------------------------- @@ -56,7 +60,6 @@ public: static bool isSameSurface( const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs); - SurfaceID ID() const { return mToken; } uint32_t getFlags() const { return mFlags; } uint32_t getIdentity() const { return mIdentity; } @@ -104,7 +107,7 @@ private: SurfaceControl( const sp<SurfaceComposerClient>& client, const sp<ISurface>& surface, - const ISurfaceFlingerClient::surface_data_t& data, + const ISurfaceComposerClient::surface_data_t& data, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags); ~SurfaceControl(); @@ -141,17 +144,17 @@ public: uint32_t reserved[2]; }; - Surface(const Parcel& data); + static status_t writeToParcel( + const sp<Surface>& control, Parcel* parcel); + + static sp<Surface> readFromParcel( + const Parcel& data, const sp<Surface>& other); static bool isValid(const sp<Surface>& surface) { return (surface != 0) && surface->isValid(); } - static bool isSameSurface( - const sp<Surface>& lhs, const sp<Surface>& rhs); - bool isValid(); - SurfaceID ID() const { return mToken; } uint32_t getFlags() const { return mFlags; } uint32_t getIdentity() const { return mIdentity; } @@ -163,38 +166,37 @@ public: // setSwapRectangle() is intended to be used by GL ES clients void setSwapRectangle(const Rect& r); -private: - // can't be copied - Surface& operator = (Surface& rhs); - Surface(const Surface& rhs); - - Surface(const sp<SurfaceControl>& control); - void init(); - ~Surface(); - - friend class SurfaceComposerClient; - friend class SurfaceControl; - +private: + /* + * Android frameworks friends + * (eventually this should go away and be replaced by proper APIs) + */ // camera and camcorder need access to the ISurface binder interface for preview friend class Camera; friend class MediaRecorder; - // mediaplayer needs access to ISurface for display + // MediaPlayer needs access to ISurface for display friend class MediaPlayer; friend class IOMX; // this is just to be able to write some unit tests friend class Test; - sp<SurfaceComposerClient> getClient() const; - sp<ISurface> getISurface() const; +private: + friend class SurfaceComposerClient; + friend class SurfaceControl; - status_t getBufferLocked(int index, int usage); - - status_t validate() const; + // can't be copied + Surface& operator = (Surface& rhs); + Surface(const Surface& rhs); - inline const GraphicBufferMapper& getBufferMapper() const { return mBufferMapper; } - inline GraphicBufferMapper& getBufferMapper() { return mBufferMapper; } - + Surface(const sp<SurfaceControl>& control); + Surface(const Parcel& data, const sp<IBinder>& ref); + ~Surface(); + + + /* + * android_native_window_t hooks + */ static int setSwapInterval(android_native_window_t* window, int interval); static int dequeueBuffer(android_native_window_t* window, android_native_buffer_t** buffer); static int lockBuffer(android_native_window_t* window, android_native_buffer_t* buffer); @@ -208,44 +210,86 @@ private: int query(int what, int* value); int perform(int operation, va_list args); - status_t dequeueBuffer(sp<GraphicBuffer>* buffer); - void dispatch_setUsage(va_list args); int dispatch_connect(va_list args); int dispatch_disconnect(va_list args); + int dispatch_crop(va_list args); + int dispatch_set_buffer_count(va_list args); + int dispatch_set_buffers_geometry(va_list args); void setUsage(uint32_t reqUsage); int connect(int api); int disconnect(int api); + int crop(Rect const* rect); + int setBufferCount(int bufferCount); + int setBuffersGeometry(int w, int h, int format); - uint32_t getUsage() const; - int getConnectedApi() const; + /* + * private stuff... + */ + void init(); + status_t validate() const; + sp<ISurface> getISurface() const; + + inline const GraphicBufferMapper& getBufferMapper() const { return mBufferMapper; } + inline GraphicBufferMapper& getBufferMapper() { return mBufferMapper; } + + status_t getBufferLocked(int index, + uint32_t w, uint32_t h, uint32_t format, uint32_t usage); + int getBufferIndex(const sp<GraphicBuffer>& buffer) const; + + int getConnectedApi() const; + bool needNewBuffer(int bufIdx, + uint32_t *pWidth, uint32_t *pHeight, + uint32_t *pFormat, uint32_t *pUsage) const; + + class BufferInfo { + uint32_t mWidth; + uint32_t mHeight; + uint32_t mFormat; + uint32_t mUsage; + mutable uint32_t mDirty; + enum { + GEOMETRY = 0x01 + }; + public: + BufferInfo(); + void set(uint32_t w, uint32_t h, uint32_t format); + void set(uint32_t usage); + void get(uint32_t *pWidth, uint32_t *pHeight, + uint32_t *pFormat, uint32_t *pUsage) const; + bool validateBuffer(const sp<GraphicBuffer>& buffer) const; + }; + // constants - sp<SurfaceComposerClient> mClient; + GraphicBufferMapper& mBufferMapper; + SurfaceClient& mClient; + SharedBufferClient* mSharedBufferClient; + status_t mInitCheck; sp<ISurface> mSurface; - SurfaceID mToken; uint32_t mIdentity; PixelFormat mFormat; uint32_t mFlags; - GraphicBufferMapper& mBufferMapper; - SharedBufferClient* mSharedBufferClient; // protected by mSurfaceLock Rect mSwapRectangle; - uint32_t mUsage; int mConnected; + Rect mNextBufferCrop; + BufferInfo mBufferInfo; // protected by mSurfaceLock. These are also used from lock/unlock // but in that case, they must be called form the same thread. - sp<GraphicBuffer> mBuffers[2]; mutable Region mDirtyRegion; // must be used from the lock/unlock thread sp<GraphicBuffer> mLockedBuffer; sp<GraphicBuffer> mPostedBuffer; mutable Region mOldDirtyRegion; - bool mNeedFullUpdate; + bool mReserved; + + // only used from dequeueBuffer() + Vector< sp<GraphicBuffer> > mBuffers; // query() must be called from dequeueBuffer() thread uint32_t mWidth; diff --git a/include/surfaceflinger/SurfaceComposerClient.h b/include/surfaceflinger/SurfaceComposerClient.h index 9d0f0cb..8773d71 100644 --- a/include/surfaceflinger/SurfaceComposerClient.h +++ b/include/surfaceflinger/SurfaceComposerClient.h @@ -22,8 +22,9 @@ #include <binder/IBinder.h> -#include <utils/SortedVector.h> #include <utils/RefBase.h> +#include <utils/Singleton.h> +#include <utils/SortedVector.h> #include <utils/threads.h> #include <ui/PixelFormat.h> @@ -39,8 +40,26 @@ class Region; class SharedClient; class ISurfaceComposer; class DisplayInfo; +class surface_flinger_cblk_t; + +// --------------------------------------------------------------------------- + +class ComposerService : public Singleton<ComposerService> +{ + // these are constants + sp<ISurfaceComposer> mComposerService; + sp<IMemoryHeap> mServerCblkMemory; + surface_flinger_cblk_t volatile* mServerCblk; + ComposerService(); + friend class Singleton<ComposerService>; +public: + static sp<ISurfaceComposer> getComposerService(); + static surface_flinger_cblk_t const volatile * getControlBlock(); +}; -class SurfaceComposerClient : virtual public RefBase +// --------------------------------------------------------------------------- + +class SurfaceComposerClient : public RefBase { public: SurfaceComposerClient(); @@ -52,10 +71,6 @@ public: // Return the connection of this client sp<IBinder> connection() const; - // Retrieve a client for an existing connection. - static sp<SurfaceComposerClient> - clientForConnection(const sp<IBinder>& conn); - // Forcibly remove connection before all references have gone away. void dispose(); @@ -123,13 +138,6 @@ public: status_t linkToComposerDeath(const sp<IBinder::DeathRecipient>& recipient, void* cookie = NULL, uint32_t flags = 0); -private: - friend class Surface; - friend class SurfaceControl; - - SurfaceComposerClient(const sp<ISurfaceComposer>& sm, - const sp<IBinder>& conn); - status_t hide(SurfaceID id); status_t show(SurfaceID id, int32_t layer = -1); status_t freeze(SurfaceID id); @@ -142,32 +150,26 @@ private: status_t setMatrix(SurfaceID id, float dsdx, float dtdx, float dsdy, float dtdy); status_t setPosition(SurfaceID id, int32_t x, int32_t y); status_t setSize(SurfaceID id, uint32_t w, uint32_t h); - - void signalServer(); - status_t destroySurface(SurfaceID sid); - void _init(const sp<ISurfaceComposer>& sm, - const sp<ISurfaceFlingerClient>& conn); - - inline layer_state_t* _get_state_l(SurfaceID id); - layer_state_t* _lockLayerState(SurfaceID id); - inline void _unlockLayerState(); +private: + virtual void onFirstRef(); + inline layer_state_t* get_state_l(SurfaceID id); + layer_state_t* lockLayerState(SurfaceID id); + inline void unlockLayerState(); mutable Mutex mLock; - layer_state_t* mPrebuiltLayerState; SortedVector<layer_state_t> mStates; int32_t mTransactionOpen; + layer_state_t* mPrebuiltLayerState; // these don't need to be protected because they never change // after assignment status_t mStatus; - SharedClient* mControl; - sp<IMemoryHeap> mControlMemory; - sp<ISurfaceFlingerClient> mClient; - sp<ISurfaceComposer> mSignalServer; + sp<ISurfaceComposerClient> mClient; }; +// --------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_SF_SURFACE_COMPOSER_CLIENT_H diff --git a/include/ui/EventHub.h b/include/ui/EventHub.h index 3b18c77..d322a34 100644 --- a/include/ui/EventHub.h +++ b/include/ui/EventHub.h @@ -18,6 +18,7 @@ #ifndef _RUNTIME_EVENT_HUB_H #define _RUNTIME_EVENT_HUB_H +#include <android/input.h> #include <utils/String8.h> #include <utils/threads.h> #include <utils/Log.h> @@ -27,6 +28,31 @@ #include <linux/input.h> +/* These constants are not defined in linux/input.h but they are part of the multitouch + * input protocol. */ + +#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */ +#define ABS_MT_TOUCH_MINOR 0x31 /* Minor axis (omit if circular) */ +#define ABS_MT_WIDTH_MAJOR 0x32 /* Major axis of approaching ellipse */ +#define ABS_MT_WIDTH_MINOR 0x33 /* Minor axis (omit if circular) */ +#define ABS_MT_ORIENTATION 0x34 /* Ellipse orientation */ +#define ABS_MT_POSITION_X 0x35 /* Center X ellipse position */ +#define ABS_MT_POSITION_Y 0x36 /* Center Y ellipse position */ +#define ABS_MT_TOOL_TYPE 0x37 /* Type of touching device (finger, pen, ...) */ +#define ABS_MT_BLOB_ID 0x38 /* Group a set of packets as a blob */ +#define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */ +#define ABS_MT_PRESSURE 0x3a /* Pressure on contact area */ + +#define MT_TOOL_FINGER 0 /* Identifies a finger */ +#define MT_TOOL_PEN 1 /* Identifies a pen */ + +#define SYN_MT_REPORT 2 + +/* Convenience constants. */ + +#define BTN_FIRST 0x100 // first button scancode +#define BTN_LAST 0x15f // last button scancode + struct pollfd; namespace android { @@ -34,62 +60,101 @@ namespace android { class KeyLayoutMap; /* - * Grand Central Station for events. With a single call to waitEvent() - * you can wait for: - * - input events from the keypad of a real device - * - input events and meta-events (e.g. "quit") from the simulator - * - synthetic events from the runtime (e.g. "URL fetch completed") - * - real or forged "vsync" events + * Grand Central Station for events. * - * Do not instantiate this class. Instead, call startUp(). + * The event hub aggregates input events received across all known input + * devices on the system, including devices that may be emulated by the simulator + * environment. In addition, the event hub generates fake input events to indicate + * when devices are added or removed. + * + * The event hub provies a stream of input events (via the getEvent function). + * It also supports querying the current actual state of input devices such as identifying + * which keys are currently down. Finally, the event hub keeps track of the capabilities of + * individual input devices, such as their class and the set of key codes that they support. */ -class EventHub : public RefBase +class EventHubInterface : public virtual RefBase { +protected: + EventHubInterface() { } + virtual ~EventHubInterface() { } + +public: + // Synthetic raw event type codes produced when devices are added or removed. + enum { + DEVICE_ADDED = 0x10000000, + DEVICE_REMOVED = 0x20000000 + }; + + virtual uint32_t getDeviceClasses(int32_t deviceId) const = 0; + + virtual String8 getDeviceName(int32_t deviceId) const = 0; + + virtual int getAbsoluteInfo(int32_t deviceId, int axis, int *outMinValue, + int* outMaxValue, int* outFlat, int* outFuzz) const = 0; + + virtual status_t scancodeToKeycode(int32_t deviceId, int scancode, + int32_t* outKeycode, uint32_t* outFlags) const = 0; + + // exclude a particular device from opening + // this can be used to ignore input devices for sensors + virtual void addExcludedDevice(const char* deviceName) = 0; + + /* + * Wait for the next event to become available and return it. + * After returning, the EventHub holds onto a wake lock until the next call to getEvent. + * This ensures that the device will not go to sleep while the event is being processed. + * If the device needs to remain awake longer than that, then the caller is responsible + * for taking care of it (say, by poking the power manager user activity timer). + */ + virtual bool getEvent(int32_t* outDeviceId, int32_t* outType, + int32_t* outScancode, int32_t* outKeycode, uint32_t *outFlags, + int32_t* outValue, nsecs_t* outWhen) = 0; + + /* + * Query current input state. + * deviceId may be -1 to search for the device automatically, filtered by class. + * deviceClasses may be -1 to ignore device class while searching. + */ + virtual int32_t getScanCodeState(int32_t deviceId, int32_t deviceClasses, + int32_t scanCode) const = 0; + virtual int32_t getKeyCodeState(int32_t deviceId, int32_t deviceClasses, + int32_t keyCode) const = 0; + virtual int32_t getSwitchState(int32_t deviceId, int32_t deviceClasses, + int32_t sw) const = 0; + + /* + * Examine key input devices for specific framework keycode support + */ + virtual bool hasKeys(size_t numCodes, const int32_t* keyCodes, + uint8_t* outFlags) const = 0; +}; + +class EventHub : public EventHubInterface { public: EventHub(); - + status_t errorCheck() const; + + virtual uint32_t getDeviceClasses(int32_t deviceId) const; - // bit fields for classes of devices. - enum { - CLASS_KEYBOARD = 0x00000001, - CLASS_ALPHAKEY = 0x00000002, - CLASS_TOUCHSCREEN = 0x00000004, - CLASS_TRACKBALL = 0x00000008, - CLASS_TOUCHSCREEN_MT= 0x00000010, - CLASS_DPAD = 0x00000020 - }; - uint32_t getDeviceClasses(int32_t deviceId) const; - - String8 getDeviceName(int32_t deviceId) const; + virtual String8 getDeviceName(int32_t deviceId) const; - int getAbsoluteInfo(int32_t deviceId, int axis, int *outMinValue, + virtual int getAbsoluteInfo(int32_t deviceId, int axis, int *outMinValue, int* outMaxValue, int* outFlat, int* outFuzz) const; - int getSwitchState(int sw) const; - int getSwitchState(int32_t deviceId, int sw) const; - - int getScancodeState(int key) const; - int getScancodeState(int32_t deviceId, int key) const; - - int getKeycodeState(int key) const; - int getKeycodeState(int32_t deviceId, int key) const; - - status_t scancodeToKeycode(int32_t deviceId, int scancode, + virtual status_t scancodeToKeycode(int32_t deviceId, int scancode, int32_t* outKeycode, uint32_t* outFlags) const; - // exclude a particular device from opening - // this can be used to ignore input devices for sensors - void addExcludedDevice(const char* deviceName); + virtual void addExcludedDevice(const char* deviceName); - // special type codes when devices are added/removed. - enum { - DEVICE_ADDED = 0x10000000, - DEVICE_REMOVED = 0x20000000 - }; - - // examine key input devices for specific framework keycode support - bool hasKeys(size_t numCodes, int32_t* keyCodes, uint8_t* outFlags); + virtual int32_t getScanCodeState(int32_t deviceId, int32_t deviceClasses, + int32_t scanCode) const; + virtual int32_t getKeyCodeState(int32_t deviceId, int32_t deviceClasses, + int32_t keyCode) const; + virtual int32_t getSwitchState(int32_t deviceId, int32_t deviceClasses, + int32_t sw) const; + + virtual bool hasKeys(size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const; virtual bool getEvent(int32_t* outDeviceId, int32_t* outType, int32_t* outScancode, int32_t* outKeycode, uint32_t *outFlags, @@ -126,6 +191,10 @@ private: device_t* getDevice(int32_t deviceId) const; bool hasKeycode(device_t* device, int keycode) const; + int32_t getScanCodeStateLocked(device_t* device, int32_t scanCode) const; + int32_t getKeyCodeStateLocked(device_t* device, int32_t keyCode) const; + int32_t getSwitchStateLocked(device_t* device, int32_t sw) const; + // Protect all internal state. mutable Mutex mLock; @@ -151,7 +220,7 @@ private: // device ids that report particular switches. #ifdef EV_SW - int32_t mSwitches[SW_MAX+1]; + int32_t mSwitches[SW_MAX + 1]; #endif }; diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h index e72b6b3..a3e85a9 100644 --- a/include/ui/GraphicBuffer.h +++ b/include/ui/GraphicBuffer.h @@ -93,10 +93,8 @@ public: void setIndex(int index); int getIndex() const; - void setVerticalStride(uint32_t vstride); - uint32_t getVerticalStride() const; -protected: +private: virtual ~GraphicBuffer(); enum { @@ -105,8 +103,12 @@ protected: ownData = 2, }; - inline const GraphicBufferMapper& getBufferMapper() const { return mBufferMapper; } - inline GraphicBufferMapper& getBufferMapper() { return mBufferMapper; } + inline const GraphicBufferMapper& getBufferMapper() const { + return mBufferMapper; + } + inline GraphicBufferMapper& getBufferMapper() { + return mBufferMapper; + } uint8_t mOwner; private: @@ -134,7 +136,6 @@ private: GraphicBufferMapper& mBufferMapper; ssize_t mInitCheck; - uint32_t mVStride; int mIndex; }; diff --git a/include/ui/GraphicBufferAllocator.h b/include/ui/GraphicBufferAllocator.h index 741d763..54b8236 100644 --- a/include/ui/GraphicBufferAllocator.h +++ b/include/ui/GraphicBufferAllocator.h @@ -73,9 +73,9 @@ private: struct alloc_rec_t { uint32_t w; uint32_t h; + uint32_t s; PixelFormat format; uint32_t usage; - void* vaddr; size_t size; }; diff --git a/include/ui/Input.h b/include/ui/Input.h new file mode 100644 index 0000000..92ff872 --- /dev/null +++ b/include/ui/Input.h @@ -0,0 +1,370 @@ +/* + * 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 _UI_INPUT_H +#define _UI_INPUT_H + +/** + * Native input event structures. + */ + +#include <android/input.h> +#include <utils/Vector.h> +#include <utils/Timers.h> + +/* + * Additional private constants not defined in ndk/ui/input.h. + */ +enum { + /* + * Private control to determine when an app is tracking a key sequence. + */ + KEY_EVENT_FLAG_START_TRACKING = 0x40000000 +}; + +/* + * Maximum number of pointers supported per motion event. + */ +#define MAX_POINTERS 10 + +namespace android { + +/* + * A raw event as retrieved from the EventHub. + */ +struct RawEvent { + nsecs_t when; + int32_t deviceId; + int32_t type; + int32_t scanCode; + int32_t keyCode; + int32_t value; + uint32_t flags; +}; + +/* + * Flags that flow alongside events in the input dispatch system to help with certain + * policy decisions such as waking from device sleep. + * + * TODO This enumeration should probably be split up or relabeled for clarity. + */ +enum { + /* These flags originate in RawEvents and are generally set in the key map. */ + + POLICY_FLAG_WAKE = 0x00000001, + POLICY_FLAG_WAKE_DROPPED = 0x00000002, + POLICY_FLAG_SHIFT = 0x00000004, + POLICY_FLAG_CAPS_LOCK = 0x00000008, + POLICY_FLAG_ALT = 0x00000010, + POLICY_FLAG_ALT_GR = 0x00000020, + POLICY_FLAG_MENU = 0x00000040, + POLICY_FLAG_LAUNCHER = 0x00000080, + + /* These flags are set by the input reader policy as it intercepts each event. */ + + // Indicates that the screen was off when the event was received and the event + // should wake the device. + POLICY_FLAG_WOKE_HERE = 0x10000000, + + // Indicates that the screen was dim when the event was received and the event + // should brighten the device. + POLICY_FLAG_BRIGHT_HERE = 0x20000000, +}; + +/* + * Describes the basic configuration of input devices that are present. + */ +struct InputConfiguration { + enum { + TOUCHSCREEN_UNDEFINED = 0, + TOUCHSCREEN_NOTOUCH = 1, + TOUCHSCREEN_STYLUS = 2, + TOUCHSCREEN_FINGER = 3 + }; + + enum { + KEYBOARD_UNDEFINED = 0, + KEYBOARD_NOKEYS = 1, + KEYBOARD_QWERTY = 2, + KEYBOARD_12KEY = 3 + }; + + enum { + NAVIGATION_UNDEFINED = 0, + NAVIGATION_NONAV = 1, + NAVIGATION_DPAD = 2, + NAVIGATION_TRACKBALL = 3, + NAVIGATION_WHEEL = 4 + }; + + int32_t touchScreen; + int32_t keyboard; + int32_t navigation; +}; + +/* + * Pointer coordinate data. + */ +struct PointerCoords { + float x; + float y; + float pressure; + float size; +}; + +/* + * Input events. + */ +struct input_event_t { }; + +class InputEvent : public input_event_t { +public: + virtual ~InputEvent() { } + + virtual int32_t getType() const = 0; + + inline int32_t getDeviceId() const { return mDeviceId; } + + inline int32_t getNature() const { return mNature; } + +protected: + void initialize(int32_t deviceId, int32_t nature); + +private: + int32_t mDeviceId; + int32_t mNature; +}; + +/* + * Key events. + */ +class KeyEvent : public InputEvent { +public: + virtual ~KeyEvent() { } + + virtual int32_t getType() const { return INPUT_EVENT_TYPE_KEY; } + + inline int32_t getAction() const { return mAction; } + + inline int32_t getFlags() const { return mFlags; } + + inline int32_t getKeyCode() const { return mKeyCode; } + + inline int32_t getScanCode() const { return mScanCode; } + + inline int32_t getMetaState() const { return mMetaState; } + + inline int32_t getRepeatCount() const { return mRepeatCount; } + + inline nsecs_t getDownTime() const { return mDownTime; } + + inline nsecs_t getEventTime() const { return mEventTime; } + + void initialize( + int32_t deviceId, + int32_t nature, + int32_t action, + int32_t flags, + int32_t keyCode, + int32_t scanCode, + int32_t metaState, + int32_t repeatCount, + nsecs_t downTime, + nsecs_t eventTime); + +private: + int32_t mAction; + int32_t mFlags; + int32_t mKeyCode; + int32_t mScanCode; + int32_t mMetaState; + int32_t mRepeatCount; + nsecs_t mDownTime; + nsecs_t mEventTime; +}; + +/* + * Motion events. + */ +class MotionEvent : public InputEvent { +public: + virtual ~MotionEvent() { } + + virtual int32_t getType() const { return INPUT_EVENT_TYPE_MOTION; } + + inline int32_t getAction() const { return mAction; } + + inline int32_t getEdgeFlags() const { return mEdgeFlags; } + + inline int32_t getMetaState() const { return mMetaState; } + + inline float getXOffset() const { return mXOffset; } + + inline float getYOffset() const { return mYOffset; } + + inline float getXPrecision() const { return mXPrecision; } + + inline float getYPrecision() const { return mYPrecision; } + + inline nsecs_t getDownTime() const { return mDownTime; } + + inline size_t getPointerCount() const { return mPointerIds.size(); } + + inline int32_t getPointerId(size_t pointerIndex) const { return mPointerIds[pointerIndex]; } + + inline nsecs_t getEventTime() const { return mSampleEventTimes[getHistorySize()]; } + + inline float getRawX(size_t pointerIndex) const { + return getCurrentPointerCoords(pointerIndex).x; + } + + inline float getRawY(size_t pointerIndex) const { + return getCurrentPointerCoords(pointerIndex).y; + } + + inline float getX(size_t pointerIndex) const { + return getRawX(pointerIndex) + mXOffset; + } + + inline float getY(size_t pointerIndex) const { + return getRawY(pointerIndex) + mYOffset; + } + + inline float getPressure(size_t pointerIndex) const { + return getCurrentPointerCoords(pointerIndex).pressure; + } + + inline float getSize(size_t pointerIndex) const { + return getCurrentPointerCoords(pointerIndex).size; + } + + inline size_t getHistorySize() const { return mSampleEventTimes.size() - 1; } + + inline nsecs_t getHistoricalEventTime(size_t historicalIndex) const { + return mSampleEventTimes[historicalIndex]; + } + + inline float getHistoricalRawX(size_t pointerIndex, size_t historicalIndex) const { + return getHistoricalPointerCoords(pointerIndex, historicalIndex).x; + } + + inline float getHistoricalRawY(size_t pointerIndex, size_t historicalIndex) const { + return getHistoricalPointerCoords(pointerIndex, historicalIndex).y; + } + + inline float getHistoricalX(size_t pointerIndex, size_t historicalIndex) const { + return getHistoricalRawX(pointerIndex, historicalIndex) + mXOffset; + } + + inline float getHistoricalY(size_t pointerIndex, size_t historicalIndex) const { + return getHistoricalRawY(pointerIndex, historicalIndex) + mYOffset; + } + + inline float getHistoricalPressure(size_t pointerIndex, size_t historicalIndex) const { + return getHistoricalPointerCoords(pointerIndex, historicalIndex).pressure; + } + + inline float getHistoricalSize(size_t pointerIndex, size_t historicalIndex) const { + return getHistoricalPointerCoords(pointerIndex, historicalIndex).size; + } + + void initialize( + int32_t deviceId, + int32_t nature, + int32_t action, + int32_t edgeFlags, + int32_t metaState, + float xOffset, + float yOffset, + float xPrecision, + float yPrecision, + nsecs_t downTime, + nsecs_t eventTime, + size_t pointerCount, + const int32_t* pointerIds, + const PointerCoords* pointerCoords); + + void addSample( + nsecs_t eventTime, + const PointerCoords* pointerCoords); + + void offsetLocation(float xOffset, float yOffset); + + // Low-level accessors. + inline const int32_t* getPointerIds() const { return mPointerIds.array(); } + inline const nsecs_t* getSampleEventTimes() const { return mSampleEventTimes.array(); } + inline const PointerCoords* getSamplePointerCoords() const { + return mSamplePointerCoords.array(); + } + +private: + int32_t mAction; + int32_t mEdgeFlags; + int32_t mMetaState; + float mXOffset; + float mYOffset; + float mXPrecision; + float mYPrecision; + nsecs_t mDownTime; + Vector<int32_t> mPointerIds; + Vector<nsecs_t> mSampleEventTimes; + Vector<PointerCoords> mSamplePointerCoords; + + inline const PointerCoords& getCurrentPointerCoords(size_t pointerIndex) const { + return mSamplePointerCoords[getHistorySize() * getPointerCount() + pointerIndex]; + } + + inline const PointerCoords& getHistoricalPointerCoords( + size_t pointerIndex, size_t historicalIndex) const { + return mSamplePointerCoords[historicalIndex * getPointerCount() + pointerIndex]; + } +}; + +/* + * Input event factory. + */ +class InputEventFactoryInterface { +protected: + virtual ~InputEventFactoryInterface() { } + +public: + InputEventFactoryInterface() { } + + virtual KeyEvent* createKeyEvent() = 0; + virtual MotionEvent* createMotionEvent() = 0; +}; + +/* + * A simple input event factory implementation that uses a single preallocated instance + * of each type of input event that are reused for each request. + */ +class PreallocatedInputEventFactory : public InputEventFactoryInterface { +public: + PreallocatedInputEventFactory() { } + virtual ~PreallocatedInputEventFactory() { } + + virtual KeyEvent* createKeyEvent() { return & mKeyEvent; } + virtual MotionEvent* createMotionEvent() { return & mMotionEvent; } + +private: + KeyEvent mKeyEvent; + MotionEvent mMotionEvent; +}; + + +} // namespace android + +#endif // _UI_INPUT_H diff --git a/include/ui/InputDispatcher.h b/include/ui/InputDispatcher.h new file mode 100644 index 0000000..80a20c9 --- /dev/null +++ b/include/ui/InputDispatcher.h @@ -0,0 +1,549 @@ +/* + * 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 _UI_INPUT_DISPATCHER_H +#define _UI_INPUT_DISPATCHER_H + +#include <ui/Input.h> +#include <ui/InputTransport.h> +#include <utils/KeyedVector.h> +#include <utils/Vector.h> +#include <utils/threads.h> +#include <utils/Timers.h> +#include <utils/RefBase.h> +#include <utils/String8.h> +#include <utils/PollLoop.h> +#include <utils/Pool.h> + +#include <stddef.h> +#include <unistd.h> + + +namespace android { + +/* + * An input target specifies how an input event is to be dispatched to a particular window + * including the window's input channel, control flags, a timeout, and an X / Y offset to + * be added to input event coordinates to compensate for the absolute position of the + * window area. + */ +struct InputTarget { + enum { + /* This flag indicates that subsequent event delivery should be held until the + * current event is delivered to this target or a timeout occurs. */ + FLAG_SYNC = 0x01, + + /* This flag indicates that a MotionEvent with ACTION_DOWN falls outside of the area of + * this target and so should instead be delivered as an ACTION_OUTSIDE to this target. */ + FLAG_OUTSIDE = 0x02, + + /* This flag indicates that a KeyEvent or MotionEvent is being canceled. + * In the case of a key event, it should be delivered with KeyEvent.FLAG_CANCELED set. + * In the case of a motion event, it should be delivered as MotionEvent.ACTION_CANCEL. */ + FLAG_CANCEL = 0x04 + }; + + // The input channel to be targeted. + sp<InputChannel> inputChannel; + + // Flags for the input target. + int32_t flags; + + // The timeout for event delivery to this target in nanoseconds. Or -1 if none. + nsecs_t timeout; + + // The x and y offset to add to a MotionEvent as it is delivered. + // (ignored for KeyEvents) + float xOffset, yOffset; +}; + +/* + * Input dispatcher policy interface. + * + * The input reader policy is used by the input reader to interact with the Window Manager + * and other system components. + * + * The actual implementation is partially supported by callbacks into the DVM + * via JNI. This interface is also mocked in the unit tests. + */ +class InputDispatcherPolicyInterface : public virtual RefBase { +protected: + InputDispatcherPolicyInterface() { } + virtual ~InputDispatcherPolicyInterface() { } + +public: + /* Notifies the system that a configuration change has occurred. */ + virtual void notifyConfigurationChanged(nsecs_t when) = 0; + + /* Notifies the system that an input channel is unrecoverably broken. */ + virtual void notifyInputChannelBroken(const sp<InputChannel>& inputChannel) = 0; + + /* Notifies the system that an input channel is not responding. */ + virtual void notifyInputChannelANR(const sp<InputChannel>& inputChannel) = 0; + + /* Notifies the system that an input channel recovered from ANR. */ + virtual void notifyInputChannelRecoveredFromANR(const sp<InputChannel>& inputChannel) = 0; + + /* Gets the key repeat timeout or -1 if automatic key repeating is disabled. */ + virtual nsecs_t getKeyRepeatTimeout() = 0; + + /* Gets the input targets for a key event. */ + virtual void getKeyEventTargets(KeyEvent* keyEvent, uint32_t policyFlags, + Vector<InputTarget>& outTargets) = 0; + + /* Gets the input targets for a motion event. */ + virtual void getMotionEventTargets(MotionEvent* motionEvent, uint32_t policyFlags, + Vector<InputTarget>& outTargets) = 0; +}; + + +/* Notifies the system about input events generated by the input reader. + * The dispatcher is expected to be mostly asynchronous. */ +class InputDispatcherInterface : public virtual RefBase { +protected: + InputDispatcherInterface() { } + virtual ~InputDispatcherInterface() { } + +public: + /* Runs a single iteration of the dispatch loop. + * Nominally processes one queued event, a timeout, or a response from an input consumer. + * + * This method should only be called on the input dispatcher thread. + */ + virtual void dispatchOnce() = 0; + + /* Notifies the dispatcher about new events. + * + * These methods should only be called on the input reader thread. + */ + virtual void notifyConfigurationChanged(nsecs_t eventTime) = 0; + virtual void notifyAppSwitchComing(nsecs_t eventTime) = 0; + virtual void notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t nature, + uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode, + int32_t scanCode, int32_t metaState, nsecs_t downTime) = 0; + virtual void notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t nature, + uint32_t policyFlags, int32_t action, int32_t metaState, int32_t edgeFlags, + uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords, + float xPrecision, float yPrecision, nsecs_t downTime) = 0; + + /* Registers or unregister input channels that may be used as targets for input events. + * + * These methods may be called on any thread (usually by the input manager). + */ + virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel) = 0; + virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) = 0; +}; + +/* Dispatches events to input targets. Some functions of the input dispatcher, such as + * identifying input targets, are controlled by a separate policy object. + * + * IMPORTANT INVARIANT: + * Because the policy can potentially block or cause re-entrance into the input dispatcher, + * the input dispatcher never calls into the policy while holding its internal locks. + * The implementation is also carefully designed to recover from scenarios such as an + * input channel becoming unregistered while identifying input targets or processing timeouts. + * + * Methods marked 'Locked' must be called with the lock acquired. + * + * Methods marked 'LockedInterruptible' must be called with the lock acquired but + * may during the course of their execution release the lock, call into the policy, and + * then reacquire the lock. The caller is responsible for recovering gracefully. + * + * A 'LockedInterruptible' method may called a 'Locked' method, but NOT vice-versa. + */ +class InputDispatcher : public InputDispatcherInterface { +protected: + virtual ~InputDispatcher(); + +public: + explicit InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy); + + virtual void dispatchOnce(); + + virtual void notifyConfigurationChanged(nsecs_t eventTime); + virtual void notifyAppSwitchComing(nsecs_t eventTime); + virtual void notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t nature, + uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode, + int32_t scanCode, int32_t metaState, nsecs_t downTime); + virtual void notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t nature, + uint32_t policyFlags, int32_t action, int32_t metaState, int32_t edgeFlags, + uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords, + float xPrecision, float yPrecision, nsecs_t downTime); + + virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel); + virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel); + +private: + template <typename T> + struct Link { + T* next; + T* prev; + }; + + struct EventEntry : Link<EventEntry> { + enum { + TYPE_SENTINEL, + TYPE_CONFIGURATION_CHANGED, + TYPE_KEY, + TYPE_MOTION + }; + + int32_t refCount; + int32_t type; + nsecs_t eventTime; + + bool dispatchInProgress; // initially false, set to true while dispatching + }; + + struct ConfigurationChangedEntry : EventEntry { + }; + + struct KeyEntry : EventEntry { + int32_t deviceId; + int32_t nature; + uint32_t policyFlags; + int32_t action; + int32_t flags; + int32_t keyCode; + int32_t scanCode; + int32_t metaState; + int32_t repeatCount; + nsecs_t downTime; + }; + + struct MotionSample { + MotionSample* next; + + nsecs_t eventTime; + PointerCoords pointerCoords[MAX_POINTERS]; + }; + + struct MotionEntry : EventEntry { + int32_t deviceId; + int32_t nature; + uint32_t policyFlags; + int32_t action; + int32_t metaState; + int32_t edgeFlags; + float xPrecision; + float yPrecision; + nsecs_t downTime; + uint32_t pointerCount; + int32_t pointerIds[MAX_POINTERS]; + + // Linked list of motion samples associated with this motion event. + MotionSample firstSample; + MotionSample* lastSample; + }; + + // Tracks the progress of dispatching a particular event to a particular connection. + struct DispatchEntry : Link<DispatchEntry> { + EventEntry* eventEntry; // the event to dispatch + int32_t targetFlags; + float xOffset; + float yOffset; + nsecs_t timeout; + + // True if dispatch has started. + bool inProgress; + + // For motion events: + // Pointer to the first motion sample to dispatch in this cycle. + // Usually NULL to indicate that the list of motion samples begins at + // MotionEntry::firstSample. Otherwise, some samples were dispatched in a previous + // cycle and this pointer indicates the location of the first remainining sample + // to dispatch during the current cycle. + MotionSample* headMotionSample; + // Pointer to a motion sample to dispatch in the next cycle if the dispatcher was + // unable to send all motion samples during this cycle. On the next cycle, + // headMotionSample will be initialized to tailMotionSample and tailMotionSample + // will be set to NULL. + MotionSample* tailMotionSample; + }; + + // A command entry captures state and behavior for an action to be performed in the + // dispatch loop after the initial processing has taken place. It is essentially + // a kind of continuation used to postpone sensitive policy interactions to a point + // in the dispatch loop where it is safe to release the lock (generally after finishing + // the critical parts of the dispatch cycle). + // + // The special thing about commands is that they can voluntarily release and reacquire + // the dispatcher lock at will. Initially when the command starts running, the + // dispatcher lock is held. However, if the command needs to call into the policy to + // do some work, it can release the lock, do the work, then reacquire the lock again + // before returning. + // + // This mechanism is a bit clunky but it helps to preserve the invariant that the dispatch + // never calls into the policy while holding its lock. + // + // Commands are implicitly 'LockedInterruptible'. + struct CommandEntry; + typedef void (InputDispatcher::*Command)(CommandEntry* commandEntry); + + struct CommandEntry : Link<CommandEntry> { + CommandEntry(); + ~CommandEntry(); + + Command command; + + // parameters for the command (usage varies by command) + sp<InputChannel> inputChannel; + }; + + // Generic queue implementation. + template <typename T> + struct Queue { + T head; + T tail; + + inline Queue() { + head.prev = NULL; + head.next = & tail; + tail.prev = & head; + tail.next = NULL; + } + + inline bool isEmpty() { + return head.next == & tail; + } + + inline void enqueueAtTail(T* entry) { + T* last = tail.prev; + last->next = entry; + entry->prev = last; + entry->next = & tail; + tail.prev = entry; + } + + inline void enqueueAtHead(T* entry) { + T* first = head.next; + head.next = entry; + entry->prev = & head; + entry->next = first; + first->prev = entry; + } + + inline void dequeue(T* entry) { + entry->prev->next = entry->next; + entry->next->prev = entry->prev; + } + + inline T* dequeueAtHead() { + T* first = head.next; + dequeue(first); + return first; + } + }; + + /* Allocates queue entries and performs reference counting as needed. */ + class Allocator { + public: + Allocator(); + + ConfigurationChangedEntry* obtainConfigurationChangedEntry(); + KeyEntry* obtainKeyEntry(); + MotionEntry* obtainMotionEntry(); + DispatchEntry* obtainDispatchEntry(EventEntry* eventEntry); + CommandEntry* obtainCommandEntry(Command command); + + void releaseEventEntry(EventEntry* entry); + void releaseConfigurationChangedEntry(ConfigurationChangedEntry* entry); + void releaseKeyEntry(KeyEntry* entry); + void releaseMotionEntry(MotionEntry* entry); + void releaseDispatchEntry(DispatchEntry* entry); + void releaseCommandEntry(CommandEntry* entry); + + void appendMotionSample(MotionEntry* motionEntry, + nsecs_t eventTime, int32_t pointerCount, const PointerCoords* pointerCoords); + + private: + Pool<ConfigurationChangedEntry> mConfigurationChangeEntryPool; + Pool<KeyEntry> mKeyEntryPool; + Pool<MotionEntry> mMotionEntryPool; + Pool<MotionSample> mMotionSamplePool; + Pool<DispatchEntry> mDispatchEntryPool; + Pool<CommandEntry> mCommandEntryPool; + }; + + /* Manages the dispatch state associated with a single input channel. */ + class Connection : public RefBase { + protected: + virtual ~Connection(); + + public: + enum Status { + // Everything is peachy. + STATUS_NORMAL, + // An unrecoverable communication error has occurred. + STATUS_BROKEN, + // The client is not responding. + STATUS_NOT_RESPONDING, + // The input channel has been unregistered. + STATUS_ZOMBIE + }; + + Status status; + sp<InputChannel> inputChannel; + InputPublisher inputPublisher; + Queue<DispatchEntry> outboundQueue; + nsecs_t nextTimeoutTime; // next timeout time (LONG_LONG_MAX if none) + + nsecs_t lastEventTime; // the time when the event was originally captured + nsecs_t lastDispatchTime; // the time when the last event was dispatched + nsecs_t lastANRTime; // the time when the last ANR was recorded + + explicit Connection(const sp<InputChannel>& inputChannel); + + inline const char* getInputChannelName() const { return inputChannel->getName().string(); } + + const char* getStatusLabel() const; + + // Finds a DispatchEntry in the outbound queue associated with the specified event. + // Returns NULL if not found. + DispatchEntry* findQueuedDispatchEntryForEvent(const EventEntry* eventEntry) const; + + // Determine whether this connection has a pending synchronous dispatch target. + // Since there can only ever be at most one such target at a time, if there is one, + // it must be at the tail because nothing else can be enqueued after it. + inline bool hasPendingSyncTarget() { + return ! outboundQueue.isEmpty() + && (outboundQueue.tail.prev->targetFlags & InputTarget::FLAG_SYNC); + } + + // Gets the time since the current event was originally obtained from the input driver. + inline double getEventLatencyMillis(nsecs_t currentTime) { + return (currentTime - lastEventTime) / 1000000.0; + } + + // Gets the time since the current event entered the outbound dispatch queue. + inline double getDispatchLatencyMillis(nsecs_t currentTime) { + return (currentTime - lastDispatchTime) / 1000000.0; + } + + // Gets the time since the current event ANR was declared, if applicable. + inline double getANRLatencyMillis(nsecs_t currentTime) { + return (currentTime - lastANRTime) / 1000000.0; + } + + status_t initialize(); + }; + + sp<InputDispatcherPolicyInterface> mPolicy; + + Mutex mLock; + + Allocator mAllocator; + sp<PollLoop> mPollLoop; + + Queue<EventEntry> mInboundQueue; + Queue<CommandEntry> mCommandQueue; + + // All registered connections mapped by receive pipe file descriptor. + KeyedVector<int, sp<Connection> > mConnectionsByReceiveFd; + + // Active connections are connections that have a non-empty outbound queue. + Vector<Connection*> mActiveConnections; + + // Preallocated key and motion event objects used only to ask the input dispatcher policy + // for the targets of an event that is to be dispatched. + KeyEvent mReusableKeyEvent; + MotionEvent mReusableMotionEvent; + + // The input targets that were most recently identified for dispatch. + // If there is a synchronous event dispatch in progress, the current input targets will + // remain unchanged until the dispatch has completed or been aborted. + Vector<InputTarget> mCurrentInputTargets; + bool mCurrentInputTargetsValid; // false while targets are being recomputed + + // Key repeat tracking. + // XXX Move this up to the input reader instead. + struct KeyRepeatState { + KeyEntry* lastKeyEntry; // or null if no repeat + nsecs_t nextRepeatTime; + } mKeyRepeatState; + + void resetKeyRepeatLocked(); + + // Deferred command processing. + bool runCommandsLockedInterruptible(); + CommandEntry* postCommandLocked(Command command); + + // Process events that have just been dequeued from the head of the input queue. + void processConfigurationChangedLockedInterruptible( + nsecs_t currentTime, ConfigurationChangedEntry* entry); + void processKeyLockedInterruptible( + nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout); + void processKeyRepeatLockedInterruptible( + nsecs_t currentTime, nsecs_t keyRepeatTimeout); + void processMotionLockedInterruptible( + nsecs_t currentTime, MotionEntry* entry); + + // Identify input targets for an event and dispatch to them. + void identifyInputTargetsAndDispatchKeyLockedInterruptible( + nsecs_t currentTime, KeyEntry* entry); + void identifyInputTargetsAndDispatchMotionLockedInterruptible( + nsecs_t currentTime, MotionEntry* entry); + void dispatchEventToCurrentInputTargetsLocked( + nsecs_t currentTime, EventEntry* entry, bool resumeWithAppendedMotionSample); + + // Manage the dispatch cycle for a single connection. + void prepareDispatchCycleLocked(nsecs_t currentTime, Connection* connection, + EventEntry* eventEntry, const InputTarget* inputTarget, + bool resumeWithAppendedMotionSample); + void startDispatchCycleLocked(nsecs_t currentTime, Connection* connection); + void finishDispatchCycleLocked(nsecs_t currentTime, Connection* connection); + bool timeoutDispatchCycleLocked(nsecs_t currentTime, Connection* connection); + bool abortDispatchCycleLocked(nsecs_t currentTime, Connection* connection, + bool broken); + static bool handleReceiveCallback(int receiveFd, int events, void* data); + + // Add or remove a connection to the mActiveConnections vector. + void activateConnectionLocked(Connection* connection); + void deactivateConnectionLocked(Connection* connection); + + // Outbound policy interactions. + void doNotifyConfigurationChangedLockedInterruptible(CommandEntry* commandEntry); + + // Interesting events that we might like to log or tell the framework about. + void onDispatchCycleStartedLocked( + nsecs_t currentTime, Connection* connection); + void onDispatchCycleFinishedLocked( + nsecs_t currentTime, Connection* connection, bool recoveredFromANR); + void onDispatchCycleANRLocked( + nsecs_t currentTime, Connection* connection); + void onDispatchCycleBrokenLocked( + nsecs_t currentTime, Connection* connection); + + void doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry); + void doNotifyInputChannelANRLockedInterruptible(CommandEntry* commandEntry); + void doNotifyInputChannelRecoveredFromANRLockedInterruptible(CommandEntry* commandEntry); +}; + +/* Enqueues and dispatches input events, endlessly. */ +class InputDispatcherThread : public Thread { +public: + explicit InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher); + ~InputDispatcherThread(); + +private: + virtual bool threadLoop(); + + sp<InputDispatcherInterface> mDispatcher; +}; + +} // namespace android + +#endif // _UI_INPUT_DISPATCHER_PRIV_H diff --git a/include/ui/InputManager.h b/include/ui/InputManager.h new file mode 100644 index 0000000..3872c26 --- /dev/null +++ b/include/ui/InputManager.h @@ -0,0 +1,142 @@ +/* + * 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 _UI_INPUT_MANAGER_H +#define _UI_INPUT_MANAGER_H + +/** + * Native input manager. + */ + +#include <ui/EventHub.h> +#include <ui/Input.h> +#include <utils/Errors.h> +#include <utils/Vector.h> +#include <utils/Timers.h> +#include <utils/RefBase.h> +#include <utils/String8.h> + +namespace android { + +class InputChannel; + +class InputReaderInterface; +class InputReaderPolicyInterface; +class InputReaderThread; + +class InputDispatcherInterface; +class InputDispatcherPolicyInterface; +class InputDispatcherThread; + +/* + * The input manager is the core of the system event processing. + * + * The input manager uses two threads. + * + * 1. The InputReaderThread (called "InputReader") reads and preprocesses raw input events, + * applies policy, and posts messages to a queue managed by the DispatcherThread. + * 2. The InputDispatcherThread (called "InputDispatcher") thread waits for new events on the + * queue and asynchronously dispatches them to applications. + * + * By design, the InputReaderThread class and InputDispatcherThread class do not share any + * internal state. Moreover, all communication is done one way from the InputReaderThread + * into the InputDispatcherThread and never the reverse. Both classes may interact with the + * InputDispatchPolicy, however. + * + * The InputManager class never makes any calls into Java itself. Instead, the + * InputDispatchPolicy is responsible for performing all external interactions with the + * system, including calling DVM services. + */ +class InputManagerInterface : public virtual RefBase { +protected: + InputManagerInterface() { } + virtual ~InputManagerInterface() { } + +public: + /* Starts the input manager threads. */ + virtual status_t start() = 0; + + /* Stops the input manager threads and waits for them to exit. */ + virtual status_t stop() = 0; + + /* Registers an input channel prior to using it as the target of an event. */ + virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel) = 0; + + /* Unregisters an input channel. */ + virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) = 0; + + /* Gets input device configuration. */ + virtual void getInputConfiguration(InputConfiguration* outConfiguration) const = 0; + + /* + * Queries current input state. + * deviceId may be -1 to search for the device automatically, filtered by class. + * deviceClasses may be -1 to ignore device class while searching. + */ + virtual int32_t getScanCodeState(int32_t deviceId, int32_t deviceClasses, + int32_t scanCode) const = 0; + virtual int32_t getKeyCodeState(int32_t deviceId, int32_t deviceClasses, + int32_t keyCode) const = 0; + virtual int32_t getSwitchState(int32_t deviceId, int32_t deviceClasses, + int32_t sw) const = 0; + + /* Determines whether physical keys exist for the given framework-domain key codes. */ + virtual bool hasKeys(size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const = 0; +}; + +class InputManager : public InputManagerInterface { +protected: + virtual ~InputManager(); + +public: + InputManager( + const sp<EventHubInterface>& eventHub, + const sp<InputReaderPolicyInterface>& readerPolicy, + const sp<InputDispatcherPolicyInterface>& dispatcherPolicy); + + // (used for testing purposes) + InputManager( + const sp<InputReaderInterface>& reader, + const sp<InputDispatcherInterface>& dispatcher); + + virtual status_t start(); + virtual status_t stop(); + + virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel); + virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel); + + virtual void getInputConfiguration(InputConfiguration* outConfiguration) const; + virtual int32_t getScanCodeState(int32_t deviceId, int32_t deviceClasses, + int32_t scanCode) const; + virtual int32_t getKeyCodeState(int32_t deviceId, int32_t deviceClasses, + int32_t keyCode) const; + virtual int32_t getSwitchState(int32_t deviceId, int32_t deviceClasses, + int32_t sw) const; + virtual bool hasKeys(size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const; + +private: + sp<InputReaderInterface> mReader; + sp<InputReaderThread> mReaderThread; + + sp<InputDispatcherInterface> mDispatcher; + sp<InputDispatcherThread> mDispatcherThread; + + void initialize(); +}; + +} // namespace android + +#endif // _UI_INPUT_MANAGER_H diff --git a/include/ui/InputReader.h b/include/ui/InputReader.h new file mode 100644 index 0000000..d76b8fe --- /dev/null +++ b/include/ui/InputReader.h @@ -0,0 +1,621 @@ +/* + * 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 _UI_INPUT_READER_H +#define _UI_INPUT_READER_H + +#include <ui/EventHub.h> +#include <ui/Input.h> +#include <ui/InputDispatcher.h> +#include <utils/KeyedVector.h> +#include <utils/threads.h> +#include <utils/Timers.h> +#include <utils/RefBase.h> +#include <utils/String8.h> +#include <utils/BitSet.h> + +#include <stddef.h> +#include <unistd.h> + +/* Maximum pointer id value supported. + * (This is limited by our use of BitSet32 to track pointer assignments.) */ +#define MAX_POINTER_ID 32 + +/* Maximum number of historical samples to average. */ +#define AVERAGING_HISTORY_SIZE 5 + + +namespace android { + +extern int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState); +extern int32_t rotateKeyCode(int32_t keyCode, int32_t orientation); + +/* + * An input device structure tracks the state of a single input device. + * + * This structure is only used by ReaderThread and is not intended to be shared with + * DispatcherThread (because that would require locking). This works out fine because + * DispatcherThread is only interested in cooked event data anyways and does not need + * any of the low-level data from InputDevice. + */ +struct InputDevice { + struct AbsoluteAxisInfo { + int32_t minValue; // minimum value + int32_t maxValue; // maximum value + int32_t range; // range of values, equal to maxValue - minValue + int32_t flat; // center flat position, eg. flat == 8 means center is between -8 and 8 + int32_t fuzz; // error tolerance, eg. fuzz == 4 means value is +/- 4 due to noise + }; + + struct VirtualKey { + int32_t keyCode; + int32_t scanCode; + uint32_t flags; + + // computed hit box, specified in touch screen coords based on known display size + int32_t hitLeft; + int32_t hitTop; + int32_t hitRight; + int32_t hitBottom; + + inline bool isHit(int32_t x, int32_t y) const { + return x >= hitLeft && x <= hitRight && y >= hitTop && y <= hitBottom; + } + }; + + struct KeyboardState { + struct Current { + int32_t metaState; + nsecs_t downTime; // time of most recent key down + } current; + + void reset(); + }; + + struct TrackballState { + struct Accumulator { + enum { + FIELD_BTN_MOUSE = 1, + FIELD_REL_X = 2, + FIELD_REL_Y = 4 + }; + + uint32_t fields; + + bool btnMouse; + int32_t relX; + int32_t relY; + + inline void clear() { + fields = 0; + } + + inline bool isDirty() { + return fields != 0; + } + } accumulator; + + struct Current { + bool down; + nsecs_t downTime; + } current; + + struct Precalculated { + float xScale; + float yScale; + float xPrecision; + float yPrecision; + } precalculated; + + void reset(); + }; + + struct SingleTouchScreenState { + struct Accumulator { + enum { + FIELD_BTN_TOUCH = 1, + FIELD_ABS_X = 2, + FIELD_ABS_Y = 4, + FIELD_ABS_PRESSURE = 8, + FIELD_ABS_TOOL_WIDTH = 16 + }; + + uint32_t fields; + + bool btnTouch; + int32_t absX; + int32_t absY; + int32_t absPressure; + int32_t absToolWidth; + + inline void clear() { + fields = 0; + } + + inline bool isDirty() { + return fields != 0; + } + } accumulator; + + struct Current { + bool down; + int32_t x; + int32_t y; + int32_t pressure; + int32_t size; + } current; + + void reset(); + }; + + struct MultiTouchScreenState { + struct Accumulator { + enum { + FIELD_ABS_MT_POSITION_X = 1, + FIELD_ABS_MT_POSITION_Y = 2, + FIELD_ABS_MT_TOUCH_MAJOR = 4, + FIELD_ABS_MT_WIDTH_MAJOR = 8, + FIELD_ABS_MT_TRACKING_ID = 16 + }; + + uint32_t pointerCount; + struct Pointer { + uint32_t fields; + + int32_t absMTPositionX; + int32_t absMTPositionY; + int32_t absMTTouchMajor; + int32_t absMTWidthMajor; + int32_t absMTTrackingId; + + inline void clear() { + fields = 0; + } + } pointers[MAX_POINTERS + 1]; // + 1 to remove the need for extra range checks + + inline void clear() { + pointerCount = 0; + pointers[0].clear(); + } + + inline bool isDirty() { + return pointerCount != 0; + } + } accumulator; + + void reset(); + }; + + struct PointerData { + uint32_t id; + int32_t x; + int32_t y; + int32_t pressure; + int32_t size; + }; + + struct TouchData { + uint32_t pointerCount; + PointerData pointers[MAX_POINTERS]; + BitSet32 idBits; + uint32_t idToIndex[MAX_POINTER_ID]; + + void copyFrom(const TouchData& other); + + inline void clear() { + pointerCount = 0; + idBits.clear(); + } + }; + + // common state used for both single-touch and multi-touch screens after the initial + // touch decoding has been performed + struct TouchScreenState { + Vector<VirtualKey> virtualKeys; + + struct Parameters { + bool useBadTouchFilter; + bool useJumpyTouchFilter; + bool useAveragingTouchFilter; + + AbsoluteAxisInfo xAxis; + AbsoluteAxisInfo yAxis; + AbsoluteAxisInfo pressureAxis; + AbsoluteAxisInfo sizeAxis; + } parameters; + + // The touch data of the current sample being processed. + TouchData currentTouch; + + // The touch data of the previous sample that was processed. This is updated + // incrementally while the current sample is being processed. + TouchData lastTouch; + + // The time the primary pointer last went down. + nsecs_t downTime; + + struct CurrentVirtualKeyState { + bool down; + nsecs_t downTime; + int32_t keyCode; + int32_t scanCode; + } currentVirtualKey; + + struct AveragingTouchFilterState { + // Individual history tracks are stored by pointer id + uint32_t historyStart[MAX_POINTERS]; + uint32_t historyEnd[MAX_POINTERS]; + struct { + struct { + int32_t x; + int32_t y; + int32_t pressure; + } pointers[MAX_POINTERS]; + } historyData[AVERAGING_HISTORY_SIZE]; + } averagingTouchFilter; + + struct JumpTouchFilterState { + int32_t jumpyPointsDropped; + } jumpyTouchFilter; + + struct Precalculated { + float xScale; + float yScale; + float pressureScale; + float sizeScale; + } precalculated; + + void reset(); + + bool applyBadTouchFilter(); + bool applyJumpyTouchFilter(); + void applyAveragingTouchFilter(); + void calculatePointerIds(); + + bool isPointInsideDisplay(int32_t x, int32_t y) const; + }; + + InputDevice(int32_t id, uint32_t classes, String8 name); + + int32_t id; + uint32_t classes; + String8 name; + bool ignored; + + KeyboardState keyboard; + TrackballState trackball; + TouchScreenState touchScreen; + union { + SingleTouchScreenState singleTouchScreen; + MultiTouchScreenState multiTouchScreen; + }; + + void reset(); + + inline bool isKeyboard() const { return classes & INPUT_DEVICE_CLASS_KEYBOARD; } + inline bool isAlphaKey() const { return classes & INPUT_DEVICE_CLASS_ALPHAKEY; } + inline bool isTrackball() const { return classes & INPUT_DEVICE_CLASS_TRACKBALL; } + inline bool isDPad() const { return classes & INPUT_DEVICE_CLASS_DPAD; } + inline bool isSingleTouchScreen() const { return (classes + & (INPUT_DEVICE_CLASS_TOUCHSCREEN | INPUT_DEVICE_CLASS_TOUCHSCREEN_MT)) + == INPUT_DEVICE_CLASS_TOUCHSCREEN; } + inline bool isMultiTouchScreen() const { return classes + & INPUT_DEVICE_CLASS_TOUCHSCREEN_MT; } + inline bool isTouchScreen() const { return classes + & (INPUT_DEVICE_CLASS_TOUCHSCREEN | INPUT_DEVICE_CLASS_TOUCHSCREEN_MT); } +}; + + +/* + * Input reader policy interface. + * + * The input reader policy is used by the input reader to interact with the Window Manager + * and other system components. + * + * The actual implementation is partially supported by callbacks into the DVM + * via JNI. This interface is also mocked in the unit tests. + */ +class InputReaderPolicyInterface : public virtual RefBase { +protected: + InputReaderPolicyInterface() { } + virtual ~InputReaderPolicyInterface() { } + +public: + /* Display orientations. */ + enum { + ROTATION_0 = 0, + ROTATION_90 = 1, + ROTATION_180 = 2, + ROTATION_270 = 3 + }; + + /* Actions returned by interceptXXX methods. */ + enum { + // The input dispatcher should do nothing and discard the input unless other + // flags are set. + ACTION_NONE = 0, + + // The input dispatcher should dispatch the input to the application. + ACTION_DISPATCH = 0x00000001, + + // The input dispatcher should perform special filtering in preparation for + // a pending app switch. + ACTION_APP_SWITCH_COMING = 0x00000002, + + // The input dispatcher should add POLICY_FLAG_WOKE_HERE to the policy flags it + // passes through the dispatch pipeline. + ACTION_WOKE_HERE = 0x00000004, + + // The input dispatcher should add POLICY_FLAG_BRIGHT_HERE to the policy flags it + // passes through the dispatch pipeline. + ACTION_BRIGHT_HERE = 0x00000008 + }; + + /* Describes a virtual key. */ + struct VirtualKeyDefinition { + int32_t scanCode; + + // configured position data, specified in display coords + int32_t centerX; + int32_t centerY; + int32_t width; + int32_t height; + }; + + /* Gets information about the display with the specified id. + * Returns true if the display info is available, false otherwise. + */ + virtual bool getDisplayInfo(int32_t displayId, + int32_t* width, int32_t* height, int32_t* orientation) = 0; + + /* Provides feedback for a virtual key. + */ + virtual void virtualKeyFeedback(nsecs_t when, int32_t deviceId, + int32_t action, int32_t flags, int32_t keyCode, + int32_t scanCode, int32_t metaState, nsecs_t downTime) = 0; + + /* Intercepts a key event. + * The policy can use this method as an opportunity to perform power management functions + * and early event preprocessing. + * + * Returns a policy action constant such as ACTION_DISPATCH. + */ + virtual int32_t interceptKey(nsecs_t when, int32_t deviceId, + bool down, int32_t keyCode, int32_t scanCode, uint32_t policyFlags) = 0; + + /* Intercepts a trackball event. + * The policy can use this method as an opportunity to perform power management functions + * and early event preprocessing. + * + * Returns a policy action constant such as ACTION_DISPATCH. + */ + virtual int32_t interceptTrackball(nsecs_t when, bool buttonChanged, bool buttonDown, + bool rolled) = 0; + + /* Intercepts a touch event. + * The policy can use this method as an opportunity to perform power management functions + * and early event preprocessing. + * + * Returns a policy action constant such as ACTION_DISPATCH. + */ + virtual int32_t interceptTouch(nsecs_t when) = 0; + + /* Intercepts a switch event. + * The policy can use this method as an opportunity to perform power management functions + * and early event preprocessing. + * + * Switches are not dispatched to applications so this method should + * usually return ACTION_NONE. + */ + virtual int32_t interceptSwitch(nsecs_t when, int32_t switchCode, int32_t switchValue) = 0; + + /* Determines whether to turn on some hacks we have to improve the touch interaction with a + * certain device whose screen currently is not all that good. + */ + virtual bool filterTouchEvents() = 0; + + /* Determines whether to turn on some hacks to improve touch interaction with another device + * where touch coordinate data can get corrupted. + */ + virtual bool filterJumpyTouchEvents() = 0; + + /* Gets the configured virtual key definitions for an input device. */ + virtual void getVirtualKeyDefinitions(const String8& deviceName, + Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions) = 0; + + /* Gets the excluded device names for the platform. */ + virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) = 0; +}; + + +/* Processes raw input events and sends cooked event data to an input dispatcher. */ +class InputReaderInterface : public virtual RefBase { +protected: + InputReaderInterface() { } + virtual ~InputReaderInterface() { } + +public: + /* Runs a single iteration of the processing loop. + * Nominally reads and processes one incoming message from the EventHub. + * + * This method should be called on the input reader thread. + */ + virtual void loopOnce() = 0; + + /* Gets the current virtual key. Returns false if not down. + * + * This method may be called on any thread (usually by the input manager). + */ + virtual bool getCurrentVirtualKey(int32_t* outKeyCode, int32_t* outScanCode) const = 0; + + /* Gets the current input device configuration. + * + * This method may be called on any thread (usually by the input manager). + */ + virtual void getCurrentInputConfiguration(InputConfiguration* outConfiguration) const = 0; + + /* + * Query current input state. + * deviceId may be -1 to search for the device automatically, filtered by class. + * deviceClasses may be -1 to ignore device class while searching. + */ + virtual int32_t getCurrentScanCodeState(int32_t deviceId, int32_t deviceClasses, + int32_t scanCode) const = 0; + virtual int32_t getCurrentKeyCodeState(int32_t deviceId, int32_t deviceClasses, + int32_t keyCode) const = 0; + virtual int32_t getCurrentSwitchState(int32_t deviceId, int32_t deviceClasses, + int32_t sw) const = 0; + + /* Determine whether physical keys exist for the given framework-domain key codes. */ + virtual bool hasKeys(size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const = 0; +}; + + +/* The input reader reads raw event data from the event hub and processes it into input events + * that it sends to the input dispatcher. Some functions of the input reader, such as early + * event filtering in low power states, are controlled by a separate policy object. + * + * IMPORTANT INVARIANT: + * Because the policy can potentially block or cause re-entrance into the input reader, + * the input reader never calls into the policy while holding its internal locks. + */ +class InputReader : public InputReaderInterface { +public: + InputReader(const sp<EventHubInterface>& eventHub, + const sp<InputReaderPolicyInterface>& policy, + const sp<InputDispatcherInterface>& dispatcher); + virtual ~InputReader(); + + virtual void loopOnce(); + + virtual bool getCurrentVirtualKey(int32_t* outKeyCode, int32_t* outScanCode) const; + + virtual void getCurrentInputConfiguration(InputConfiguration* outConfiguration) const; + + virtual int32_t getCurrentScanCodeState(int32_t deviceId, int32_t deviceClasses, + int32_t scanCode) const; + virtual int32_t getCurrentKeyCodeState(int32_t deviceId, int32_t deviceClasses, + int32_t keyCode) const; + virtual int32_t getCurrentSwitchState(int32_t deviceId, int32_t deviceClasses, + int32_t sw) const; + + virtual bool hasKeys(size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const; + +private: + // Lock that must be acquired while manipulating state that may be concurrently accessed + // from other threads by input state query methods. It should be held for as short a + // time as possible. + // + // Exported state: + // - global virtual key code and scan code + // - device list and immutable properties of devices such as id, name, and class + // (but not other internal device state) + mutable Mutex mExportedStateLock; + + // current virtual key information (lock mExportedStateLock) + int32_t mExportedVirtualKeyCode; + int32_t mExportedVirtualScanCode; + + // current input configuration (lock mExportedStateLock) + InputConfiguration mExportedInputConfiguration; + + // combined key meta state + int32_t mGlobalMetaState; + + sp<EventHubInterface> mEventHub; + sp<InputReaderPolicyInterface> mPolicy; + sp<InputDispatcherInterface> mDispatcher; + + KeyedVector<int32_t, InputDevice*> mDevices; + + // display properties needed to translate touch screen coordinates into display coordinates + int32_t mDisplayOrientation; + int32_t mDisplayWidth; + int32_t mDisplayHeight; + + // low-level input event decoding + void process(const RawEvent* rawEvent); + void handleDeviceAdded(const RawEvent* rawEvent); + void handleDeviceRemoved(const RawEvent* rawEvent); + void handleSync(const RawEvent* rawEvent); + void handleKey(const RawEvent* rawEvent); + void handleRelativeMotion(const RawEvent* rawEvent); + void handleAbsoluteMotion(const RawEvent* rawEvent); + void handleSwitch(const RawEvent* rawEvent); + + // input policy processing and dispatch + void onKey(nsecs_t when, InputDevice* device, bool down, + int32_t keyCode, int32_t scanCode, uint32_t policyFlags); + void onSwitch(nsecs_t when, InputDevice* device, int32_t switchCode, int32_t switchValue); + void onSingleTouchScreenStateChanged(nsecs_t when, InputDevice* device); + void onMultiTouchScreenStateChanged(nsecs_t when, InputDevice* device); + void onTouchScreenChanged(nsecs_t when, InputDevice* device, bool havePointerIds); + void onTrackballStateChanged(nsecs_t when, InputDevice* device); + void onConfigurationChanged(nsecs_t when); + + bool applyStandardInputDispatchPolicyActions(nsecs_t when, + int32_t policyActions, uint32_t* policyFlags); + + bool consumeVirtualKeyTouches(nsecs_t when, InputDevice* device, uint32_t policyFlags); + void dispatchVirtualKey(nsecs_t when, InputDevice* device, uint32_t policyFlags, + int32_t keyEventAction, int32_t keyEventFlags); + void dispatchTouches(nsecs_t when, InputDevice* device, uint32_t policyFlags); + void dispatchTouch(nsecs_t when, InputDevice* device, uint32_t policyFlags, + InputDevice::TouchData* touch, BitSet32 idBits, int32_t motionEventAction); + + // display + void resetDisplayProperties(); + bool refreshDisplayProperties(); + + // device management + InputDevice* getDevice(int32_t deviceId); + InputDevice* getNonIgnoredDevice(int32_t deviceId); + void addDevice(nsecs_t when, int32_t deviceId); + void removeDevice(nsecs_t when, InputDevice* device); + void configureDevice(InputDevice* device); + void configureDeviceForCurrentDisplaySize(InputDevice* device); + void configureVirtualKeys(InputDevice* device); + void configureAbsoluteAxisInfo(InputDevice* device, int axis, const char* name, + InputDevice::AbsoluteAxisInfo* out); + void configureExcludedDevices(); + + // global meta state management for all devices + void resetGlobalMetaState(); + int32_t globalMetaState(); + + // virtual key management + void updateExportedVirtualKeyState(); + + // input configuration management + void updateExportedInputConfiguration(); +}; + + +/* Reads raw events from the event hub and processes them, endlessly. */ +class InputReaderThread : public Thread { +public: + InputReaderThread(const sp<InputReaderInterface>& reader); + virtual ~InputReaderThread(); + +private: + sp<InputReaderInterface> mReader; + + virtual bool threadLoop(); +}; + +} // namespace android + +#endif // _UI_INPUT_READER_H diff --git a/include/ui/InputTransport.h b/include/ui/InputTransport.h new file mode 100644 index 0000000..7b182f3 --- /dev/null +++ b/include/ui/InputTransport.h @@ -0,0 +1,333 @@ +/* + * 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 _UI_INPUT_TRANSPORT_H +#define _UI_INPUT_TRANSPORT_H + +/** + * Native input transport. + * + * Uses anonymous shared memory as a whiteboard for sending input events from an + * InputPublisher to an InputConsumer and ensuring appropriate synchronization. + * One interesting feature is that published events can be updated in place as long as they + * have not yet been consumed. + * + * The InputPublisher and InputConsumer only take care of transferring event data + * over an InputChannel and sending synchronization signals. The InputDispatcher and InputQueue + * build on these abstractions to add multiplexing and queueing. + */ + +#include <semaphore.h> +#include <ui/Input.h> +#include <utils/Errors.h> +#include <utils/Timers.h> +#include <utils/RefBase.h> +#include <utils/String8.h> + +namespace android { + +/* + * An input channel consists of a shared memory buffer and a pair of pipes + * used to send input messages from an InputPublisher to an InputConsumer + * across processes. Each channel has a descriptive name for debugging purposes. + * + * Each endpoint has its own InputChannel object that specifies its own file descriptors. + * + * The input channel is closed when all references to it are released. + */ +class InputChannel : public RefBase { +protected: + virtual ~InputChannel(); + +public: + InputChannel(const String8& name, int32_t ashmemFd, int32_t receivePipeFd, + int32_t sendPipeFd); + + /* Creates a pair of input channels and their underlying shared memory buffers + * and pipes. + * + * Returns OK on success. + */ + static status_t openInputChannelPair(const String8& name, + sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel); + + inline String8 getName() const { return mName; } + inline int32_t getAshmemFd() const { return mAshmemFd; } + inline int32_t getReceivePipeFd() const { return mReceivePipeFd; } + inline int32_t getSendPipeFd() const { return mSendPipeFd; } + + /* Sends a signal to the other endpoint. + * + * Returns OK on success. + * Returns DEAD_OBJECT if the channel's peer has been closed. + * Other errors probably indicate that the channel is broken. + */ + status_t sendSignal(char signal); + + /* Receives a signal send by the other endpoint. + * (Should only call this after poll() indicates that the receivePipeFd has available input.) + * + * Returns OK on success. + * Returns WOULD_BLOCK if there is no signal present. + * Returns DEAD_OBJECT if the channel's peer has been closed. + * Other errors probably indicate that the channel is broken. + */ + status_t receiveSignal(char* outSignal); + +private: + String8 mName; + int32_t mAshmemFd; + int32_t mReceivePipeFd; + int32_t mSendPipeFd; +}; + +/* + * Private intermediate representation of input events as messages written into an + * ashmem buffer. + */ +struct InputMessage { + /* Semaphore count is set to 1 when the message is published. + * It becomes 0 transiently while the publisher updates the message. + * It becomes 0 permanently when the consumer consumes the message. + */ + sem_t semaphore; + + /* Initialized to false by the publisher. + * Set to true by the consumer when it consumes the message. + */ + bool consumed; + + int32_t type; + + struct SampleData { + nsecs_t eventTime; + PointerCoords coords[0]; // variable length + }; + + int32_t deviceId; + int32_t nature; + + union { + struct { + int32_t action; + int32_t flags; + int32_t keyCode; + int32_t scanCode; + int32_t metaState; + int32_t repeatCount; + nsecs_t downTime; + nsecs_t eventTime; + } key; + + struct { + int32_t action; + int32_t metaState; + int32_t edgeFlags; + nsecs_t downTime; + float xOffset; + float yOffset; + float xPrecision; + float yPrecision; + size_t pointerCount; + int32_t pointerIds[MAX_POINTERS]; + size_t sampleCount; + SampleData sampleData[0]; // variable length + } motion; + }; + + /* Gets the number of bytes to add to step to the next SampleData object in a motion + * event message for a given number of pointers. + */ + static inline size_t sampleDataStride(size_t pointerCount) { + return sizeof(InputMessage::SampleData) + pointerCount * sizeof(PointerCoords); + } + + /* Adds the SampleData stride to the given pointer. */ + static inline SampleData* sampleDataPtrIncrement(SampleData* ptr, size_t stride) { + return reinterpret_cast<InputMessage::SampleData*>(reinterpret_cast<char*>(ptr) + stride); + } +}; + +/* + * Publishes input events to an anonymous shared memory buffer. + * Uses atomic operations to coordinate shared access with a single concurrent consumer. + */ +class InputPublisher { +public: + /* Creates a publisher associated with an input channel. */ + explicit InputPublisher(const sp<InputChannel>& channel); + + /* Destroys the publisher and releases its input channel. */ + ~InputPublisher(); + + /* Gets the underlying input channel. */ + inline sp<InputChannel> getChannel() { return mChannel; } + + /* Prepares the publisher for use. Must be called before it is used. + * Returns OK on success. + * + * This method implicitly calls reset(). */ + status_t initialize(); + + /* Resets the publisher to its initial state and unpins its ashmem buffer. + * Returns OK on success. + * + * Should be called after an event has been consumed to release resources used by the + * publisher until the next event is ready to be published. + */ + status_t reset(); + + /* Publishes a key event to the ashmem buffer. + * + * Returns OK on success. + * Returns INVALID_OPERATION if the publisher has not been reset. + */ + status_t publishKeyEvent( + int32_t deviceId, + int32_t nature, + int32_t action, + int32_t flags, + int32_t keyCode, + int32_t scanCode, + int32_t metaState, + int32_t repeatCount, + nsecs_t downTime, + nsecs_t eventTime); + + /* Publishes a motion event to the ashmem buffer. + * + * Returns OK on success. + * Returns INVALID_OPERATION if the publisher has not been reset. + * Returns BAD_VALUE if pointerCount is less than 1 or greater than MAX_POINTERS. + */ + status_t publishMotionEvent( + int32_t deviceId, + int32_t nature, + int32_t action, + int32_t edgeFlags, + int32_t metaState, + float xOffset, + float yOffset, + float xPrecision, + float yPrecision, + nsecs_t downTime, + nsecs_t eventTime, + size_t pointerCount, + const int32_t* pointerIds, + const PointerCoords* pointerCoords); + + /* Appends a motion sample to a motion event unless already consumed. + * + * Returns OK on success. + * Returns INVALID_OPERATION if the current event is not a MOTION_EVENT_ACTION_MOVE event. + * Returns FAILED_TRANSACTION if the current event has already been consumed. + * Returns NO_MEMORY if the buffer is full and no additional samples can be added. + */ + status_t appendMotionSample( + nsecs_t eventTime, + const PointerCoords* pointerCoords); + + /* Sends a dispatch signal to the consumer to inform it that a new message is available. + * + * Returns OK on success. + * Errors probably indicate that the channel is broken. + */ + status_t sendDispatchSignal(); + + /* Receives the finished signal from the consumer in reply to the original dispatch signal. + * + * Returns OK on success. + * Returns WOULD_BLOCK if there is no signal present. + * Other errors probably indicate that the channel is broken. + */ + status_t receiveFinishedSignal(); + +private: + sp<InputChannel> mChannel; + + size_t mAshmemSize; + InputMessage* mSharedMessage; + bool mPinned; + bool mSemaphoreInitialized; + bool mWasDispatched; + + size_t mMotionEventPointerCount; + InputMessage::SampleData* mMotionEventSampleDataTail; + size_t mMotionEventSampleDataStride; + + status_t publishInputEvent( + int32_t type, + int32_t deviceId, + int32_t nature); +}; + +/* + * Consumes input events from an anonymous shared memory buffer. + * Uses atomic operations to coordinate shared access with a single concurrent publisher. + */ +class InputConsumer { +public: + /* Creates a consumer associated with an input channel. */ + explicit InputConsumer(const sp<InputChannel>& channel); + + /* Destroys the consumer and releases its input channel. */ + ~InputConsumer(); + + /* Gets the underlying input channel. */ + inline sp<InputChannel> getChannel() { return mChannel; } + + /* Prepares the consumer for use. Must be called before it is used. */ + status_t initialize(); + + /* Consumes the input event in the buffer and copies its contents into + * an InputEvent object created using the specified factory. + * This operation will block if the publisher is updating the event. + * + * Returns OK on success. + * Returns INVALID_OPERATION if there is no currently published event. + * Returns NO_MEMORY if the event could not be created. + */ + status_t consume(InputEventFactoryInterface* factory, InputEvent** outEvent); + + /* Sends a finished signal to the publisher to inform it that the current message is + * finished processing. + * + * Returns OK on success. + * Errors probably indicate that the channel is broken. + */ + status_t sendFinishedSignal(); + + /* Receives the dispatched signal from the publisher. + * + * Returns OK on success. + * Returns WOULD_BLOCK if there is no signal present. + * Other errors probably indicate that the channel is broken. + */ + status_t receiveDispatchSignal(); + +private: + sp<InputChannel> mChannel; + + size_t mAshmemSize; + InputMessage* mSharedMessage; + + void populateKeyEvent(KeyEvent* keyEvent) const; + void populateMotionEvent(MotionEvent* motionEvent) const; +}; + +} // namespace android + +#endif // _UI_INPUT_TRANSPORT_H diff --git a/include/ui/KeycodeLabels.h b/include/ui/KeycodeLabels.h index 571e47b..e81d0f9 100644..100755 --- a/include/ui/KeycodeLabels.h +++ b/include/ui/KeycodeLabels.h @@ -114,6 +114,10 @@ static const KeycodeLabel KEYCODES[] = { { "MEDIA_REWIND", 89 }, { "MEDIA_FAST_FORWARD", 90 }, { "MUTE", 91 }, + { "PAGE_UP", 92 }, + { "PAGE_DOWN", 93 }, + { "PICTSYMBOLS", 94 }, + { "SWITCH_CHARSET", 95 }, // NOTE: If you add a new keycode here you must also add it to: // (enum KeyCode, in this file) @@ -218,7 +222,11 @@ typedef enum KeyCode { kKeyCodePreviousSong = 88, kKeyCodeRewind = 89, kKeyCodeForward = 90, - kKeyCodeMute = 91 + kKeyCodeMute = 91, + kKeyCodePageUp = 92, + kKeyCodePageDown = 93, + kKeyCodePictSymbols = 94, + kKeyCodeSwitchCharset = 95 } KeyCode; static const KeycodeLabel FLAGS[] = { diff --git a/include/ui/android_native_buffer.h b/include/ui/android_native_buffer.h index 9c92af8..402843e 100644 --- a/include/ui/android_native_buffer.h +++ b/include/ui/android_native_buffer.h @@ -33,6 +33,15 @@ typedef struct android_native_buffer_t common.version = sizeof(android_native_buffer_t); memset(common.reserved, 0, sizeof(common.reserved)); } + + // Implement the methods that sp<android_native_buffer_t> expects so that it + // can be used to automatically refcount android_native_buffer_t's. + void incStrong(const void* id) const { + common.incRef(const_cast<android_native_base_t*>(&common)); + } + void decStrong(const void* id) const { + common.decRef(const_cast<android_native_base_t*>(&common)); + } #endif struct android_native_base_t common; diff --git a/include/ui/egl/android_natives.h b/include/ui/egl/android_natives.h index 773fd93..171f3df 100644 --- a/include/ui/egl/android_natives.h +++ b/include/ui/egl/android_natives.h @@ -41,6 +41,14 @@ extern "C" { struct android_native_buffer_t; +typedef struct android_native_rect_t +{ + int32_t left; + int32_t top; + int32_t right; + int32_t bottom; +} android_native_rect_t; + // --------------------------------------------------------------------------- typedef struct android_native_base_t @@ -63,15 +71,18 @@ typedef struct android_native_base_t /* attributes queriable with query() */ enum { NATIVE_WINDOW_WIDTH = 0, - NATIVE_WINDOW_HEIGHT = 1, - NATIVE_WINDOW_FORMAT = 2, + NATIVE_WINDOW_HEIGHT, + NATIVE_WINDOW_FORMAT, }; /* valid operations for the (*perform)() hook */ enum { NATIVE_WINDOW_SET_USAGE = 0, - NATIVE_WINDOW_CONNECT = 1, - NATIVE_WINDOW_DISCONNECT = 2 + NATIVE_WINDOW_CONNECT, + NATIVE_WINDOW_DISCONNECT, + NATIVE_WINDOW_SET_CROP, + NATIVE_WINDOW_SET_BUFFER_COUNT, + NATIVE_WINDOW_SET_BUFFERS_GEOMETRY, }; /* parameter for NATIVE_WINDOW_[DIS]CONNECT */ @@ -89,6 +100,15 @@ typedef struct android_native_window_t common.version = sizeof(android_native_window_t); memset(common.reserved, 0, sizeof(common.reserved)); } + + // Implement the methods that sp<android_native_window_t> expects so that it + // can be used to automatically refcount android_native_window_t's. + void incStrong(const void* id) const { + common.incRef(const_cast<android_native_base_t*>(&common)); + } + void decStrong(const void* id) const { + common.decRef(const_cast<android_native_base_t*>(&common)); + } #endif struct android_native_base_t common; @@ -125,7 +145,7 @@ typedef struct android_native_window_t * * Returns 0 on success or -errno on error. */ - int (*dequeueBuffer)(struct android_native_window_t* window, + int (*dequeueBuffer)(struct android_native_window_t* window, struct android_native_buffer_t** buffer); /* @@ -171,6 +191,9 @@ typedef struct android_native_window_t * NATIVE_WINDOW_SET_USAGE * NATIVE_WINDOW_CONNECT * NATIVE_WINDOW_DISCONNECT + * NATIVE_WINDOW_SET_CROP + * NATIVE_WINDOW_SET_BUFFER_COUNT + * NATIVE_WINDOW_SET_BUFFERS_GEOMETRY * */ @@ -182,8 +205,9 @@ typedef struct android_native_window_t /* - * native_window_set_usage() sets the intended usage flags for the next - * buffers acquired with (*lockBuffer)() and on. + * native_window_set_usage(..., usage) + * Sets the intended usage flags for the next buffers + * acquired with (*lockBuffer)() and on. * By default (if this function is never called), a usage of * GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE * is assumed. @@ -198,8 +222,8 @@ static inline int native_window_set_usage( } /* - * native_window_connect(..., NATIVE_WINDOW_API_EGL) must be called - * by EGL when the window is made current. + * native_window_connect(..., NATIVE_WINDOW_API_EGL) + * Must be called by EGL when the window is made current. * Returns -EINVAL if for some reason the window cannot be connected, which * can happen if it's connected to some other API. */ @@ -210,8 +234,8 @@ static inline int native_window_connect( } /* - * native_window_disconnect(..., NATIVE_WINDOW_API_EGL) must be called - * by EGL when the window is made not current. + * native_window_disconnect(..., NATIVE_WINDOW_API_EGL) + * Must be called by EGL when the window is made not current. * An error is returned if for instance the window wasn't connected in the * first place. */ @@ -221,6 +245,54 @@ static inline int native_window_disconnect( return window->perform(window, NATIVE_WINDOW_DISCONNECT, api); } +/* + * native_window_set_crop(..., crop) + * Sets which region of the next queued buffers needs to be considered. + * A buffer's crop region is scaled to match the surface's size. + * + * The specified crop region applies to all buffers queued after it is called. + * + * if 'crop' is NULL, subsequently queued buffers won't be cropped. + * + * An error is returned if for instance the crop region is invalid, + * out of the buffer's bound or if the window is invalid. + */ +static inline int native_window_set_crop( + android_native_window_t* window, + android_native_rect_t const * crop) +{ + return window->perform(window, NATIVE_WINDOW_SET_CROP, crop); +} + +/* + * native_window_set_buffer_count(..., count) + * Sets the number of buffers associated with this native window. + */ +static inline int native_window_set_buffer_count( + android_native_window_t* window, + size_t bufferCount) +{ + return window->perform(window, NATIVE_WINDOW_SET_BUFFER_COUNT, bufferCount); +} + +/* + * native_window_set_buffers_geometry(..., int w, int h, int format) + * All buffers dequeued after this call will have the geometry specified. + * In particular, all buffers will have a fixed-size, independent form the + * native-window size. They will be appropriately scaled to the window-size + * upon composition. + * + * If all parameters are 0, the normal behavior is restored. That is, + * dequeued buffers following this call will be sized to the window's size. + * + */ +static inline int native_window_set_buffers_geometry( + android_native_window_t* window, + int w, int h, int format) +{ + return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_GEOMETRY, + w, h, format); +} // --------------------------------------------------------------------------- @@ -263,6 +335,15 @@ namespace android { template <typename NATIVE_TYPE, typename TYPE, typename REF> class EGLNativeBase : public NATIVE_TYPE, public REF { +public: + // Disambiguate between the incStrong in REF and NATIVE_TYPE + void incStrong(const void* id) const { + REF::incStrong(id); + } + void decStrong(const void* id) const { + REF::decStrong(id); + } + protected: typedef EGLNativeBase<NATIVE_TYPE, TYPE, REF> BASE; EGLNativeBase() : NATIVE_TYPE(), REF() { diff --git a/include/utils/BitSet.h b/include/utils/BitSet.h new file mode 100644 index 0000000..19c8bf0 --- /dev/null +++ b/include/utils/BitSet.h @@ -0,0 +1,67 @@ +/* + * 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 UTILS_BITSET_H +#define UTILS_BITSET_H + +#include <stdint.h> + +/* + * Contains some bit manipulation helpers. + */ + +namespace android { + +// A simple set of 32 bits that can be individually marked or cleared. +struct BitSet32 { + uint32_t value; + + inline BitSet32() : value(0) { } + explicit inline BitSet32(uint32_t value) : value(value) { } + + // Gets the value associated with a particular bit index. + static inline uint32_t valueForBit(uint32_t n) { return 0x80000000 >> n; } + + // Clears the bit set. + inline void clear() { value = 0; } + + // Returns true if the bit set does not contain any marked bits. + inline bool isEmpty() const { return ! value; } + + // Returns true if the specified bit is marked. + inline bool hasBit(uint32_t n) const { return value & valueForBit(n); } + + // Marks the specified bit. + inline void markBit(uint32_t n) { value |= valueForBit(n); } + + // Clears the specified bit. + inline void clearBit(uint32_t n) { value &= ~ valueForBit(n); } + + // Finds the first marked bit in the set. + // Result is undefined if all bits are unmarked. + inline uint32_t firstMarkedBit() const { return __builtin_clz(value); } + + // Finds the first unmarked bit in the set. + // Result is undefined if all bits are marked. + inline uint32_t firstUnmarkedBit() const { return __builtin_clz(~ value); } + + inline bool operator== (const BitSet32& other) const { return value == other.value; } + inline bool operator!= (const BitSet32& other) const { return value != other.value; } +}; + +} // namespace android + +#endif // UTILS_BITSET_H diff --git a/include/utils/Buffer.h b/include/utils/Buffer.h deleted file mode 100644 index 8e22b0f..0000000 --- a/include/utils/Buffer.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2008 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 __UTILS_BUFFER_H__ -#define __UTILS_BUFFER_H__ 1 - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -namespace android { - -class Buffer -{ -private: - char *buf; - int bufsiz; - int used; - void ensureCapacity(int len); - - void - makeRoomFor(int len) - { - if (len + used >= bufsiz) { - bufsiz = (len + used) * 3/2 + 2; - char *blah = new char[bufsiz]; - - memcpy(blah, buf, used); - delete[] buf; - buf = blah; - } - } - -public: - Buffer() - { - bufsiz = 16; - buf = new char[bufsiz]; - clear(); - } - - ~Buffer() - { - delete[] buf; - } - - void - clear() - { - buf[0] = '\0'; - used = 0; - } - - int - length() - { - return used; - } - - void - append(const char c) - { - makeRoomFor(1); - buf[used] = c; - used++; - buf[used] = '\0'; - } - - void - append(const char *s, int len) - { - makeRoomFor(len); - - memcpy(buf + used, s, len); - used += len; - buf[used] = '\0'; - } - - void - append(const char *s) - { - append(s, strlen(s)); - } - - char * - getBytes() - { - return buf; - } -}; - -}; // namespace android - -#endif diff --git a/include/utils/PollLoop.h b/include/utils/PollLoop.h new file mode 100644 index 0000000..a95fb17 --- /dev/null +++ b/include/utils/PollLoop.h @@ -0,0 +1,139 @@ +/* + * 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 UTILS_POLL_LOOP_H +#define UTILS_POLL_LOOP_H + +#include <utils/Vector.h> +#include <utils/threads.h> + +#include <sys/poll.h> + +namespace android { + +/** + * A basic file descriptor polling loop based on poll() with callbacks. + */ +class PollLoop : public RefBase { +protected: + virtual ~PollLoop(); + +public: + PollLoop(); + + /** + * A callback that it to be invoked when an event occurs on a file descriptor. + * Specifies the events that were triggered and the user data provided when the + * callback was set. + * + * Returns true if the callback should be kept, false if it should be removed automatically + * after the callback returns. + */ + typedef bool (*Callback)(int fd, int events, void* data); + + /** + * Performs a single call to poll() with optional timeout in milliseconds. + * Invokes callbacks for all file descriptors on which an event occurred. + * + * If the timeout is zero, returns immediately without blocking. + * If the timeout is negative, waits indefinitely until awoken. + * + * Returns true if a callback was invoked or if the loop was awoken by wake(). + * Returns false if a timeout or error occurred. + * + * This method must only be called on the main thread. + * This method blocks until either a file descriptor is signalled, a timeout occurs, + * or wake() is called. + * This method does not return until it has finished invoking the appropriate callbacks + * for all file descriptors that were signalled. + */ + bool pollOnce(int timeoutMillis); + + /** + * Wakes the loop asynchronously. + * + * This method can be called on any thread. + * This method returns immediately. + */ + void wake(); + + /** + * Sets the callback for a file descriptor, replacing the existing one, if any. + * It is an error to call this method with events == 0 or callback == NULL. + * + * Note that a callback can be invoked with the POLLERR, POLLHUP or POLLNVAL events + * even if it is not explicitly requested when registered. + * + * This method can be called on any thread. + * This method may block briefly if it needs to wake the poll loop. + */ + void setCallback(int fd, int events, Callback callback, void* data = NULL); + + /** + * Removes the callback for a file descriptor, if one exists. + * + * When this method returns, it is safe to close the file descriptor since the poll loop + * will no longer have a reference to it. However, it is possible for the callback to + * already be running or for it to run one last time if the file descriptor was already + * signalled. Calling code is responsible for ensuring that this case is safely handled. + * For example, if the callback takes care of removing itself during its own execution either + * by returning false or calling this method, then it can be guaranteed to not be invoked + * again at any later time unless registered anew. + * + * This method can be called on any thread. + * This method may block briefly if it needs to wake the poll loop. + * + * Returns true if a callback was actually removed, false if none was registered. + */ + bool removeCallback(int fd); + +private: + struct RequestedCallback { + Callback callback; + void* data; + }; + + struct PendingCallback { + int fd; + int events; + Callback callback; + void* data; + }; + + Mutex mLock; + bool mPolling; + uint32_t mWaiters; + Condition mAwake; + Condition mResume; + + int mWakeReadPipeFd; + int mWakeWritePipeFd; + + Vector<struct pollfd> mRequestedFds; + Vector<RequestedCallback> mRequestedCallbacks; + + Vector<PendingCallback> mPendingCallbacks; // used privately by pollOnce + + void openWakePipe(); + void closeWakePipe(); + + ssize_t getRequestIndexLocked(int fd); + void wakeAndLock(); +}; + +} // namespace android + +#endif // UTILS_POLL_LOOP_H diff --git a/include/utils/Pool.h b/include/utils/Pool.h new file mode 100644 index 0000000..2ee768e --- /dev/null +++ b/include/utils/Pool.h @@ -0,0 +1,71 @@ +/* + * 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 UTILS_POOL_H +#define UTILS_POOL_H + +#include <utils/TypeHelpers.h> + +namespace android { + +class PoolImpl { +public: + PoolImpl(size_t objSize); + ~PoolImpl(); + + void* allocImpl(); + void freeImpl(void* obj); + +private: + size_t mObjSize; +}; + +/* + * A homogeneous typed memory pool for fixed size objects. + * Not intended to be thread-safe. + */ +template<typename T> +class Pool : private PoolImpl { +public: + /* Creates an initially empty pool. */ + Pool() : PoolImpl(sizeof(T)) { } + + /* Destroys the pool. + * Assumes that the pool is empty. */ + ~Pool() { } + + /* Allocates an object from the pool, growing the pool if needed. */ + inline T* alloc() { + void* mem = allocImpl(); + if (! traits<T>::has_trivial_ctor) { + return new (mem) T(); + } else { + return static_cast<T*>(mem); + } + } + + /* Frees an object from the pool. */ + inline void free(T* obj) { + if (! traits<T>::has_trivial_dtor) { + obj->~T(); + } + freeImpl(obj); + } +}; + +} // namespace android + +#endif // UTILS_POOL_H diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h index b701ce7..c7d9ff1 100644 --- a/include/utils/ResourceTypes.h +++ b/include/utils/ResourceTypes.h @@ -933,6 +933,7 @@ struct ResTable_config SCREENSIZE_SMALL = 0x01, SCREENSIZE_NORMAL = 0x02, SCREENSIZE_LARGE = 0x03, + SCREENSIZE_XLARGE = 0x04, // screenLayout bits for wide/long screen variation. MASK_SCREENLONG = 0x30, @@ -1208,7 +1209,28 @@ struct ResTable_config if (screenLayout || o.screenLayout) { if (((screenLayout^o.screenLayout) & MASK_SCREENSIZE) != 0 && (requested->screenLayout & MASK_SCREENSIZE)) { - return (screenLayout & MASK_SCREENSIZE); + // A little backwards compatibility here: undefined is + // considered equivalent to normal. But only if the + // requested size is at least normal; otherwise, small + // is better than the default. + int mySL = (screenLayout & MASK_SCREENSIZE); + int oSL = (o.screenLayout & MASK_SCREENSIZE); + int fixedMySL = mySL; + int fixedOSL = oSL; + if ((requested->screenLayout & MASK_SCREENSIZE) >= SCREENSIZE_NORMAL) { + if (fixedMySL == 0) fixedMySL = SCREENSIZE_NORMAL; + if (fixedOSL == 0) fixedOSL = SCREENSIZE_NORMAL; + } + // For screen size, the best match is the one that is + // closest to the requested screen size, but not over + // (the not over part is dealt with in match() below). + if (fixedMySL == fixedOSL) { + // If the two are the same, but 'this' is actually + // undefined, then the other is really a better match. + if (mySL == 0) return false; + return true; + } + return fixedMySL >= fixedOSL; } if (((screenLayout^o.screenLayout) & MASK_SCREENLONG) != 0 && (requested->screenLayout & MASK_SCREENLONG)) { @@ -1370,8 +1392,11 @@ struct ResTable_config if (screenConfig != 0) { const int screenSize = screenLayout&MASK_SCREENSIZE; const int setScreenSize = settings.screenLayout&MASK_SCREENSIZE; - if (setScreenSize != 0 && screenSize != 0 - && screenSize != setScreenSize) { + // Any screen sizes for larger screens than the setting do not + // match. + if ((setScreenSize != 0 && screenSize != 0 + && screenSize > setScreenSize) || + (setScreenSize == 0 && screenSize != 0)) { return false; } diff --git a/include/utils/Singleton.h b/include/utils/Singleton.h index bc7626a..3b975b4 100644 --- a/include/utils/Singleton.h +++ b/include/utils/Singleton.h @@ -54,11 +54,13 @@ private: * (eg: <TYPE>.cpp) to create the static instance of Singleton<>'s attributes, * and avoid to have a copy of them in each compilation units Singleton<TYPE> * is used. + * NOTE: we use a version of Mutex ctor that takes a parameter, because + * for some unknown reason using the default ctor doesn't emit the variable! */ -#define ANDROID_SINGLETON_STATIC_INSTANCE(TYPE) \ - template class Singleton< TYPE >; \ - template< class TYPE > Mutex Singleton< TYPE >::sLock; \ +#define ANDROID_SINGLETON_STATIC_INSTANCE(TYPE) \ + template class Singleton< TYPE >; \ + template<> Mutex Singleton< TYPE >::sLock(Mutex::PRIVATE); \ template<> TYPE* Singleton< TYPE >::sInstance(0); diff --git a/include/utils/StopWatch.h b/include/utils/StopWatch.h index cc0bebc..693dd3c 100644 --- a/include/utils/StopWatch.h +++ b/include/utils/StopWatch.h @@ -37,6 +37,8 @@ public: const char* name() const; nsecs_t lap(); nsecs_t elapsedTime() const; + + void reset(); private: const char* mName; diff --git a/include/utils/Vector.h b/include/utils/Vector.h index ad59fd6..ec851bd 100644 --- a/include/utils/Vector.h +++ b/include/utils/Vector.h @@ -114,13 +114,19 @@ public: ssize_t appendVector(const Vector<TYPE>& vector); + //! insert an array at a given index + ssize_t insertArrayAt(const TYPE* array, size_t index, size_t length); + + //! append an array at the end of this vector + ssize_t appendArray(const TYPE* array, size_t length); + /*! * add/insert/replace items */ //! insert one or several items initialized with their default constructor inline ssize_t insertAt(size_t index, size_t numItems = 1); - //! insert on onr several items initialized from a prototype item + //! insert one or several items initialized from a prototype item ssize_t insertAt(const TYPE& prototype_item, size_t index, size_t numItems = 1); //! pop the top of the stack (removes the last element). No-op if the stack's empty inline void pop(); @@ -259,6 +265,16 @@ ssize_t Vector<TYPE>::appendVector(const Vector<TYPE>& vector) { } template<class TYPE> inline +ssize_t Vector<TYPE>::insertArrayAt(const TYPE* array, size_t index, size_t length) { + return VectorImpl::insertArrayAt(array, index, length); +} + +template<class TYPE> inline +ssize_t Vector<TYPE>::appendArray(const TYPE* array, size_t length) { + return VectorImpl::appendArray(array, length); +} + +template<class TYPE> inline ssize_t Vector<TYPE>::insertAt(const TYPE& item, size_t index, size_t numItems) { return VectorImpl::insertAt(&item, index, numItems); } diff --git a/include/utils/VectorImpl.h b/include/utils/VectorImpl.h index 49b03f1..c4ec2ff 100644 --- a/include/utils/VectorImpl.h +++ b/include/utils/VectorImpl.h @@ -65,9 +65,11 @@ public: size_t capacity() const; ssize_t setCapacity(size_t size); - /*! append/insert another vector */ + /*! append/insert another vector or array */ ssize_t insertVectorAt(const VectorImpl& vector, size_t index); ssize_t appendVector(const VectorImpl& vector); + ssize_t insertArrayAt(const void* array, size_t index, size_t length); + ssize_t appendArray(const void* array, size_t length); /*! add/insert/replace items */ ssize_t insertAt(size_t where, size_t numItems = 1); @@ -184,6 +186,8 @@ private: void push(const void* item); ssize_t insertVectorAt(const VectorImpl& vector, size_t index); ssize_t appendVector(const VectorImpl& vector); + ssize_t insertArrayAt(const void* array, size_t index, size_t length); + ssize_t appendArray(const void* array, size_t length); ssize_t insertAt(size_t where, size_t numItems = 1); ssize_t insertAt(const void* item, size_t where, size_t numItems = 1); ssize_t replaceAt(size_t index); diff --git a/include/utils/ZipFileCRO.h b/include/utils/ZipFileCRO.h index 30e0036..e38bf66 100644 --- a/include/utils/ZipFileCRO.h +++ b/include/utils/ZipFileCRO.h @@ -47,8 +47,8 @@ extern ZipEntryCRO ZipFileCRO_findEntryByName(ZipFileCRO zip, const char* fileName); extern bool ZipFileCRO_getEntryInfo(ZipFileCRO zip, ZipEntryCRO entry, - int* pMethod, long* pUncompLen, - long* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32); + int* pMethod, size_t* pUncompLen, + size_t* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32); extern bool ZipFileCRO_uncompressEntry(ZipFileCRO zip, ZipEntryCRO entry, int fd); diff --git a/include/utils/ZipFileRO.h b/include/utils/ZipFileRO.h index 51c4f2f..97d31f4 100644 --- a/include/utils/ZipFileRO.h +++ b/include/utils/ZipFileRO.h @@ -58,14 +58,19 @@ typedef void* ZipEntryRO; class ZipFileRO { public: ZipFileRO() - : mFd(-1), mFileMap(NULL), mHashTableSize(-1), mHashTable(NULL) + : mFd(-1), mFileName(NULL), mFileLength(-1), + mDirectoryMap(NULL), + mNumEntries(-1), mDirectoryOffset(-1), + mHashTableSize(-1), mHashTable(NULL) {} ~ZipFileRO() { free(mHashTable); - if (mFileMap) - mFileMap->release(); + if (mDirectoryMap) + mDirectoryMap->release(); if (mFd >= 0) close(mFd); + if (mFileName) + free(mFileName); } /* @@ -118,8 +123,8 @@ public: * Returns "false" if "entry" is bogus or if the data in the Zip file * appears to be bad. */ - bool getEntryInfo(ZipEntryRO entry, int* pMethod, long* pUncompLen, - long* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32) const; + bool getEntryInfo(ZipEntryRO entry, int* pMethod, size_t* pUncompLen, + size_t* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32) const; /* * Create a new FileMap object that maps a subset of the archive. For @@ -155,13 +160,13 @@ public: * Utility function: uncompress deflated data, buffer to buffer. */ static bool inflateBuffer(void* outBuf, const void* inBuf, - long uncompLen, long compLen); + size_t uncompLen, size_t compLen); /* * Utility function: uncompress deflated data, buffer to fd. */ static bool inflateBuffer(int fd, const void* inBuf, - long uncompLen, long compLen); + size_t uncompLen, size_t compLen); /* * Some basic functions for raw data manipulation. "LE" means @@ -179,6 +184,9 @@ private: ZipFileRO(const ZipFileRO& src); ZipFileRO& operator=(const ZipFileRO& src); + /* locate and parse the central directory */ + bool mapCentralDirectory(void); + /* parse the archive, prepping internal structures */ bool parseZipArchive(void); @@ -203,12 +211,21 @@ private: /* open Zip archive */ int mFd; + /* zip file name */ + char* mFileName; + + /* length of file */ + size_t mFileLength; + /* mapped file */ - FileMap* mFileMap; + FileMap* mDirectoryMap; /* number of entries in the Zip archive */ int mNumEntries; + /* CD directory offset in the Zip archive */ + off_t mDirectoryOffset; + /* * We know how many entries are in the Zip archive, so we have a * fixed-size hash table. We probe for an empty slot. diff --git a/include/utils/threads.h b/include/utils/threads.h index 5ac0c5e..1bcfaed 100644 --- a/include/utils/threads.h +++ b/include/utils/threads.h @@ -295,6 +295,96 @@ typedef Mutex::Autolock AutoMutex; /*****************************************************************************/ +#if defined(HAVE_PTHREADS) + +/* + * Simple mutex class. The implementation is system-dependent. + * + * The mutex must be unlocked by the thread that locked it. They are not + * recursive, i.e. the same thread can't lock it multiple times. + */ +class RWLock { +public: + enum { + PRIVATE = 0, + SHARED = 1 + }; + + RWLock(); + RWLock(const char* name); + RWLock(int type, const char* name = NULL); + ~RWLock(); + + status_t readLock(); + status_t tryReadLock(); + status_t writeLock(); + status_t tryWriteLock(); + void unlock(); + + class AutoRLock { + public: + inline AutoRLock(RWLock& rwlock) : mLock(rwlock) { mLock.readLock(); } + inline ~AutoRLock() { mLock.unlock(); } + private: + RWLock& mLock; + }; + + class AutoWLock { + public: + inline AutoWLock(RWLock& rwlock) : mLock(rwlock) { mLock.writeLock(); } + inline ~AutoWLock() { mLock.unlock(); } + private: + RWLock& mLock; + }; + +private: + // A RWLock cannot be copied + RWLock(const RWLock&); + RWLock& operator = (const RWLock&); + + pthread_rwlock_t mRWLock; +}; + +inline RWLock::RWLock() { + pthread_rwlock_init(&mRWLock, NULL); +} +inline RWLock::RWLock(const char* name) { + pthread_rwlock_init(&mRWLock, NULL); +} +inline RWLock::RWLock(int type, const char* name) { + if (type == SHARED) { + pthread_rwlockattr_t attr; + pthread_rwlockattr_init(&attr); + pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_SHARED); + pthread_rwlock_init(&mRWLock, &attr); + pthread_rwlockattr_destroy(&attr); + } else { + pthread_rwlock_init(&mRWLock, NULL); + } +} +inline RWLock::~RWLock() { + pthread_rwlock_destroy(&mRWLock); +} +inline status_t RWLock::readLock() { + return -pthread_rwlock_rdlock(&mRWLock); +} +inline status_t RWLock::tryReadLock() { + return -pthread_rwlock_tryrdlock(&mRWLock); +} +inline status_t RWLock::writeLock() { + return -pthread_rwlock_wrlock(&mRWLock); +} +inline status_t RWLock::tryWriteLock() { + return -pthread_rwlock_trywrlock(&mRWLock); +} +inline void RWLock::unlock() { + pthread_rwlock_unlock(&mRWLock); +} + +#endif // HAVE_PTHREADS + +/*****************************************************************************/ + /* * Condition variable class. The implementation is system-dependent. * |