diff options
-rw-r--r-- | libshims/Android.mk | 48 | ||||
-rw-r--r-- | libshims/include/ui/GraphicBuffer.h | 158 | ||||
-rw-r--r-- | libshims/include/ui/GraphicBufferAllocator.h | 95 | ||||
-rw-r--r-- | libshims/include/ui/GraphicBufferMapper.h | 67 | ||||
-rw-r--r-- | libshims/include/utils/Looper.h | 478 | ||||
-rw-r--r-- | libshims/include/utils/VectorImpl.h | 201 | ||||
-rw-r--r-- | libshims/ui/GraphicBuffer.cpp | 336 | ||||
-rw-r--r-- | libshims/ui/GraphicBufferAllocator.cpp | 159 | ||||
-rw-r--r-- | libshims/ui/GraphicBufferMapper.cpp | 119 | ||||
-rw-r--r-- | libshims/utils/Looper.cpp | 573 | ||||
-rw-r--r-- | libshims/utils/VectorImpl.cpp | 691 |
11 files changed, 2925 insertions, 0 deletions
diff --git a/libshims/Android.mk b/libshims/Android.mk new file mode 100644 index 0000000..3fd0761 --- /dev/null +++ b/libshims/Android.mk @@ -0,0 +1,48 @@ +# +# Copyright (C) 2016 The LineageOS 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. + +LOCAL_PATH := $(call my-dir) + + +# libshim_camera +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + ui/GraphicBuffer.cpp \ + ui/GraphicBufferAllocator.cpp \ + ui/GraphicBufferMapper.cpp \ + utils/Looper.cpp \ + utils/VectorImpl.cpp + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/include \ + external/safe-iop/include \ + system/core/libutils + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libhardware \ + liblog \ + libui \ + libsync \ + libutils + +LOCAL_MODULE := libshim_camera + +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_CLASS := SHARED_LIBRARIES + +include $(BUILD_SHARED_LIBRARY) diff --git a/libshims/include/ui/GraphicBuffer.h b/libshims/include/ui/GraphicBuffer.h new file mode 100644 index 0000000..e1e6a64 --- /dev/null +++ b/libshims/include/ui/GraphicBuffer.h @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_GRAPHIC_BUFFER_H +#define ANDROID_GRAPHIC_BUFFER_H + +#include <stdint.h> +#include <sys/types.h> + +#include <ui/ANativeObjectBase.h> +#include <ui/PixelFormat.h> +#include <ui/Rect.h> +#include <utils/Flattenable.h> +#include <utils/RefBase.h> + +#include <hardware/gralloc.h> + +struct ANativeWindowBuffer; + +namespace android { + +class GraphicBufferMapper; + +// =========================================================================== +// GraphicBuffer +// =========================================================================== + +class GraphicBuffer + : public ANativeObjectBase< ANativeWindowBuffer, GraphicBuffer, RefBase >, + public Flattenable<GraphicBuffer> +{ + friend class Flattenable<GraphicBuffer>; +public: + + enum { + USAGE_SW_READ_NEVER = GRALLOC_USAGE_SW_READ_NEVER, + USAGE_SW_READ_RARELY = GRALLOC_USAGE_SW_READ_RARELY, + USAGE_SW_READ_OFTEN = GRALLOC_USAGE_SW_READ_OFTEN, + USAGE_SW_READ_MASK = GRALLOC_USAGE_SW_READ_MASK, + + USAGE_SW_WRITE_NEVER = GRALLOC_USAGE_SW_WRITE_NEVER, + USAGE_SW_WRITE_RARELY = GRALLOC_USAGE_SW_WRITE_RARELY, + USAGE_SW_WRITE_OFTEN = GRALLOC_USAGE_SW_WRITE_OFTEN, + USAGE_SW_WRITE_MASK = GRALLOC_USAGE_SW_WRITE_MASK, + + USAGE_SOFTWARE_MASK = USAGE_SW_READ_MASK|USAGE_SW_WRITE_MASK, + + USAGE_PROTECTED = GRALLOC_USAGE_PROTECTED, + + USAGE_HW_TEXTURE = GRALLOC_USAGE_HW_TEXTURE, + USAGE_HW_RENDER = GRALLOC_USAGE_HW_RENDER, + USAGE_HW_2D = GRALLOC_USAGE_HW_2D, + USAGE_HW_COMPOSER = GRALLOC_USAGE_HW_COMPOSER, + USAGE_HW_VIDEO_ENCODER = GRALLOC_USAGE_HW_VIDEO_ENCODER, + USAGE_HW_MASK = GRALLOC_USAGE_HW_MASK, + }; + + GraphicBuffer(); + + // creates w * h buffer + GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, + uint32_t inUsage); + + // create a buffer from an existing handle + GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, + uint32_t inUsage, uint32_t inStride, native_handle_t* inHandle, + bool keepOwnership); + + // create a buffer from an existing ANativeWindowBuffer + GraphicBuffer(ANativeWindowBuffer* buffer, bool keepOwnership); + + // return status + status_t initCheck() const; + + uint32_t getWidth() const { return static_cast<uint32_t>(width); } + uint32_t getHeight() const { return static_cast<uint32_t>(height); } + uint32_t getStride() const { return static_cast<uint32_t>(stride); } + uint32_t getUsage() const { return static_cast<uint32_t>(usage); } + PixelFormat getPixelFormat() const { return format; } + Rect getBounds() const { return Rect(width, height); } + + status_t reallocate(uint32_t inWidth, uint32_t inHeight, + PixelFormat inFormat, uint32_t inUsage); + + status_t lock(uint32_t inUsage, void** vaddr); + status_t lock(uint32_t inUsage, const Rect& rect, void** vaddr); + // For HAL_PIXEL_FORMAT_YCbCr_420_888 + status_t lockYCbCr(uint32_t inUsage, android_ycbcr *ycbcr); + status_t lockYCbCr(uint32_t inUsage, const Rect& rect, + android_ycbcr *ycbcr); + status_t unlock(); + + ANativeWindowBuffer* getNativeBuffer() const; + + // for debugging + static void dumpAllocationsToSystemLog(); + + // Flattenable protocol + size_t getFlattenedSize() const; + size_t getFdCount() const; + status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const; + status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count); + +private: + ~GraphicBuffer(); + + enum { + ownNone = 0, + ownHandle = 1, + ownData = 2, + }; + + inline const GraphicBufferMapper& getBufferMapper() const { + return mBufferMapper; + } + inline GraphicBufferMapper& getBufferMapper() { + return mBufferMapper; + } + uint8_t mOwner; + +private: + friend class Surface; + friend class BpSurface; + friend class BnSurface; + friend class LightRefBase<GraphicBuffer>; + GraphicBuffer(const GraphicBuffer& rhs); + GraphicBuffer& operator = (const GraphicBuffer& rhs); + const GraphicBuffer& operator = (const GraphicBuffer& rhs) const; + + status_t initSize(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, + uint32_t inUsage); + + void free_handle(); + + GraphicBufferMapper& mBufferMapper; + ssize_t mInitCheck; + + // If we're wrapping another buffer then this reference will make sure it + // doesn't get freed. + sp<ANativeWindowBuffer> mWrappedBuffer; +}; + +}; // namespace android + +#endif // ANDROID_GRAPHIC_BUFFER_H diff --git a/libshims/include/ui/GraphicBufferAllocator.h b/libshims/include/ui/GraphicBufferAllocator.h new file mode 100644 index 0000000..b6094a7 --- /dev/null +++ b/libshims/include/ui/GraphicBufferAllocator.h @@ -0,0 +1,95 @@ +/* +** +** Copyright 2009, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#ifndef ANDROID_BUFFER_ALLOCATOR_H +#define ANDROID_BUFFER_ALLOCATOR_H + +#include <stdint.h> + +#include <cutils/native_handle.h> + +#include <utils/Errors.h> +#include <utils/KeyedVector.h> +#include <utils/threads.h> +#include <utils/Singleton.h> + +#include <ui/PixelFormat.h> + +#include <hardware/gralloc.h> + + +namespace android { +// --------------------------------------------------------------------------- + +class String8; + +class GraphicBufferAllocator : public Singleton<GraphicBufferAllocator> +{ +public: + enum { + USAGE_SW_READ_NEVER = GRALLOC_USAGE_SW_READ_NEVER, + USAGE_SW_READ_RARELY = GRALLOC_USAGE_SW_READ_RARELY, + USAGE_SW_READ_OFTEN = GRALLOC_USAGE_SW_READ_OFTEN, + USAGE_SW_READ_MASK = GRALLOC_USAGE_SW_READ_MASK, + + USAGE_SW_WRITE_NEVER = GRALLOC_USAGE_SW_WRITE_NEVER, + USAGE_SW_WRITE_RARELY = GRALLOC_USAGE_SW_WRITE_RARELY, + USAGE_SW_WRITE_OFTEN = GRALLOC_USAGE_SW_WRITE_OFTEN, + USAGE_SW_WRITE_MASK = GRALLOC_USAGE_SW_WRITE_MASK, + + USAGE_SOFTWARE_MASK = USAGE_SW_READ_MASK|USAGE_SW_WRITE_MASK, + + USAGE_HW_TEXTURE = GRALLOC_USAGE_HW_TEXTURE, + USAGE_HW_RENDER = GRALLOC_USAGE_HW_RENDER, + USAGE_HW_2D = GRALLOC_USAGE_HW_2D, + USAGE_HW_MASK = GRALLOC_USAGE_HW_MASK + }; + + static inline GraphicBufferAllocator& get() { return getInstance(); } + + status_t alloc(uint32_t w, uint32_t h, PixelFormat format, int usage, + buffer_handle_t* handle, int32_t* stride); + + status_t free(buffer_handle_t handle); + + void dump(String8& res) const; + static void dumpToSystemLog(); + +private: + struct alloc_rec_t { + uint32_t width; + uint32_t height; + uint32_t stride; + PixelFormat format; + uint32_t usage; + size_t size; + }; + + static Mutex sLock; + static KeyedVector<buffer_handle_t, alloc_rec_t> sAllocList; + + friend class Singleton<GraphicBufferAllocator>; + GraphicBufferAllocator(); + ~GraphicBufferAllocator(); + + alloc_device_t *mAllocDev; +}; + +// --------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_BUFFER_ALLOCATOR_H diff --git a/libshims/include/ui/GraphicBufferMapper.h b/libshims/include/ui/GraphicBufferMapper.h new file mode 100644 index 0000000..fbfdfc3 --- /dev/null +++ b/libshims/include/ui/GraphicBufferMapper.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_UI_BUFFER_MAPPER_H +#define ANDROID_UI_BUFFER_MAPPER_H + +#include <stdint.h> +#include <sys/types.h> + +#include <utils/Singleton.h> + +#include <hardware/gralloc.h> + + +struct gralloc_module_t; + +namespace android { + +// --------------------------------------------------------------------------- + +class Rect; + +class GraphicBufferMapper : public Singleton<GraphicBufferMapper> +{ +public: + static inline GraphicBufferMapper& get() { return getInstance(); } + + status_t registerBuffer(buffer_handle_t handle); + + status_t unregisterBuffer(buffer_handle_t handle); + + status_t lock(buffer_handle_t handle, + int usage, const Rect& bounds, void** vaddr); + + status_t lockYCbCr(buffer_handle_t handle, + int usage, const Rect& bounds, android_ycbcr *ycbcr); + + status_t unlock(buffer_handle_t handle); + + // dumps information about the mapping of this handle + void dump(buffer_handle_t handle); + +private: + friend class Singleton<GraphicBufferMapper>; + GraphicBufferMapper(); + gralloc_module_t const *mAllocMod; +}; + +// --------------------------------------------------------------------------- + +}; // namespace android + +#endif // ANDROID_UI_BUFFER_MAPPER_H + diff --git a/libshims/include/utils/Looper.h b/libshims/include/utils/Looper.h new file mode 100644 index 0000000..88e13cf --- /dev/null +++ b/libshims/include/utils/Looper.h @@ -0,0 +1,478 @@ +/* + * 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_LOOPER_H +#define UTILS_LOOPER_H + +#include <utils/threads.h> +#include <utils/RefBase.h> +#include <utils/KeyedVector.h> +#include <utils/Timers.h> + +#include <sys/epoll.h> + +namespace android { + +/* + * NOTE: Since Looper is used to implement the NDK ALooper, the Looper + * enums and the signature of Looper_callbackFunc need to align with + * that implementation. + */ + +/** + * For callback-based event loops, this is the prototype of the function + * that is called when a file descriptor event occurs. + * It is given the file descriptor it is associated with, + * a bitmask of the poll events that were triggered (typically EVENT_INPUT), + * and the data pointer that was originally supplied. + * + * Implementations should return 1 to continue receiving callbacks, or 0 + * to have this file descriptor and callback unregistered from the looper. + */ +typedef int (*Looper_callbackFunc)(int fd, int events, void* data); + +/** + * A message that can be posted to a Looper. + */ +struct Message { + Message() : what(0) { } + Message(int what) : what(what) { } + + /* The message type. (interpretation is left up to the handler) */ + int what; +}; + + +/** + * Interface for a Looper message handler. + * + * The Looper holds a strong reference to the message handler whenever it has + * a message to deliver to it. Make sure to call Looper::removeMessages + * to remove any pending messages destined for the handler so that the handler + * can be destroyed. + */ +class MessageHandler : public virtual RefBase { +protected: + virtual ~MessageHandler() { } + +public: + /** + * Handles a message. + */ + virtual void handleMessage(const Message& message) = 0; +}; + + +/** + * A simple proxy that holds a weak reference to a message handler. + */ +class WeakMessageHandler : public MessageHandler { +protected: + virtual ~WeakMessageHandler(); + +public: + WeakMessageHandler(const wp<MessageHandler>& handler); + virtual void handleMessage(const Message& message); + +private: + wp<MessageHandler> mHandler; +}; + + +/** + * A looper callback. + */ +class LooperCallback : public virtual RefBase { +protected: + virtual ~LooperCallback() { } + +public: + /** + * Handles a poll event for the given file descriptor. + * It is given the file descriptor it is associated with, + * a bitmask of the poll events that were triggered (typically EVENT_INPUT), + * and the data pointer that was originally supplied. + * + * Implementations should return 1 to continue receiving callbacks, or 0 + * to have this file descriptor and callback unregistered from the looper. + */ + virtual int handleEvent(int fd, int events, void* data) = 0; +}; + +/** + * Wraps a Looper_callbackFunc function pointer. + */ +class SimpleLooperCallback : public LooperCallback { +protected: + virtual ~SimpleLooperCallback(); + +public: + SimpleLooperCallback(Looper_callbackFunc callback); + virtual int handleEvent(int fd, int events, void* data); + +private: + Looper_callbackFunc mCallback; +}; + +/** + * A polling loop that supports monitoring file descriptor events, optionally + * using callbacks. The implementation uses epoll() internally. + * + * A looper can be associated with a thread although there is no requirement that it must be. + */ +class Looper : public RefBase { +protected: + virtual ~Looper(); + +public: + enum { + /** + * Result from Looper_pollOnce() and Looper_pollAll(): + * The poll was awoken using wake() before the timeout expired + * and no callbacks were executed and no other file descriptors were ready. + */ + POLL_WAKE = -1, + + /** + * Result from Looper_pollOnce() and Looper_pollAll(): + * One or more callbacks were executed. + */ + POLL_CALLBACK = -2, + + /** + * Result from Looper_pollOnce() and Looper_pollAll(): + * The timeout expired. + */ + POLL_TIMEOUT = -3, + + /** + * Result from Looper_pollOnce() and Looper_pollAll(): + * An error occurred. + */ + POLL_ERROR = -4, + }; + + /** + * Flags for file descriptor events that a looper can monitor. + * + * These flag bits can be combined to monitor multiple events at once. + */ + enum { + /** + * The file descriptor is available for read operations. + */ + EVENT_INPUT = 1 << 0, + + /** + * The file descriptor is available for write operations. + */ + EVENT_OUTPUT = 1 << 1, + + /** + * The file descriptor has encountered an error condition. + * + * The looper always sends notifications about errors; it is not necessary + * to specify this event flag in the requested event set. + */ + EVENT_ERROR = 1 << 2, + + /** + * The file descriptor was hung up. + * For example, indicates that the remote end of a pipe or socket was closed. + * + * The looper always sends notifications about hangups; it is not necessary + * to specify this event flag in the requested event set. + */ + EVENT_HANGUP = 1 << 3, + + /** + * The file descriptor is invalid. + * For example, the file descriptor was closed prematurely. + * + * The looper always sends notifications about invalid file descriptors; it is not necessary + * to specify this event flag in the requested event set. + */ + EVENT_INVALID = 1 << 4, + }; + + enum { + /** + * Option for Looper_prepare: this looper will accept calls to + * Looper_addFd() that do not have a callback (that is provide NULL + * for the callback). In this case the caller of Looper_pollOnce() + * or Looper_pollAll() MUST check the return from these functions to + * discover when data is available on such fds and process it. + */ + PREPARE_ALLOW_NON_CALLBACKS = 1<<0 + }; + + /** + * Creates a looper. + * + * If allowNonCallbaks is true, the looper will allow file descriptors to be + * registered without associated callbacks. This assumes that the caller of + * pollOnce() is prepared to handle callback-less events itself. + */ + Looper(bool allowNonCallbacks); + + /** + * Returns whether this looper instance allows the registration of file descriptors + * using identifiers instead of callbacks. + */ + bool getAllowNonCallbacks() const; + + /** + * Waits for events to be available, 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 an event appears. + * + * Returns POLL_WAKE if the poll was awoken using wake() before + * the timeout expired and no callbacks were invoked and no other file + * descriptors were ready. + * + * Returns POLL_CALLBACK if one or more callbacks were invoked. + * + * Returns POLL_TIMEOUT if there was no data before the given + * timeout expired. + * + * Returns POLL_ERROR if an error occurred. + * + * Returns a value >= 0 containing an identifier if its file descriptor has data + * and it has no callback function (requiring the caller here to handle it). + * In this (and only this) case outFd, outEvents and outData will contain the poll + * events and data associated with the fd, otherwise they will be set to NULL. + * + * This method does not return until it has finished invoking the appropriate callbacks + * for all file descriptors that were signalled. + */ + int pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData); + inline int pollOnce(int timeoutMillis) { + return pollOnce(timeoutMillis, NULL, NULL, NULL); + } + + /** + * Like pollOnce(), but performs all pending callbacks until all + * data has been consumed or a file descriptor is available with no callback. + * This function will never return POLL_CALLBACK. + */ + int pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData); + inline int pollAll(int timeoutMillis) { + return pollAll(timeoutMillis, NULL, NULL, NULL); + } + + /** + * Wakes the poll asynchronously. + * + * This method can be called on any thread. + * This method returns immediately. + */ + void wake(); + + /** + * Adds a new file descriptor to be polled by the looper. + * If the same file descriptor was previously added, it is replaced. + * + * "fd" is the file descriptor to be added. + * "ident" is an identifier for this event, which is returned from pollOnce(). + * The identifier must be >= 0, or POLL_CALLBACK if providing a non-NULL callback. + * "events" are the poll events to wake up on. Typically this is EVENT_INPUT. + * "callback" is the function to call when there is an event on the file descriptor. + * "data" is a private data pointer to supply to the callback. + * + * There are two main uses of this function: + * + * (1) If "callback" is non-NULL, then this function will be called when there is + * data on the file descriptor. It should execute any events it has pending, + * appropriately reading from the file descriptor. The 'ident' is ignored in this case. + * + * (2) If "callback" is NULL, the 'ident' will be returned by Looper_pollOnce + * when its file descriptor has data available, requiring the caller to take + * care of processing it. + * + * Returns 1 if the file descriptor was added, 0 if the arguments were invalid. + * + * This method can be called on any thread. + * This method may block briefly if it needs to wake the poll. + * + * The callback may either be specified as a bare function pointer or as a smart + * pointer callback object. The smart pointer should be preferred because it is + * easier to avoid races when the callback is removed from a different thread. + * See removeFd() for details. + */ + int addFd(int fd, int ident, int events, Looper_callbackFunc callback, void* data); + int addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data); + + /** + * Removes a previously added file descriptor from the looper. + * + * When this method returns, it is safe to close the file descriptor since the looper + * 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 0 or by calling this method, then it can be guaranteed to not be invoked + * again at any later time unless registered anew. + * + * A simple way to avoid this problem is to use the version of addFd() that takes + * a sp<LooperCallback> instead of a bare function pointer. The LooperCallback will + * be released at the appropriate time by the Looper. + * + * Returns 1 if the file descriptor was removed, 0 if none was previously registered. + * + * This method can be called on any thread. + * This method may block briefly if it needs to wake the poll. + */ + int removeFd(int fd); + + /** + * Enqueues a message to be processed by the specified handler. + * + * The handler must not be null. + * This method can be called on any thread. + */ + void sendMessage(const sp<MessageHandler>& handler, const Message& message); + + /** + * Enqueues a message to be processed by the specified handler after all pending messages + * after the specified delay. + * + * The time delay is specified in uptime nanoseconds. + * The handler must not be null. + * This method can be called on any thread. + */ + void sendMessageDelayed(nsecs_t uptimeDelay, const sp<MessageHandler>& handler, + const Message& message); + + /** + * Enqueues a message to be processed by the specified handler after all pending messages + * at the specified time. + * + * The time is specified in uptime nanoseconds. + * The handler must not be null. + * This method can be called on any thread. + */ + void sendMessageAtTime(nsecs_t uptime, const sp<MessageHandler>& handler, + const Message& message); + + /** + * Removes all messages for the specified handler from the queue. + * + * The handler must not be null. + * This method can be called on any thread. + */ + void removeMessages(const sp<MessageHandler>& handler); + + /** + * Removes all messages of a particular type for the specified handler from the queue. + * + * The handler must not be null. + * This method can be called on any thread. + */ + void removeMessages(const sp<MessageHandler>& handler, int what); + + /** + * Returns whether this looper's thread is currently polling for more work to do. + * This is a good signal that the loop is still alive rather than being stuck + * handling a callback. Note that this method is intrinsically racy, since the + * state of the loop can change before you get the result back. + */ + bool isPolling() const; + + /** + * Prepares a looper associated with the calling thread, and returns it. + * If the thread already has a looper, it is returned. Otherwise, a new + * one is created, associated with the thread, and returned. + * + * The opts may be PREPARE_ALLOW_NON_CALLBACKS or 0. + */ + static sp<Looper> prepare(int opts); + + /** + * Sets the given looper to be associated with the calling thread. + * If another looper is already associated with the thread, it is replaced. + * + * If "looper" is NULL, removes the currently associated looper. + */ + static void setForThread(const sp<Looper>& looper); + + /** + * Returns the looper associated with the calling thread, or NULL if + * there is not one. + */ + static sp<Looper> getForThread(); + +private: + struct Request { + int fd; + int ident; + sp<LooperCallback> callback; + void* data; + }; + + struct Response { + int events; + Request request; + }; + + struct MessageEnvelope { + MessageEnvelope() : uptime(0) { } + + MessageEnvelope(nsecs_t uptime, const sp<MessageHandler> handler, + const Message& message) : uptime(uptime), handler(handler), message(message) { + } + + nsecs_t uptime; + sp<MessageHandler> handler; + Message message; + }; + + const bool mAllowNonCallbacks; // immutable + + int mWakeReadPipeFd; // immutable + int mWakeWritePipeFd; // immutable + Mutex mLock; + + Vector<MessageEnvelope> mMessageEnvelopes; // guarded by mLock + bool mSendingMessage; // guarded by mLock + + // Whether we are currently waiting for work. Not protected by a lock, + // any use of it is racy anyway. + volatile bool mPolling; + + int mEpollFd; // immutable + + // Locked list of file descriptor monitoring requests. + KeyedVector<int, Request> mRequests; // guarded by mLock + + // This state is only used privately by pollOnce and does not require a lock since + // it runs on a single thread. + Vector<Response> mResponses; + size_t mResponseIndex; + nsecs_t mNextMessageUptime; // set to LLONG_MAX when none + + int pollInner(int timeoutMillis); + void awoken(); + void pushResponse(int events, const Request& request); + + static void initTLSKey(); + static void threadDestructor(void *st); +}; + +} // namespace android + +#endif // UTILS_LOOPER_H
\ No newline at end of file diff --git a/libshims/include/utils/VectorImpl.h b/libshims/include/utils/VectorImpl.h new file mode 100644 index 0000000..f5fa742 --- /dev/null +++ b/libshims/include/utils/VectorImpl.h @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2005 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_VECTOR_IMPL_H +#define ANDROID_VECTOR_IMPL_H + +#include <assert.h> +#include <stdint.h> +#include <sys/types.h> +#include <utils/Errors.h> + +// --------------------------------------------------------------------------- +// No user serviceable parts in here... +// --------------------------------------------------------------------------- + +namespace android { + +/*! + * Implementation of the guts of the vector<> class + * this ensures backward binary compatibility and + * reduces code size. + * For performance reasons, we expose mStorage and mCount + * so these fields are set in stone. + * + */ + +class VectorImpl +{ +public: + enum { // flags passed to the ctor + HAS_TRIVIAL_CTOR = 0x00000001, + HAS_TRIVIAL_DTOR = 0x00000002, + HAS_TRIVIAL_COPY = 0x00000004, + }; + + VectorImpl(size_t itemSize, uint32_t flags); + VectorImpl(const VectorImpl& rhs); + virtual ~VectorImpl(); + + /*! must be called from subclasses destructor */ + void finish_vector(); + + VectorImpl& operator = (const VectorImpl& rhs); + + /*! C-style array access */ + inline const void* arrayImpl() const { return mStorage; } + void* editArrayImpl(); + + /*! vector stats */ + inline size_t size() const { return mCount; } + inline bool isEmpty() const { return mCount == 0; } + size_t capacity() const; + ssize_t setCapacity(size_t size); + ssize_t resize(size_t size); + + /*! 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); + ssize_t insertAt(const void* item, size_t where, size_t numItems = 1); + void pop(); + void push(); + void push(const void* item); + ssize_t add(); + ssize_t add(const void* item); + ssize_t replaceAt(size_t index); + ssize_t replaceAt(const void* item, size_t index); + + /*! remove items */ + ssize_t removeItemsAt(size_t index, size_t count = 1); + void clear(); + + const void* itemLocation(size_t index) const; + void* editItemLocation(size_t index); + + typedef int (*compar_t)(const void* lhs, const void* rhs); + typedef int (*compar_r_t)(const void* lhs, const void* rhs, void* state); + status_t sort(compar_t cmp); + status_t sort(compar_r_t cmp, void* state); + +protected: + size_t itemSize() const; + void release_storage(); + + virtual void do_construct(void* storage, size_t num) const = 0; + virtual void do_destroy(void* storage, size_t num) const = 0; + virtual void do_copy(void* dest, const void* from, size_t num) const = 0; + virtual void do_splat(void* dest, const void* item, size_t num) const = 0; + virtual void do_move_forward(void* dest, const void* from, size_t num) const = 0; + virtual void do_move_backward(void* dest, const void* from, size_t num) const = 0; + + virtual void reservedVectorImpl1(); + virtual void reservedVectorImpl2(); + virtual void reservedVectorImpl3(); + virtual void reservedVectorImpl4(); + virtual void reservedVectorImpl5(); + virtual void reservedVectorImpl6(); + virtual void reservedVectorImpl7(); + virtual void reservedVectorImpl8(); + +private: + void* _grow(size_t where, size_t amount); + void _shrink(size_t where, size_t amount); + + inline void _do_construct(void* storage, size_t num) const; + inline void _do_destroy(void* storage, size_t num) const; + inline void _do_copy(void* dest, const void* from, size_t num) const; + inline void _do_splat(void* dest, const void* item, size_t num) const; + inline void _do_move_forward(void* dest, const void* from, size_t num) const; + inline void _do_move_backward(void* dest, const void* from, size_t num) const; + + // These 2 fields are exposed in the inlines below, + // so they're set in stone. + void * mStorage; // base address of the vector + size_t mCount; // number of items + + const uint32_t mFlags; + const size_t mItemSize; +}; + + + +class SortedVectorImpl : public VectorImpl +{ +public: + SortedVectorImpl(size_t itemSize, uint32_t flags); + SortedVectorImpl(const VectorImpl& rhs); + virtual ~SortedVectorImpl(); + + SortedVectorImpl& operator = (const SortedVectorImpl& rhs); + + //! finds the index of an item + ssize_t indexOf(const void* item) const; + + //! finds where this item should be inserted + size_t orderOf(const void* item) const; + + //! add an item in the right place (or replaces it if there is one) + ssize_t add(const void* item); + + //! merges a vector into this one + ssize_t merge(const VectorImpl& vector); + ssize_t merge(const SortedVectorImpl& vector); + + //! removes an item + ssize_t remove(const void* item); + +protected: + virtual int do_compare(const void* lhs, const void* rhs) const = 0; + + virtual void reservedSortedVectorImpl1(); + virtual void reservedSortedVectorImpl2(); + virtual void reservedSortedVectorImpl3(); + virtual void reservedSortedVectorImpl4(); + virtual void reservedSortedVectorImpl5(); + virtual void reservedSortedVectorImpl6(); + virtual void reservedSortedVectorImpl7(); + virtual void reservedSortedVectorImpl8(); + +private: + ssize_t _indexOrderOf(const void* item, size_t* order = 0) const; + + // these are made private, because they can't be used on a SortedVector + // (they don't have an implementation either) + ssize_t add(); + void pop(); + void push(); + 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); + ssize_t replaceAt(const void* item, size_t index); +}; + +}; // namespace android + + +// --------------------------------------------------------------------------- + +#endif // ANDROID_VECTOR_IMPL_H diff --git a/libshims/ui/GraphicBuffer.cpp b/libshims/ui/GraphicBuffer.cpp new file mode 100644 index 0000000..dad41b4 --- /dev/null +++ b/libshims/ui/GraphicBuffer.cpp @@ -0,0 +1,336 @@ +/* + * Copyright (C) 2007 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. + */ + +#define LOG_TAG "GraphicBuffer" + +#include <stdlib.h> +#include <stdint.h> +#include <sys/types.h> + +#include <utils/Errors.h> +#include <utils/Log.h> + +#include <ui/GraphicBuffer.h> +#include <ui/GraphicBufferAllocator.h> +#include <ui/GraphicBufferMapper.h> +#include <ui/PixelFormat.h> + +namespace android { + +// =========================================================================== +// Buffer and implementation of ANativeWindowBuffer +// =========================================================================== + +GraphicBuffer::GraphicBuffer() + : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()), + mInitCheck(NO_ERROR) +{ + width = + height = + stride = + format = + usage = 0; + handle = NULL; +} + +GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight, + PixelFormat inFormat, uint32_t inUsage) + : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()), + mInitCheck(NO_ERROR) +{ + width = + height = + stride = + format = + usage = 0; + handle = NULL; + mInitCheck = initSize(inWidth, inHeight, inFormat, inUsage); +} + +GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight, + PixelFormat inFormat, uint32_t inUsage, uint32_t inStride, + native_handle_t* inHandle, bool keepOwnership) + : BASE(), mOwner(keepOwnership ? ownHandle : ownNone), + mBufferMapper(GraphicBufferMapper::get()), + mInitCheck(NO_ERROR) +{ + width = static_cast<int>(inWidth); + height = static_cast<int>(inHeight); + stride = static_cast<int>(inStride); + format = inFormat; + usage = static_cast<int>(inUsage); + handle = inHandle; +} + +GraphicBuffer::GraphicBuffer(ANativeWindowBuffer* buffer, bool keepOwnership) + : BASE(), mOwner(keepOwnership ? ownHandle : ownNone), + mBufferMapper(GraphicBufferMapper::get()), + mInitCheck(NO_ERROR), mWrappedBuffer(buffer) +{ + width = buffer->width; + height = buffer->height; + stride = buffer->stride; + format = buffer->format; + usage = buffer->usage; + handle = buffer->handle; +} + +GraphicBuffer::~GraphicBuffer() +{ + if (handle) { + free_handle(); + } +} + +void GraphicBuffer::free_handle() +{ + if (mOwner == ownHandle) { + mBufferMapper.unregisterBuffer(handle); + native_handle_close(handle); + native_handle_delete(const_cast<native_handle*>(handle)); + } else if (mOwner == ownData) { + GraphicBufferAllocator& allocator(GraphicBufferAllocator::get()); + allocator.free(handle); + } + + mWrappedBuffer = 0; +} + +status_t GraphicBuffer::initCheck() const { + return static_cast<status_t>(mInitCheck); +} + +void GraphicBuffer::dumpAllocationsToSystemLog() +{ + GraphicBufferAllocator::dumpToSystemLog(); +} + +ANativeWindowBuffer* GraphicBuffer::getNativeBuffer() const +{ + LOG_ALWAYS_FATAL_IF(this == NULL, "getNativeBuffer() called on NULL GraphicBuffer"); + return static_cast<ANativeWindowBuffer*>( + const_cast<GraphicBuffer*>(this)); +} + +status_t GraphicBuffer::reallocate(uint32_t inWidth, uint32_t inHeight, + PixelFormat inFormat, uint32_t inUsage) +{ + if (mOwner != ownData) + return INVALID_OPERATION; + + if (handle && + static_cast<int>(inWidth) == width && + static_cast<int>(inHeight) == height && + inFormat == format && + static_cast<int>(inUsage) == usage) + return NO_ERROR; + + if (handle) { + GraphicBufferAllocator& allocator(GraphicBufferAllocator::get()); + allocator.free(handle); + handle = 0; + } + return initSize(inWidth, inHeight, inFormat, inUsage); +} + +status_t GraphicBuffer::initSize(uint32_t inWidth, uint32_t inHeight, + PixelFormat inFormat, uint32_t inUsage) +{ + GraphicBufferAllocator& allocator = GraphicBufferAllocator::get(); + int outStride = 0; + status_t err = allocator.alloc(inWidth, inHeight, inFormat, inUsage, + &handle, &outStride); + if (err == NO_ERROR) { + width = static_cast<int>(inWidth); + height = static_cast<int>(inHeight); + format = inFormat; + usage = static_cast<int>(inUsage); + stride = static_cast<int>(outStride); + } + return err; +} + +status_t GraphicBuffer::lock(uint32_t inUsage, void** vaddr) +{ + const Rect lockBounds(width, height); + status_t res = lock(inUsage, lockBounds, vaddr); + return res; +} + +status_t GraphicBuffer::lock(uint32_t inUsage, const Rect& rect, void** vaddr) +{ + if (rect.left < 0 || rect.right > width || + rect.top < 0 || rect.bottom > height) { + ALOGE("locking pixels (%d,%d,%d,%d) outside of buffer (w=%d, h=%d)", + rect.left, rect.top, rect.right, rect.bottom, + width, height); + return BAD_VALUE; + } + status_t res = getBufferMapper().lock(handle, inUsage, rect, vaddr); + return res; +} + +status_t GraphicBuffer::lockYCbCr(uint32_t inUsage, android_ycbcr* ycbcr) +{ + const Rect lockBounds(width, height); + status_t res = lockYCbCr(inUsage, lockBounds, ycbcr); + return res; +} + +status_t GraphicBuffer::lockYCbCr(uint32_t inUsage, const Rect& rect, + android_ycbcr* ycbcr) +{ + if (rect.left < 0 || rect.right > width || + rect.top < 0 || rect.bottom > height) { + ALOGE("locking pixels (%d,%d,%d,%d) outside of buffer (w=%d, h=%d)", + rect.left, rect.top, rect.right, rect.bottom, + width, height); + return BAD_VALUE; + } + status_t res = getBufferMapper().lockYCbCr(handle, inUsage, rect, ycbcr); + return res; +} + +status_t GraphicBuffer::unlock() +{ + status_t res = getBufferMapper().unlock(handle); + return res; +} + +size_t GraphicBuffer::getFlattenedSize() const { + return static_cast<size_t>(8 + (handle ? handle->numInts : 0)) * sizeof(int); +} + +size_t GraphicBuffer::getFdCount() const { + return static_cast<size_t>(handle ? handle->numFds : 0); +} + +status_t GraphicBuffer::flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const { + size_t sizeNeeded = GraphicBuffer::getFlattenedSize(); + if (size < sizeNeeded) return NO_MEMORY; + + size_t fdCountNeeded = GraphicBuffer::getFdCount(); + if (count < fdCountNeeded) return NO_MEMORY; + + int* buf = static_cast<int*>(buffer); + buf[0] = 'GBFR'; + buf[1] = width; + buf[2] = height; + buf[3] = stride; + buf[4] = format; + buf[5] = usage; + buf[6] = 0; + buf[7] = 0; + + if (handle) { + buf[6] = handle->numFds; + buf[7] = handle->numInts; + memcpy(fds, handle->data, + static_cast<size_t>(handle->numFds) * sizeof(int)); + memcpy(&buf[8], handle->data + handle->numFds, + static_cast<size_t>(handle->numInts) * sizeof(int)); + } + + buffer = static_cast<void*>(static_cast<int*>(buffer) + sizeNeeded); + size -= sizeNeeded; + if (handle) { + fds += handle->numFds; + count -= static_cast<size_t>(handle->numFds); + } + + return NO_ERROR; +} + +status_t GraphicBuffer::unflatten( + void const*& buffer, size_t& size, int const*& fds, size_t& count) { + if (size < 8 * sizeof(int)) return NO_MEMORY; + + int const* buf = static_cast<int const*>(buffer); + if (buf[0] != 'GBFR') return BAD_TYPE; + + const size_t numFds = static_cast<size_t>(buf[6]); + const size_t numInts = static_cast<size_t>(buf[7]); + + // Limit the maxNumber to be relatively small. The number of fds or ints + // should not come close to this number, and the number itself was simply + // chosen to be high enough to not cause issues and low enough to prevent + // overflow problems. + const size_t maxNumber = 4096; + if (numFds >= maxNumber || numInts >= (maxNumber - 10)) { + width = height = stride = format = usage = 0; + handle = NULL; + ALOGE("unflatten: numFds or numInts is too large: %zd, %zd", + numFds, numInts); + return BAD_VALUE; + } + + const size_t sizeNeeded = (8 + numInts) * sizeof(int); + if (size < sizeNeeded) return NO_MEMORY; + + size_t fdCountNeeded = numFds; + if (count < fdCountNeeded) return NO_MEMORY; + + if (handle) { + // free previous handle if any + free_handle(); + } + + if (numFds || numInts) { + width = buf[1]; + height = buf[2]; + stride = buf[3]; + format = buf[4]; + usage = buf[5]; + native_handle* h = native_handle_create( + static_cast<int>(numFds), static_cast<int>(numInts)); + if (!h) { + width = height = stride = format = usage = 0; + handle = NULL; + ALOGE("unflatten: native_handle_create failed"); + return NO_MEMORY; + } + memcpy(h->data, fds, numFds * sizeof(int)); + memcpy(h->data + numFds, &buf[8], numInts * sizeof(int)); + handle = h; + } else { + width = height = stride = format = usage = 0; + handle = NULL; + } + + mOwner = ownHandle; + + if (handle != 0) { + status_t err = mBufferMapper.registerBuffer(handle); + if (err != NO_ERROR) { + width = height = stride = format = usage = 0; + handle = NULL; + ALOGE("unflatten: registerBuffer failed: %s (%d)", + strerror(-err), err); + return err; + } + } + + buffer = static_cast<void const*>(static_cast<int const*>(buffer) + sizeNeeded); + size -= sizeNeeded; + fds += numFds; + count -= numFds; + + return NO_ERROR; +} + +// --------------------------------------------------------------------------- + +}; // namespace android diff --git a/libshims/ui/GraphicBufferAllocator.cpp b/libshims/ui/GraphicBufferAllocator.cpp new file mode 100644 index 0000000..4f93fb6 --- /dev/null +++ b/libshims/ui/GraphicBufferAllocator.cpp @@ -0,0 +1,159 @@ +/* +** +** Copyright 2009, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#define LOG_TAG "GraphicBufferAllocator" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +#include <cutils/log.h> + +#include <utils/Singleton.h> +#include <utils/String8.h> +#include <utils/Trace.h> + +#include <ui/GraphicBufferAllocator.h> + +namespace android { +// --------------------------------------------------------------------------- + +ANDROID_SINGLETON_STATIC_INSTANCE( GraphicBufferAllocator ) + +Mutex GraphicBufferAllocator::sLock; +KeyedVector<buffer_handle_t, + GraphicBufferAllocator::alloc_rec_t> GraphicBufferAllocator::sAllocList; + +GraphicBufferAllocator::GraphicBufferAllocator() + : mAllocDev(0) +{ + hw_module_t const* module; + int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module); + ALOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID); + if (err == 0) { + gralloc_open(module, &mAllocDev); + } +} + +GraphicBufferAllocator::~GraphicBufferAllocator() +{ + gralloc_close(mAllocDev); +} + +void GraphicBufferAllocator::dump(String8& result) const +{ + Mutex::Autolock _l(sLock); + KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList); + size_t total = 0; + const size_t SIZE = 4096; + char buffer[SIZE]; + snprintf(buffer, SIZE, "Allocated buffers:\n"); + result.append(buffer); + const size_t c = list.size(); + for (size_t i=0 ; i<c ; i++) { + const alloc_rec_t& rec(list.valueAt(i)); + if (rec.size) { + snprintf(buffer, SIZE, "%10p: %7.2f KiB | %4u (%4u) x %4u | %8X | 0x%08x\n", + list.keyAt(i), rec.size/1024.0f, + rec.width, rec.stride, rec.height, rec.format, rec.usage); + } else { + snprintf(buffer, SIZE, "%10p: unknown | %4u (%4u) x %4u | %8X | 0x%08x\n", + list.keyAt(i), + rec.width, rec.stride, rec.height, rec.format, rec.usage); + } + result.append(buffer); + total += rec.size; + } + snprintf(buffer, SIZE, "Total allocated (estimate): %.2f KB\n", total/1024.0f); + result.append(buffer); + if (mAllocDev->common.version >= 1 && mAllocDev->dump) { + mAllocDev->dump(mAllocDev, buffer, SIZE); + result.append(buffer); + } +} + +void GraphicBufferAllocator::dumpToSystemLog() +{ + String8 s; + GraphicBufferAllocator::getInstance().dump(s); + ALOGD("%s", s.string()); +} + +status_t GraphicBufferAllocator::alloc(uint32_t width, uint32_t height, + PixelFormat format, int usage, buffer_handle_t* handle, + int32_t* stride) +{ + ATRACE_CALL(); + + // make sure to not allocate a N x 0 or 0 x N buffer, since this is + // allowed from an API stand-point allocate a 1x1 buffer instead. + if (!width || !height) + width = height = 1; + + // we have a h/w allocator and h/w buffer is requested + status_t err; + + // Filter out any usage bits that should not be passed to the gralloc module + usage &= GRALLOC_USAGE_ALLOC_MASK; + + int outStride = 0; + err = mAllocDev->alloc(mAllocDev, static_cast<int>(width), + static_cast<int>(height), format, static_cast<int>(usage), handle, + &outStride); + *stride = static_cast<uint32_t>(outStride); + + ALOGW_IF(err, "alloc(%u, %u, %d, %08x, ...) failed %d (%s)", + width, height, format, usage, err, strerror(-err)); + + if (err == NO_ERROR) { + Mutex::Autolock _l(sLock); + KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList); + int bpp = bytesPerPixel(format); + if (bpp < 0) { + // probably a HAL custom format. in any case, we don't know + // what its pixel size is. + bpp = 0; + } + alloc_rec_t rec; + rec.width = width; + rec.height = height; + rec.stride = *stride; + rec.format = format; + rec.usage = usage; + rec.size = static_cast<size_t>(height * (*stride) * bpp); + list.add(*handle, rec); + } + + return err; +} + +status_t GraphicBufferAllocator::free(buffer_handle_t handle) +{ + ATRACE_CALL(); + status_t err; + + err = mAllocDev->free(mAllocDev, handle); + + ALOGW_IF(err, "free(...) failed %d (%s)", err, strerror(-err)); + if (err == NO_ERROR) { + Mutex::Autolock _l(sLock); + KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList); + list.removeItem(handle); + } + + return err; +} + +// --------------------------------------------------------------------------- +}; // namespace android diff --git a/libshims/ui/GraphicBufferMapper.cpp b/libshims/ui/GraphicBufferMapper.cpp new file mode 100644 index 0000000..18be8ae --- /dev/null +++ b/libshims/ui/GraphicBufferMapper.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2007 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. + */ + +#define LOG_TAG "GraphicBufferMapper" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +#include <stdint.h> +#include <errno.h> + +#include <sync/sync.h> + +#include <utils/Errors.h> +#include <utils/Log.h> +#include <utils/Trace.h> + +#include <ui/GraphicBufferMapper.h> +#include <ui/Rect.h> + +#include <hardware/gralloc.h> + + +namespace android { +// --------------------------------------------------------------------------- + +ANDROID_SINGLETON_STATIC_INSTANCE( GraphicBufferMapper ) + +GraphicBufferMapper::GraphicBufferMapper() + : mAllocMod(0) +{ + hw_module_t const* module; + int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module); + ALOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID); + if (err == 0) { + mAllocMod = reinterpret_cast<gralloc_module_t const *>(module); + } +} + +status_t GraphicBufferMapper::registerBuffer(buffer_handle_t handle) +{ + ATRACE_CALL(); + status_t err; + + err = mAllocMod->registerBuffer(mAllocMod, handle); + + ALOGW_IF(err, "registerBuffer(%p) failed %d (%s)", + handle, err, strerror(-err)); + return err; +} + +status_t GraphicBufferMapper::unregisterBuffer(buffer_handle_t handle) +{ + ATRACE_CALL(); + status_t err; + + err = mAllocMod->unregisterBuffer(mAllocMod, handle); + + ALOGW_IF(err, "unregisterBuffer(%p) failed %d (%s)", + handle, err, strerror(-err)); + return err; +} + +status_t GraphicBufferMapper::lock(buffer_handle_t handle, + int usage, const Rect& bounds, void** vaddr) +{ + ATRACE_CALL(); + status_t err; + + err = mAllocMod->lock(mAllocMod, handle, static_cast<int>(usage), + bounds.left, bounds.top, bounds.width(), bounds.height(), + vaddr); + + ALOGW_IF(err, "lock(...) failed %d (%s)", err, strerror(-err)); + return err; +} + +status_t GraphicBufferMapper::lockYCbCr(buffer_handle_t handle, + int usage, const Rect& bounds, android_ycbcr *ycbcr) +{ + ATRACE_CALL(); + status_t err; + + if (mAllocMod->lock_ycbcr == NULL) { + return -EINVAL; // do not log failure + } + + err = mAllocMod->lock_ycbcr(mAllocMod, handle, static_cast<int>(usage), + bounds.left, bounds.top, bounds.width(), bounds.height(), + ycbcr); + + ALOGW_IF(err, "lock(...) failed %d (%s)", err, strerror(-err)); + return err; +} + +status_t GraphicBufferMapper::unlock(buffer_handle_t handle) +{ + ATRACE_CALL(); + status_t err; + + err = mAllocMod->unlock(mAllocMod, handle); + + ALOGW_IF(err, "unlock(...) failed %d (%s)", err, strerror(-err)); + return err; +} + +// --------------------------------------------------------------------------- +}; // namespace android diff --git a/libshims/utils/Looper.cpp b/libshims/utils/Looper.cpp new file mode 100644 index 0000000..4bab6d5 --- /dev/null +++ b/libshims/utils/Looper.cpp @@ -0,0 +1,573 @@ +// +// Copyright 2010 The Android Open Source Project +// +// A looper implementation based on epoll(). +// +#define LOG_TAG "Looper" + +//#define LOG_NDEBUG 0 + +// Debugs poll and wake interactions. +#define DEBUG_POLL_AND_WAKE 0 + +// Debugs callback registration and invocation. +#define DEBUG_CALLBACKS 0 + +#include <cutils/log.h> +#include <utils/Looper.h> +#include <utils/Timers.h> + +#include <unistd.h> +#include <fcntl.h> +#include <limits.h> + + +namespace android { + +// --- WeakMessageHandler --- + +WeakMessageHandler::WeakMessageHandler(const wp<MessageHandler>& handler) : + mHandler(handler) { +} + +WeakMessageHandler::~WeakMessageHandler() { +} + +void WeakMessageHandler::handleMessage(const Message& message) { + sp<MessageHandler> handler = mHandler.promote(); + if (handler != NULL) { + handler->handleMessage(message); + } +} + + +// --- SimpleLooperCallback --- + +SimpleLooperCallback::SimpleLooperCallback(Looper_callbackFunc callback) : + mCallback(callback) { +} + +SimpleLooperCallback::~SimpleLooperCallback() { +} + +int SimpleLooperCallback::handleEvent(int fd, int events, void* data) { + return mCallback(fd, events, data); +} + + +// --- Looper --- + +// Hint for number of file descriptors to be associated with the epoll instance. +static const int EPOLL_SIZE_HINT = 8; + +// Maximum number of file descriptors for which to retrieve poll events each iteration. +static const int EPOLL_MAX_EVENTS = 16; + +static pthread_once_t gTLSOnce = PTHREAD_ONCE_INIT; +static pthread_key_t gTLSKey = 0; + +Looper::Looper(bool allowNonCallbacks) : + mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false), + mResponseIndex(0), mNextMessageUptime(LLONG_MAX) { + int wakeFds[2]; + int result = pipe(wakeFds); + LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno); + + mWakeReadPipeFd = wakeFds[0]; + mWakeWritePipeFd = wakeFds[1]; + + result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK); + LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d", + errno); + + result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK); + LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d", + errno); + + mPolling = false; + + // Allocate the epoll instance and register the wake pipe. + mEpollFd = epoll_create(EPOLL_SIZE_HINT); + LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d", errno); + + struct epoll_event eventItem; + memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union + eventItem.events = EPOLLIN; + eventItem.data.fd = mWakeReadPipeFd; + result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem); + LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d", + errno); +} + +Looper::~Looper() { + close(mWakeReadPipeFd); + close(mWakeWritePipeFd); + close(mEpollFd); +} + +void Looper::initTLSKey() { + int result = pthread_key_create(& gTLSKey, threadDestructor); + LOG_ALWAYS_FATAL_IF(result != 0, "Could not allocate TLS key."); +} + +void Looper::threadDestructor(void *st) { + Looper* const self = static_cast<Looper*>(st); + if (self != NULL) { + self->decStrong((void*)threadDestructor); + } +} + +void Looper::setForThread(const sp<Looper>& looper) { + sp<Looper> old = getForThread(); // also has side-effect of initializing TLS + + if (looper != NULL) { + looper->incStrong((void*)threadDestructor); + } + + pthread_setspecific(gTLSKey, looper.get()); + + if (old != NULL) { + old->decStrong((void*)threadDestructor); + } +} + +sp<Looper> Looper::getForThread() { + int result = pthread_once(& gTLSOnce, initTLSKey); + LOG_ALWAYS_FATAL_IF(result != 0, "pthread_once failed"); + + return (Looper*)pthread_getspecific(gTLSKey); +} + +sp<Looper> Looper::prepare(int opts) { + bool allowNonCallbacks = opts & PREPARE_ALLOW_NON_CALLBACKS; + sp<Looper> looper = Looper::getForThread(); + if (looper == NULL) { + looper = new Looper(allowNonCallbacks); + Looper::setForThread(looper); + } + if (looper->getAllowNonCallbacks() != allowNonCallbacks) { + ALOGW("Looper already prepared for this thread with a different value for the " + "LOOPER_PREPARE_ALLOW_NON_CALLBACKS option."); + } + return looper; +} + +bool Looper::getAllowNonCallbacks() const { + return mAllowNonCallbacks; +} + +int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) { + int result = 0; + for (;;) { + while (mResponseIndex < mResponses.size()) { + const Response& response = mResponses.itemAt(mResponseIndex++); + int ident = response.request.ident; + if (ident >= 0) { + int fd = response.request.fd; + int events = response.events; + void* data = response.request.data; +#if DEBUG_POLL_AND_WAKE + ALOGD("%p ~ pollOnce - returning signalled identifier %d: " + "fd=%d, events=0x%x, data=%p", + this, ident, fd, events, data); +#endif + if (outFd != NULL) *outFd = fd; + if (outEvents != NULL) *outEvents = events; + if (outData != NULL) *outData = data; + return ident; + } + } + + if (result != 0) { +#if DEBUG_POLL_AND_WAKE + ALOGD("%p ~ pollOnce - returning result %d", this, result); +#endif + if (outFd != NULL) *outFd = 0; + if (outEvents != NULL) *outEvents = 0; + if (outData != NULL) *outData = NULL; + return result; + } + + result = pollInner(timeoutMillis); + } +} + +int Looper::pollInner(int timeoutMillis) { +#if DEBUG_POLL_AND_WAKE + ALOGD("%p ~ pollOnce - waiting: timeoutMillis=%d", this, timeoutMillis); +#endif + + // Adjust the timeout based on when the next message is due. + if (timeoutMillis != 0 && mNextMessageUptime != LLONG_MAX) { + nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); + int messageTimeoutMillis = toMillisecondTimeoutDelay(now, mNextMessageUptime); + if (messageTimeoutMillis >= 0 + && (timeoutMillis < 0 || messageTimeoutMillis < timeoutMillis)) { + timeoutMillis = messageTimeoutMillis; + } +#if DEBUG_POLL_AND_WAKE + ALOGD("%p ~ pollOnce - next message in %lldns, adjusted timeout: timeoutMillis=%d", + this, mNextMessageUptime - now, timeoutMillis); +#endif + } + + // Poll. + int result = POLL_WAKE; + mResponses.clear(); + mResponseIndex = 0; + + // We are about to idle. + mPolling = true; + + struct epoll_event eventItems[EPOLL_MAX_EVENTS]; + int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis); + + // No longer idling. + mPolling = false; + + // Acquire lock. + mLock.lock(); + + // Check for poll error. + if (eventCount < 0) { + if (errno == EINTR) { + goto Done; + } + ALOGW("Poll failed with an unexpected error, errno=%d", errno); + result = POLL_ERROR; + goto Done; + } + + // Check for poll timeout. + if (eventCount == 0) { +#if DEBUG_POLL_AND_WAKE + ALOGD("%p ~ pollOnce - timeout", this); +#endif + result = POLL_TIMEOUT; + goto Done; + } + + // Handle all events. +#if DEBUG_POLL_AND_WAKE + ALOGD("%p ~ pollOnce - handling events from %d fds", this, eventCount); +#endif + + for (int i = 0; i < eventCount; i++) { + int fd = eventItems[i].data.fd; + uint32_t epollEvents = eventItems[i].events; + if (fd == mWakeReadPipeFd) { + if (epollEvents & EPOLLIN) { + awoken(); + } else { + ALOGW("Ignoring unexpected epoll events 0x%x on wake read pipe.", epollEvents); + } + } else { + ssize_t requestIndex = mRequests.indexOfKey(fd); + if (requestIndex >= 0) { + int events = 0; + if (epollEvents & EPOLLIN) events |= EVENT_INPUT; + if (epollEvents & EPOLLOUT) events |= EVENT_OUTPUT; + if (epollEvents & EPOLLERR) events |= EVENT_ERROR; + if (epollEvents & EPOLLHUP) events |= EVENT_HANGUP; + pushResponse(events, mRequests.valueAt(requestIndex)); + } else { + ALOGW("Ignoring unexpected epoll events 0x%x on fd %d that is " + "no longer registered.", epollEvents, fd); + } + } + } +Done: ; + + // Invoke pending message callbacks. + mNextMessageUptime = LLONG_MAX; + while (mMessageEnvelopes.size() != 0) { + nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); + const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(0); + if (messageEnvelope.uptime <= now) { + // Remove the envelope from the list. + // We keep a strong reference to the handler until the call to handleMessage + // finishes. Then we drop it so that the handler can be deleted *before* + // we reacquire our lock. + { // obtain handler + sp<MessageHandler> handler = messageEnvelope.handler; + Message message = messageEnvelope.message; + mMessageEnvelopes.removeAt(0); + mSendingMessage = true; + mLock.unlock(); + +#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS + ALOGD("%p ~ pollOnce - sending message: handler=%p, what=%d", + this, handler.get(), message.what); +#endif + handler->handleMessage(message); + } // release handler + + mLock.lock(); + mSendingMessage = false; + result = POLL_CALLBACK; + } else { + // The last message left at the head of the queue determines the next wakeup time. + mNextMessageUptime = messageEnvelope.uptime; + break; + } + } + + // Release lock. + mLock.unlock(); + + // Invoke all response callbacks. + for (size_t i = 0; i < mResponses.size(); i++) { + Response& response = mResponses.editItemAt(i); + if (response.request.ident == POLL_CALLBACK) { + int fd = response.request.fd; + int events = response.events; + void* data = response.request.data; +#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS + ALOGD("%p ~ pollOnce - invoking fd event callback %p: fd=%d, events=0x%x, data=%p", + this, response.request.callback.get(), fd, events, data); +#endif + int callbackResult = response.request.callback->handleEvent(fd, events, data); + if (callbackResult == 0) { + removeFd(fd); + } + // Clear the callback reference in the response structure promptly because we + // will not clear the response vector itself until the next poll. + response.request.callback.clear(); + result = POLL_CALLBACK; + } + } + return result; +} + +int Looper::pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData) { + if (timeoutMillis <= 0) { + int result; + do { + result = pollOnce(timeoutMillis, outFd, outEvents, outData); + } while (result == POLL_CALLBACK); + return result; + } else { + nsecs_t endTime = systemTime(SYSTEM_TIME_MONOTONIC) + + milliseconds_to_nanoseconds(timeoutMillis); + + for (;;) { + int result = pollOnce(timeoutMillis, outFd, outEvents, outData); + if (result != POLL_CALLBACK) { + return result; + } + + nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); + timeoutMillis = toMillisecondTimeoutDelay(now, endTime); + if (timeoutMillis == 0) { + return POLL_TIMEOUT; + } + } + } +} + +void Looper::wake() { +#if DEBUG_POLL_AND_WAKE + ALOGD("%p ~ wake", this); +#endif + + ssize_t nWrite; + do { + nWrite = write(mWakeWritePipeFd, "W", 1); + } while (nWrite == -1 && errno == EINTR); + + if (nWrite != 1) { + if (errno != EAGAIN) { + ALOGW("Could not write wake signal, errno=%d", errno); + } + } +} + +void Looper::awoken() { +#if DEBUG_POLL_AND_WAKE + ALOGD("%p ~ awoken", this); +#endif + + char buffer[16]; + ssize_t nRead; + do { + nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer)); + } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer)); +} + +void Looper::pushResponse(int events, const Request& request) { + Response response; + response.events = events; + response.request = request; + mResponses.push(response); +} + +int Looper::addFd(int fd, int ident, int events, Looper_callbackFunc callback, void* data) { + return addFd(fd, ident, events, callback ? new SimpleLooperCallback(callback) : NULL, data); +} + +int Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data) { +#if DEBUG_CALLBACKS + ALOGD("%p ~ addFd - fd=%d, ident=%d, events=0x%x, callback=%p, data=%p", this, fd, ident, + events, callback.get(), data); +#endif + + if (!callback.get()) { + if (! mAllowNonCallbacks) { + ALOGE("Invalid attempt to set NULL callback but not allowed for this looper."); + return -1; + } + + if (ident < 0) { + ALOGE("Invalid attempt to set NULL callback with ident < 0."); + return -1; + } + } else { + ident = POLL_CALLBACK; + } + + int epollEvents = 0; + if (events & EVENT_INPUT) epollEvents |= EPOLLIN; + if (events & EVENT_OUTPUT) epollEvents |= EPOLLOUT; + + { // acquire lock + AutoMutex _l(mLock); + + Request request; + request.fd = fd; + request.ident = ident; + request.callback = callback; + request.data = data; + + struct epoll_event eventItem; + memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union + eventItem.events = epollEvents; + eventItem.data.fd = fd; + + ssize_t requestIndex = mRequests.indexOfKey(fd); + if (requestIndex < 0) { + int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem); + if (epollResult < 0) { + ALOGE("Error adding epoll events for fd %d, errno=%d", fd, errno); + return -1; + } + mRequests.add(fd, request); + } else { + int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, & eventItem); + if (epollResult < 0) { + ALOGE("Error modifying epoll events for fd %d, errno=%d", fd, errno); + return -1; + } + mRequests.replaceValueAt(requestIndex, request); + } + } // release lock + return 1; +} + +int Looper::removeFd(int fd) { +#if DEBUG_CALLBACKS + ALOGD("%p ~ removeFd - fd=%d", this, fd); +#endif + + { // acquire lock + AutoMutex _l(mLock); + ssize_t requestIndex = mRequests.indexOfKey(fd); + if (requestIndex < 0) { + return 0; + } + + int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, NULL); + if (epollResult < 0) { + ALOGE("Error removing epoll events for fd %d, errno=%d", fd, errno); + return -1; + } + + mRequests.removeItemsAt(requestIndex); + } // release lock + return 1; +} + +void Looper::sendMessage(const sp<MessageHandler>& handler, const Message& message) { + nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); + sendMessageAtTime(now, handler, message); +} + +void Looper::sendMessageDelayed(nsecs_t uptimeDelay, const sp<MessageHandler>& handler, + const Message& message) { + nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); + sendMessageAtTime(now + uptimeDelay, handler, message); +} + +void Looper::sendMessageAtTime(nsecs_t uptime, const sp<MessageHandler>& handler, + const Message& message) { +#if DEBUG_CALLBACKS + ALOGD("%p ~ sendMessageAtTime - uptime=%lld, handler=%p, what=%d", + this, uptime, handler.get(), message.what); +#endif + + size_t i = 0; + { // acquire lock + AutoMutex _l(mLock); + + size_t messageCount = mMessageEnvelopes.size(); + while (i < messageCount && uptime >= mMessageEnvelopes.itemAt(i).uptime) { + i += 1; + } + + MessageEnvelope messageEnvelope(uptime, handler, message); + mMessageEnvelopes.insertAt(messageEnvelope, i, 1); + + // Optimization: If the Looper is currently sending a message, then we can skip + // the call to wake() because the next thing the Looper will do after processing + // messages is to decide when the next wakeup time should be. In fact, it does + // not even matter whether this code is running on the Looper thread. + if (mSendingMessage) { + return; + } + } // release lock + + // Wake the poll loop only when we enqueue a new message at the head. + if (i == 0) { + wake(); + } +} + +void Looper::removeMessages(const sp<MessageHandler>& handler) { +#if DEBUG_CALLBACKS + ALOGD("%p ~ removeMessages - handler=%p", this, handler.get()); +#endif + + { // acquire lock + AutoMutex _l(mLock); + + for (size_t i = mMessageEnvelopes.size(); i != 0; ) { + const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(--i); + if (messageEnvelope.handler == handler) { + mMessageEnvelopes.removeAt(i); + } + } + } // release lock +} + +void Looper::removeMessages(const sp<MessageHandler>& handler, int what) { +#if DEBUG_CALLBACKS + ALOGD("%p ~ removeMessages - handler=%p, what=%d", this, handler.get(), what); +#endif + + { // acquire lock + AutoMutex _l(mLock); + + for (size_t i = mMessageEnvelopes.size(); i != 0; ) { + const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(--i); + if (messageEnvelope.handler == handler + && messageEnvelope.message.what == what) { + mMessageEnvelopes.removeAt(i); + } + } + } // release lock +} + +bool Looper::isPolling() const { + return mPolling; +} + +} // namespace android
\ No newline at end of file diff --git a/libshims/utils/VectorImpl.cpp b/libshims/utils/VectorImpl.cpp new file mode 100644 index 0000000..936cd37 --- /dev/null +++ b/libshims/utils/VectorImpl.cpp @@ -0,0 +1,691 @@ +/* + * Copyright (C) 2005 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. + */ + +#define LOG_TAG "Vector" + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> + +#include <log/log.h> +#include <safe_iop.h> + +#include <SharedBuffer.h> +#include <utils/Errors.h> +#include <utils/VectorImpl.h> + +/*****************************************************************************/ + + +namespace android { + +// ---------------------------------------------------------------------------- + +const size_t kMinVectorCapacity = 4; + +static inline size_t max(size_t a, size_t b) { + return a>b ? a : b; +} + +// ---------------------------------------------------------------------------- + +VectorImpl::VectorImpl(size_t itemSize, uint32_t flags) + : mStorage(0), mCount(0), mFlags(flags), mItemSize(itemSize) +{ +} + +VectorImpl::VectorImpl(const VectorImpl& rhs) + : mStorage(rhs.mStorage), mCount(rhs.mCount), + mFlags(rhs.mFlags), mItemSize(rhs.mItemSize) +{ + if (mStorage) { + SharedBuffer::bufferFromData(mStorage)->acquire(); + } +} + +VectorImpl::~VectorImpl() +{ + ALOGW_IF(mCount, + "[%p] subclasses of VectorImpl must call finish_vector()" + " in their destructor. Leaking %d bytes.", + this, (int)(mCount*mItemSize)); + // We can't call _do_destroy() here because the vtable is already gone. +} + +VectorImpl& VectorImpl::operator = (const VectorImpl& rhs) +{ + LOG_ALWAYS_FATAL_IF(mItemSize != rhs.mItemSize, + "Vector<> have different types (this=%p, rhs=%p)", this, &rhs); + if (this != &rhs) { + release_storage(); + if (rhs.mCount) { + mStorage = rhs.mStorage; + mCount = rhs.mCount; + SharedBuffer::bufferFromData(mStorage)->acquire(); + } else { + mStorage = 0; + mCount = 0; + } + } + return *this; +} + +void* VectorImpl::editArrayImpl() +{ + if (mStorage) { + const SharedBuffer* sb = SharedBuffer::bufferFromData(mStorage); + SharedBuffer* editable = sb->attemptEdit(); + if (editable == 0) { + // If we're here, we're not the only owner of the buffer. + // We must make a copy of it. + editable = SharedBuffer::alloc(sb->size()); + // Fail instead of returning a pointer to storage that's not + // editable. Otherwise we'd be editing the contents of a buffer + // for which we're not the only owner, which is undefined behaviour. + LOG_ALWAYS_FATAL_IF(editable == NULL); + _do_copy(editable->data(), mStorage, mCount); + release_storage(); + mStorage = editable->data(); + } + } + return mStorage; +} + +size_t VectorImpl::capacity() const +{ + if (mStorage) { + return SharedBuffer::bufferFromData(mStorage)->size() / mItemSize; + } + return 0; +} + +ssize_t VectorImpl::insertVectorAt(const VectorImpl& vector, size_t index) +{ + return insertArrayAt(vector.arrayImpl(), index, vector.size()); +} + +ssize_t VectorImpl::appendVector(const VectorImpl& vector) +{ + return insertVectorAt(vector, size()); +} + +ssize_t VectorImpl::insertArrayAt(const void* array, size_t index, size_t length) +{ + if (index > size()) + return BAD_INDEX; + void* where = _grow(index, length); + if (where) { + _do_copy(where, array, length); + } + return where ? index : (ssize_t)NO_MEMORY; +} + +ssize_t VectorImpl::appendArray(const void* array, size_t length) +{ + return insertArrayAt(array, size(), length); +} + +ssize_t VectorImpl::insertAt(size_t index, size_t numItems) +{ + return insertAt(0, index, numItems); +} + +ssize_t VectorImpl::insertAt(const void* item, size_t index, size_t numItems) +{ + if (index > size()) + return BAD_INDEX; + void* where = _grow(index, numItems); + if (where) { + if (item) { + _do_splat(where, item, numItems); + } else { + _do_construct(where, numItems); + } + } + return where ? index : (ssize_t)NO_MEMORY; +} + +static int sortProxy(const void* lhs, const void* rhs, void* func) +{ + return (*(VectorImpl::compar_t)func)(lhs, rhs); +} + +status_t VectorImpl::sort(VectorImpl::compar_t cmp) +{ + return sort(sortProxy, (void*)cmp); +} + +status_t VectorImpl::sort(VectorImpl::compar_r_t cmp, void* state) +{ + // the sort must be stable. we're using insertion sort which + // is well suited for small and already sorted arrays + // for big arrays, it could be better to use mergesort + const ssize_t count = size(); + if (count > 1) { + void* array = const_cast<void*>(arrayImpl()); + void* temp = 0; + ssize_t i = 1; + while (i < count) { + void* item = reinterpret_cast<char*>(array) + mItemSize*(i); + void* curr = reinterpret_cast<char*>(array) + mItemSize*(i-1); + if (cmp(curr, item, state) > 0) { + + if (!temp) { + // we're going to have to modify the array... + array = editArrayImpl(); + if (!array) return NO_MEMORY; + temp = malloc(mItemSize); + if (!temp) return NO_MEMORY; + item = reinterpret_cast<char*>(array) + mItemSize*(i); + curr = reinterpret_cast<char*>(array) + mItemSize*(i-1); + } else { + _do_destroy(temp, 1); + } + + _do_copy(temp, item, 1); + + ssize_t j = i-1; + void* next = reinterpret_cast<char*>(array) + mItemSize*(i); + do { + _do_destroy(next, 1); + _do_copy(next, curr, 1); + next = curr; + --j; + curr = reinterpret_cast<char*>(array) + mItemSize*(j); + } while (j>=0 && (cmp(curr, temp, state) > 0)); + + _do_destroy(next, 1); + _do_copy(next, temp, 1); + } + i++; + } + + if (temp) { + _do_destroy(temp, 1); + free(temp); + } + } + return NO_ERROR; +} + +void VectorImpl::pop() +{ + if (size()) + removeItemsAt(size()-1, 1); +} + +void VectorImpl::push() +{ + push(0); +} + +void VectorImpl::push(const void* item) +{ + insertAt(item, size()); +} + +ssize_t VectorImpl::add() +{ + return add(0); +} + +ssize_t VectorImpl::add(const void* item) +{ + return insertAt(item, size()); +} + +ssize_t VectorImpl::replaceAt(size_t index) +{ + return replaceAt(0, index); +} + +ssize_t VectorImpl::replaceAt(const void* prototype, size_t index) +{ + ALOG_ASSERT(index<size(), + "[%p] replace: index=%d, size=%d", this, (int)index, (int)size()); + + if (index >= size()) { + return BAD_INDEX; + } + + void* item = editItemLocation(index); + if (item != prototype) { + if (item == 0) + return NO_MEMORY; + _do_destroy(item, 1); + if (prototype == 0) { + _do_construct(item, 1); + } else { + _do_copy(item, prototype, 1); + } + } + return ssize_t(index); +} + +ssize_t VectorImpl::removeItemsAt(size_t index, size_t count) +{ + ALOG_ASSERT((index+count)<=size(), + "[%p] remove: index=%d, count=%d, size=%d", + this, (int)index, (int)count, (int)size()); + + if ((index+count) > size()) + return BAD_VALUE; + _shrink(index, count); + return index; +} + +void VectorImpl::finish_vector() +{ + release_storage(); + mStorage = 0; + mCount = 0; +} + +void VectorImpl::clear() +{ + _shrink(0, mCount); +} + +void* VectorImpl::editItemLocation(size_t index) +{ + ALOG_ASSERT(index<capacity(), + "[%p] editItemLocation: index=%d, capacity=%d, count=%d", + this, (int)index, (int)capacity(), (int)mCount); + + if (index < capacity()) { + void* buffer = editArrayImpl(); + if (buffer) { + return reinterpret_cast<char*>(buffer) + index*mItemSize; + } + } + return 0; +} + +const void* VectorImpl::itemLocation(size_t index) const +{ + ALOG_ASSERT(index<capacity(), + "[%p] itemLocation: index=%d, capacity=%d, count=%d", + this, (int)index, (int)capacity(), (int)mCount); + + if (index < capacity()) { + const void* buffer = arrayImpl(); + if (buffer) { + return reinterpret_cast<const char*>(buffer) + index*mItemSize; + } + } + return 0; +} + +ssize_t VectorImpl::setCapacity(size_t new_capacity) +{ + // The capacity must always be greater than or equal to the size + // of this vector. + if (new_capacity <= size()) { + return capacity(); + } + + size_t new_allocation_size = 0; + LOG_ALWAYS_FATAL_IF(!safe_mul(&new_allocation_size, new_capacity, mItemSize)); + SharedBuffer* sb = SharedBuffer::alloc(new_allocation_size); + if (sb) { + void* array = sb->data(); + _do_copy(array, mStorage, size()); + release_storage(); + mStorage = const_cast<void*>(array); + } else { + return NO_MEMORY; + } + return new_capacity; +} + +ssize_t VectorImpl::resize(size_t size) { + ssize_t result = NO_ERROR; + if (size > mCount) { + result = insertAt(mCount, size - mCount); + } else if (size < mCount) { + result = removeItemsAt(size, mCount - size); + } + return result < 0 ? result : size; +} + +void VectorImpl::release_storage() +{ + if (mStorage) { + const SharedBuffer* sb = SharedBuffer::bufferFromData(mStorage); + if (sb->release(SharedBuffer::eKeepStorage) == 1) { + _do_destroy(mStorage, mCount); + SharedBuffer::dealloc(sb); + } + } +} + +void* VectorImpl::_grow(size_t where, size_t amount) +{ +// ALOGV("_grow(this=%p, where=%d, amount=%d) count=%d, capacity=%d", +// this, (int)where, (int)amount, (int)mCount, (int)capacity()); + + ALOG_ASSERT(where <= mCount, + "[%p] _grow: where=%d, amount=%d, count=%d", + this, (int)where, (int)amount, (int)mCount); // caller already checked + + size_t new_size; + LOG_ALWAYS_FATAL_IF(!safe_add(&new_size, mCount, amount), "new_size overflow"); + + if (capacity() < new_size) { + // NOTE: This implementation used to resize vectors as per ((3*x + 1) / 2) + // (sigh..). Also note, the " + 1" was necessary to handle the special case + // where x == 1, where the resized_capacity will be equal to the old + // capacity without the +1. The old calculation wouldn't work properly + // if x was zero. + // + // This approximates the old calculation, using (x + (x/2) + 1) instead. + size_t new_capacity = 0; + LOG_ALWAYS_FATAL_IF(!safe_add(&new_capacity, new_size, (new_size / 2)), + "new_capacity overflow"); + LOG_ALWAYS_FATAL_IF(!safe_add(&new_capacity, new_capacity, static_cast<size_t>(1u)), + "new_capacity overflow"); + new_capacity = max(kMinVectorCapacity, new_capacity); + + size_t new_alloc_size = 0; + LOG_ALWAYS_FATAL_IF(!safe_mul(&new_alloc_size, new_capacity, mItemSize), + "new_alloc_size overflow"); + +// ALOGV("grow vector %p, new_capacity=%d", this, (int)new_capacity); + if ((mStorage) && + (mCount==where) && + (mFlags & HAS_TRIVIAL_COPY) && + (mFlags & HAS_TRIVIAL_DTOR)) + { + const SharedBuffer* cur_sb = SharedBuffer::bufferFromData(mStorage); + SharedBuffer* sb = cur_sb->editResize(new_alloc_size); + if (sb) { + mStorage = sb->data(); + } else { + return NULL; + } + } else { + SharedBuffer* sb = SharedBuffer::alloc(new_alloc_size); + if (sb) { + void* array = sb->data(); + if (where != 0) { + _do_copy(array, mStorage, where); + } + if (where != mCount) { + const void* from = reinterpret_cast<const uint8_t *>(mStorage) + where*mItemSize; + void* dest = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize; + _do_copy(dest, from, mCount-where); + } + release_storage(); + mStorage = const_cast<void*>(array); + } else { + return NULL; + } + } + } else { + void* array = editArrayImpl(); + if (where != mCount) { + const void* from = reinterpret_cast<const uint8_t *>(array) + where*mItemSize; + void* to = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize; + _do_move_forward(to, from, mCount - where); + } + } + mCount = new_size; + void* free_space = const_cast<void*>(itemLocation(where)); + return free_space; +} + +void VectorImpl::_shrink(size_t where, size_t amount) +{ + if (!mStorage) + return; + +// ALOGV("_shrink(this=%p, where=%d, amount=%d) count=%d, capacity=%d", +// this, (int)where, (int)amount, (int)mCount, (int)capacity()); + + ALOG_ASSERT(where + amount <= mCount, + "[%p] _shrink: where=%d, amount=%d, count=%d", + this, (int)where, (int)amount, (int)mCount); // caller already checked + + size_t new_size; + LOG_ALWAYS_FATAL_IF(!safe_sub(&new_size, mCount, amount)); + + if (new_size < (capacity() / 2)) { + // NOTE: (new_size * 2) is safe because capacity didn't overflow and + // new_size < (capacity / 2)). + const size_t new_capacity = max(kMinVectorCapacity, new_size * 2); + + // NOTE: (new_capacity * mItemSize), (where * mItemSize) and + // ((where + amount) * mItemSize) beyond this point are safe because + // we are always reducing the capacity of the underlying SharedBuffer. + // In other words, (old_capacity * mItemSize) did not overflow, and + // where < (where + amount) < new_capacity < old_capacity. + if ((where == new_size) && + (mFlags & HAS_TRIVIAL_COPY) && + (mFlags & HAS_TRIVIAL_DTOR)) + { + const SharedBuffer* cur_sb = SharedBuffer::bufferFromData(mStorage); + SharedBuffer* sb = cur_sb->editResize(new_capacity * mItemSize); + if (sb) { + mStorage = sb->data(); + } else { + return; + } + } else { + SharedBuffer* sb = SharedBuffer::alloc(new_capacity * mItemSize); + if (sb) { + void* array = sb->data(); + if (where != 0) { + _do_copy(array, mStorage, where); + } + if (where != new_size) { + const void* from = reinterpret_cast<const uint8_t *>(mStorage) + (where+amount)*mItemSize; + void* dest = reinterpret_cast<uint8_t *>(array) + where*mItemSize; + _do_copy(dest, from, new_size - where); + } + release_storage(); + mStorage = const_cast<void*>(array); + } else{ + return; + } + } + } else { + void* array = editArrayImpl(); + void* to = reinterpret_cast<uint8_t *>(array) + where*mItemSize; + _do_destroy(to, amount); + if (where != new_size) { + const void* from = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize; + _do_move_backward(to, from, new_size - where); + } + } + mCount = new_size; +} + +size_t VectorImpl::itemSize() const { + return mItemSize; +} + +void VectorImpl::_do_construct(void* storage, size_t num) const +{ + if (!(mFlags & HAS_TRIVIAL_CTOR)) { + do_construct(storage, num); + } +} + +void VectorImpl::_do_destroy(void* storage, size_t num) const +{ + if (!(mFlags & HAS_TRIVIAL_DTOR)) { + do_destroy(storage, num); + } +} + +void VectorImpl::_do_copy(void* dest, const void* from, size_t num) const +{ + if (!(mFlags & HAS_TRIVIAL_COPY)) { + do_copy(dest, from, num); + } else { + memcpy(dest, from, num*itemSize()); + } +} + +void VectorImpl::_do_splat(void* dest, const void* item, size_t num) const { + do_splat(dest, item, num); +} + +void VectorImpl::_do_move_forward(void* dest, const void* from, size_t num) const { + do_move_forward(dest, from, num); +} + +void VectorImpl::_do_move_backward(void* dest, const void* from, size_t num) const { + do_move_backward(dest, from, num); +} + +void VectorImpl::reservedVectorImpl1() { } +void VectorImpl::reservedVectorImpl2() { } +void VectorImpl::reservedVectorImpl3() { } +void VectorImpl::reservedVectorImpl4() { } +void VectorImpl::reservedVectorImpl5() { } +void VectorImpl::reservedVectorImpl6() { } +void VectorImpl::reservedVectorImpl7() { } +void VectorImpl::reservedVectorImpl8() { } + +/*****************************************************************************/ + +SortedVectorImpl::SortedVectorImpl(size_t itemSize, uint32_t flags) + : VectorImpl(itemSize, flags) +{ +} + +SortedVectorImpl::SortedVectorImpl(const VectorImpl& rhs) +: VectorImpl(rhs) +{ +} + +SortedVectorImpl::~SortedVectorImpl() +{ +} + +SortedVectorImpl& SortedVectorImpl::operator = (const SortedVectorImpl& rhs) +{ + return static_cast<SortedVectorImpl&>( VectorImpl::operator = (static_cast<const VectorImpl&>(rhs)) ); +} + +ssize_t SortedVectorImpl::indexOf(const void* item) const +{ + return _indexOrderOf(item); +} + +size_t SortedVectorImpl::orderOf(const void* item) const +{ + size_t o; + _indexOrderOf(item, &o); + return o; +} + +ssize_t SortedVectorImpl::_indexOrderOf(const void* item, size_t* order) const +{ + // binary search + ssize_t err = NAME_NOT_FOUND; + ssize_t l = 0; + ssize_t h = size()-1; + ssize_t mid; + const void* a = arrayImpl(); + const size_t s = itemSize(); + while (l <= h) { + mid = l + (h - l)/2; + const void* const curr = reinterpret_cast<const char *>(a) + (mid*s); + const int c = do_compare(curr, item); + if (c == 0) { + err = l = mid; + break; + } else if (c < 0) { + l = mid + 1; + } else { + h = mid - 1; + } + } + if (order) *order = l; + return err; +} + +ssize_t SortedVectorImpl::add(const void* item) +{ + size_t order; + ssize_t index = _indexOrderOf(item, &order); + if (index < 0) { + index = VectorImpl::insertAt(item, order, 1); + } else { + index = VectorImpl::replaceAt(item, index); + } + return index; +} + +ssize_t SortedVectorImpl::merge(const VectorImpl& vector) +{ + // naive merge... + if (!vector.isEmpty()) { + const void* buffer = vector.arrayImpl(); + const size_t is = itemSize(); + size_t s = vector.size(); + for (size_t i=0 ; i<s ; i++) { + ssize_t err = add( reinterpret_cast<const char*>(buffer) + i*is ); + if (err<0) { + return err; + } + } + } + return NO_ERROR; +} + +ssize_t SortedVectorImpl::merge(const SortedVectorImpl& vector) +{ + // we've merging a sorted vector... nice! + ssize_t err = NO_ERROR; + if (!vector.isEmpty()) { + // first take care of the case where the vectors are sorted together + if (do_compare(vector.itemLocation(vector.size()-1), arrayImpl()) <= 0) { + err = VectorImpl::insertVectorAt(static_cast<const VectorImpl&>(vector), 0); + } else if (do_compare(vector.arrayImpl(), itemLocation(size()-1)) >= 0) { + err = VectorImpl::appendVector(static_cast<const VectorImpl&>(vector)); + } else { + // this could be made a little better + err = merge(static_cast<const VectorImpl&>(vector)); + } + } + return err; +} + +ssize_t SortedVectorImpl::remove(const void* item) +{ + ssize_t i = indexOf(item); + if (i>=0) { + VectorImpl::removeItemsAt(i, 1); + } + return i; +} + +void SortedVectorImpl::reservedSortedVectorImpl1() { }; +void SortedVectorImpl::reservedSortedVectorImpl2() { }; +void SortedVectorImpl::reservedSortedVectorImpl3() { }; +void SortedVectorImpl::reservedSortedVectorImpl4() { }; +void SortedVectorImpl::reservedSortedVectorImpl5() { }; +void SortedVectorImpl::reservedSortedVectorImpl6() { }; +void SortedVectorImpl::reservedSortedVectorImpl7() { }; +void SortedVectorImpl::reservedSortedVectorImpl8() { }; + +/*****************************************************************************/ + +}; // namespace android + |