diff options
28 files changed, 823 insertions, 412 deletions
diff --git a/cmds/keystore/keystore.c b/cmds/keystore/keystore.c index 971a177ed3..afa64f8c9d 100644 --- a/cmds/keystore/keystore.c +++ b/cmds/keystore/keystore.c @@ -143,15 +143,20 @@ static void send_message(uint8_t *message, int length) send(the_socket, message, length, 0); } -/* Here is the file format. Values are encrypted by AES CBC, and MD5 is used to - * compute their checksums. To make the files portable, the length is stored in - * network order. Note that the first four bytes are reserved for future use and - * are always set to zero in this implementation. */ +/* Here is the file format. There are two parts in blob.value, the secret and + * the description. The secret is stored in ciphertext, and its original size + * can be found in blob.length. The description is stored after the secret in + * plaintext, and its size is specified in blob.info. The total size of the two + * parts must be no more than VALUE_SIZE bytes. The first three bytes of the + * file are reserved for future use and are always set to zero. Fields other + * than blob.info, blob.length, and blob.value are modified by encrypt_blob() + * and decrypt_blob(). Thus they should not be accessed from outside. */ static int the_entropy = -1; static struct __attribute__((packed)) { - uint32_t reserved; + uint8_t reserved[3]; + uint8_t info; uint8_t vector[AES_BLOCK_SIZE]; uint8_t encrypted[0]; uint8_t digest[MD5_DIGEST_LENGTH]; @@ -170,9 +175,13 @@ static int8_t encrypt_blob(char *name, AES_KEY *aes_key) return SYSTEM_ERROR; } - length = blob.length + blob.value - blob.encrypted; + length = blob.length + (blob.value - blob.encrypted); length = (length + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE * AES_BLOCK_SIZE; + if (blob.info != 0) { + memmove(&blob.encrypted[length], &blob.value[blob.length], blob.info); + } + blob.length = htonl(blob.length); MD5(blob.digested, length - (blob.digested - blob.encrypted), blob.digest); @@ -180,8 +189,8 @@ static int8_t encrypt_blob(char *name, AES_KEY *aes_key) AES_cbc_encrypt(blob.encrypted, blob.encrypted, length, aes_key, vector, AES_ENCRYPT); - blob.reserved = 0; - length += blob.encrypted - (uint8_t *)&blob; + memset(blob.reserved, 0, sizeof(blob.reserved)); + length += (blob.encrypted - (uint8_t *)&blob) + blob.info; fd = open(".tmp", O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR); length -= write(fd, &blob, length); @@ -200,7 +209,7 @@ static int8_t decrypt_blob(char *name, AES_KEY *aes_key) length = read(fd, &blob, sizeof(blob)); close(fd); - length -= blob.encrypted - (uint8_t *)&blob; + length -= (blob.encrypted - (uint8_t *)&blob) + blob.info; if (length < blob.value - blob.encrypted || length % AES_BLOCK_SIZE != 0) { return VALUE_CORRUPTED; } @@ -215,8 +224,13 @@ static int8_t decrypt_blob(char *name, AES_KEY *aes_key) length -= blob.value - blob.digested; blob.length = ntohl(blob.length); - return (blob.length < 0 || blob.length > length) ? VALUE_CORRUPTED : - NO_ERROR; + if (blob.length < 0 || blob.length > length) { + return VALUE_CORRUPTED; + } + if (blob.info != 0) { + memmove(&blob.value[blob.length], &blob.value[length], blob.info); + } + return NO_ERROR; } /* Here are the actions. Each of them is a function without arguments. All @@ -266,6 +280,7 @@ static int8_t insert() char name[NAME_MAX]; int n = sprintf(name, "%u_", uid); encode_key(&name[n], params[0].value, params[0].length); + blob.info = 0; blob.length = params[1].length; memcpy(blob.value, params[1].value, params[1].length); return encrypt_blob(name, &encryption_key); @@ -336,56 +351,88 @@ static int8_t reset() #define MASTER_KEY_FILE ".masterkey" #define MASTER_KEY_SIZE 16 +#define SALT_SIZE 16 -static void generate_key(uint8_t *key, uint8_t *password, int length) +static void set_key(uint8_t *key, uint8_t *password, int length, uint8_t *salt) { - PKCS5_PBKDF2_HMAC_SHA1((char *)password, length, (uint8_t *)"keystore", - sizeof("keystore"), 1024, MASTER_KEY_SIZE, key); + if (salt) { + PKCS5_PBKDF2_HMAC_SHA1((char *)password, length, salt, SALT_SIZE, + 8192, MASTER_KEY_SIZE, key); + } else { + PKCS5_PBKDF2_HMAC_SHA1((char *)password, length, (uint8_t *)"keystore", + sizeof("keystore"), 1024, MASTER_KEY_SIZE, key); + } } +/* Here is the history. To improve the security, the parameters to generate the + * master key has been changed. To make a seamless transition, we update the + * file using the same password when the user unlock it for the first time. If + * any thing goes wrong during the transition, the new file will not overwrite + * the old one. This avoids permanent damages of the existing data. */ + static int8_t password() { uint8_t key[MASTER_KEY_SIZE]; AES_KEY aes_key; - int n; + int8_t response = SYSTEM_ERROR; if (state == UNINITIALIZED) { - blob.length = MASTER_KEY_SIZE; if (read(the_entropy, blob.value, MASTER_KEY_SIZE) != MASTER_KEY_SIZE) { return SYSTEM_ERROR; } } else { - generate_key(key, params[0].value, params[0].length); + int fd = open(MASTER_KEY_FILE, O_RDONLY); + uint8_t *salt = NULL; + if (fd != -1) { + int length = read(fd, &blob, sizeof(blob)); + close(fd); + if (length > SALT_SIZE && blob.info == SALT_SIZE) { + salt = (uint8_t *)&blob + length - SALT_SIZE; + } + } + + set_key(key, params[0].value, params[0].length, salt); AES_set_decrypt_key(key, MASTER_KEY_SIZE * 8, &aes_key); - n = decrypt_blob(MASTER_KEY_FILE, &aes_key); - if (n == SYSTEM_ERROR) { + response = decrypt_blob(MASTER_KEY_FILE, &aes_key); + if (response == SYSTEM_ERROR) { return SYSTEM_ERROR; } - if (n != NO_ERROR || blob.length != MASTER_KEY_SIZE) { + if (response != NO_ERROR || blob.length != MASTER_KEY_SIZE) { if (retry <= 0) { reset(); return UNINITIALIZED; } return WRONG_PASSWORD + --retry; } + + if (!salt && params[1].length == -1) { + params[1] = params[0]; + } } if (params[1].length == -1) { memcpy(key, blob.value, MASTER_KEY_SIZE); } else { - generate_key(key, params[1].value, params[1].length); + uint8_t *salt = &blob.value[MASTER_KEY_SIZE]; + if (read(the_entropy, salt, SALT_SIZE) != SALT_SIZE) { + return SYSTEM_ERROR; + } + + set_key(key, params[1].value, params[1].length, salt); AES_set_encrypt_key(key, MASTER_KEY_SIZE * 8, &aes_key); memcpy(key, blob.value, MASTER_KEY_SIZE); - n = encrypt_blob(MASTER_KEY_FILE, &aes_key); + blob.info = SALT_SIZE; + blob.length = MASTER_KEY_SIZE; + response = encrypt_blob(MASTER_KEY_FILE, &aes_key); } - if (n == NO_ERROR) { + if (response == NO_ERROR) { AES_set_encrypt_key(key, MASTER_KEY_SIZE * 8, &encryption_key); AES_set_decrypt_key(key, MASTER_KEY_SIZE * 8, &decryption_key); state = NO_ERROR; retry = MAX_RETRY; } - return n; + return response; } static int8_t lock() diff --git a/include/private/surfaceflinger/SharedBufferStack.h b/include/private/surfaceflinger/SharedBufferStack.h index d68966791a..d6ae5e9deb 100644 --- a/include/private/surfaceflinger/SharedBufferStack.h +++ b/include/private/surfaceflinger/SharedBufferStack.h @@ -114,8 +114,9 @@ public: int32_t identity; // surface's identity (const) int32_t token; // surface's token (for debugging) - int32_t reserved32[1]; Statistics stats; + int8_t headBuf; // last retired buffer + uint8_t reservedBytes[3]; int32_t reserved; BufferData buffers[NUM_BUFFER_MAX]; // 1024 bytes }; @@ -201,6 +202,7 @@ public: status_t undoDequeue(int buf); status_t lock(int buf); + status_t cancel(int buf); status_t queue(int buf); bool needNewBuffer(int buffer) const; status_t setDirtyRegion(int buffer, const Region& reg); @@ -230,8 +232,9 @@ private: inline ssize_t operator()(); }; - struct UndoDequeueUpdate : public UpdateBase { - inline UndoDequeueUpdate(SharedBufferBase* sbb); + struct CancelUpdate : public UpdateBase { + int tail, buf; + inline CancelUpdate(SharedBufferBase* sbb, int tail, int buf); inline ssize_t operator()(); }; @@ -256,7 +259,6 @@ private: int mNumBuffers; int32_t tail; - int32_t undoDequeueTail; int32_t queued_head; // statistics... nsecs_t mDequeueTime[SharedBufferStack::NUM_BUFFER_MAX]; diff --git a/include/surfaceflinger/ISurfaceComposer.h b/include/surfaceflinger/ISurfaceComposer.h index 76307b2839..6533600238 100644 --- a/include/surfaceflinger/ISurfaceComposer.h +++ b/include/surfaceflinger/ISurfaceComposer.h @@ -115,7 +115,8 @@ public: */ virtual status_t captureScreen(DisplayID dpy, sp<IMemoryHeap>* heap, - uint32_t* width, uint32_t* height, PixelFormat* format) = 0; + uint32_t* width, uint32_t* height, PixelFormat* format, + uint32_t reqWidth, uint32_t reqHeight) = 0; /* Signal surfaceflinger that there might be some work to do * This is an ASYNCHRONOUS call. diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h index 7c5a39b680..22684db8f2 100644 --- a/include/surfaceflinger/Surface.h +++ b/include/surfaceflinger/Surface.h @@ -199,6 +199,7 @@ private: */ static int setSwapInterval(ANativeWindow* window, int interval); static int dequeueBuffer(ANativeWindow* window, android_native_buffer_t** buffer); + static int cancelBuffer(ANativeWindow* window, android_native_buffer_t* buffer); static int lockBuffer(ANativeWindow* window, android_native_buffer_t* buffer); static int queueBuffer(ANativeWindow* window, android_native_buffer_t* buffer); static int query(ANativeWindow* window, int what, int* value); @@ -207,6 +208,7 @@ private: int dequeueBuffer(android_native_buffer_t** buffer); int lockBuffer(android_native_buffer_t* buffer); int queueBuffer(android_native_buffer_t* buffer); + int cancelBuffer(android_native_buffer_t* buffer); int query(int what, int* value); int perform(int operation, va_list args); diff --git a/include/surfaceflinger/SurfaceComposerClient.h b/include/surfaceflinger/SurfaceComposerClient.h index 8773d7133b..a80832d5dd 100644 --- a/include/surfaceflinger/SurfaceComposerClient.h +++ b/include/surfaceflinger/SurfaceComposerClient.h @@ -170,6 +170,36 @@ private: }; // --------------------------------------------------------------------------- + +class ScreenshotClient +{ + sp<IMemoryHeap> mHeap; + uint32_t mWidth; + uint32_t mHeight; + PixelFormat mFormat; +public: + ScreenshotClient(); + + // frees the previous screenshot and capture a new one + status_t update(); + status_t update(uint32_t reqWidth, uint32_t reqHeight); + + // release memory occupied by the screenshot + void release(); + + // pixels are valid until this object is freed or + // release() or update() is called + void const* getPixels() const; + + uint32_t getWidth() const; + uint32_t getHeight() const; + PixelFormat getFormat() const; + uint32_t getStride() const; + // size of allocated memory in bytes + size_t getSize() const; +}; + +// --------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_SF_SURFACE_COMPOSER_CLIENT_H diff --git a/include/ui/EventHub.h b/include/ui/EventHub.h index d6b09dc01f..d78e35fbfa 100644 --- a/include/ui/EventHub.h +++ b/include/ui/EventHub.h @@ -142,8 +142,13 @@ protected: public: // Synthetic raw event type codes produced when devices are added or removed. enum { + // Sent when a device is added. DEVICE_ADDED = 0x10000000, - DEVICE_REMOVED = 0x20000000 + // Sent when a device is removed. + DEVICE_REMOVED = 0x20000000, + // Sent when all added/removed devices from the most recent scan have been reported. + // This event is always sent at least once. + FINISHED_DEVICE_SCAN = 0x30000000, }; virtual uint32_t getDeviceClasses(int32_t deviceId) const = 0; @@ -181,6 +186,8 @@ public: */ virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const = 0; + + virtual void dump(String8& dump) = 0; }; class EventHub : public EventHubInterface @@ -211,16 +218,18 @@ public: virtual bool getEvent(RawEvent* outEvent); + virtual void dump(String8& dump); + protected: virtual ~EventHub(); private: bool openPlatformInput(void); - int open_device(const char *device); - int close_device(const char *device); - int scan_dir(const char *dirname); - int read_notify(int nfd); + int openDevice(const char *device); + int closeDevice(const char *device); + int scanDir(const char *dirname); + int readNotify(int nfd); status_t mError; @@ -239,8 +248,8 @@ private: ~device_t(); }; - device_t* getDevice(int32_t deviceId) const; - bool hasKeycode(device_t* device, int keycode) const; + device_t* getDeviceLocked(int32_t deviceId) const; + bool hasKeycodeLocked(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; @@ -269,6 +278,7 @@ private: int mFDCount; bool mOpened; + bool mNeedToSendFinishedDeviceScan; List<String8> mExcludedDevices; // device ids that report particular switches. diff --git a/include/ui/Input.h b/include/ui/Input.h index 21baf32599..ee40b85d7b 100644 --- a/include/ui/Input.h +++ b/include/ui/Input.h @@ -73,7 +73,8 @@ namespace android { * policy decisions such as waking from device sleep. */ enum { - /* These flags originate in RawEvents and are generally set in the key map. */ + /* These flags originate in RawEvents and are generally set in the key map. + * See also labels for policy flags in KeycodeLabels.h. */ POLICY_FLAG_WAKE = 0x00000001, POLICY_FLAG_WAKE_DROPPED = 0x00000002, @@ -83,6 +84,7 @@ enum { POLICY_FLAG_ALT_GR = 0x00000020, POLICY_FLAG_MENU = 0x00000040, POLICY_FLAG_LAUNCHER = 0x00000080, + POLICY_FLAG_VIRTUAL = 0x00000100, POLICY_FLAG_RAW_MASK = 0x0000ffff, diff --git a/include/ui/InputReader.h b/include/ui/InputReader.h index e85735a717..3619189e10 100644 --- a/include/ui/InputReader.h +++ b/include/ui/InputReader.h @@ -103,10 +103,6 @@ public: virtual bool getDisplayInfo(int32_t displayId, int32_t* width, int32_t* height, int32_t* orientation) = 0; - /* Provides feedback for a virtual key down. - */ - virtual void virtualKeyDownFeedback() = 0; - /* Intercepts a key event. * The policy can use this method as an opportunity to perform power management functions * and early event preprocessing such as updating policy flags. @@ -283,14 +279,14 @@ private: // low-level input event decoding and device management void process(const RawEvent* rawEvent); - void addDevice(nsecs_t when, int32_t deviceId); - void removeDevice(nsecs_t when, int32_t deviceId); + void addDevice(int32_t deviceId); + void removeDevice(int32_t deviceId); InputDevice* createDevice(int32_t deviceId, const String8& name, uint32_t classes); void configureExcludedDevices(); void consumeEvent(const RawEvent* rawEvent); - void handleConfigurationChanged(nsecs_t when); + void handleConfigurationChanged(); // state management for all devices Mutex mStateLock; @@ -308,9 +304,6 @@ private: GetStateFunc getStateFunc); bool markSupportedKeyCodes(int32_t deviceId, uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags); - - // dump state - void dumpDeviceInfo(String8& dump); }; @@ -340,6 +333,7 @@ public: inline bool isIgnored() { return mMappers.isEmpty(); } + void dump(String8& dump); void addMapper(InputMapper* mapper); void configure(); void reset(); @@ -393,6 +387,7 @@ public: virtual uint32_t getSources() = 0; virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); + virtual void dump(String8& dump); virtual void configure(); virtual void reset(); virtual void process(const RawEvent* rawEvent) = 0; @@ -436,6 +431,7 @@ public: virtual uint32_t getSources(); virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); + virtual void dump(String8& dump); virtual void reset(); virtual void process(const RawEvent* rawEvent); @@ -484,6 +480,7 @@ public: virtual uint32_t getSources(); virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); + virtual void dump(String8& dump); virtual void reset(); virtual void process(const RawEvent* rawEvent); @@ -540,6 +537,7 @@ public: virtual uint32_t getSources(); virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); + virtual void dump(String8& dump); virtual void configure(); virtual void reset(); @@ -761,15 +759,16 @@ protected: } mLocked; virtual void configureParameters(); - virtual void logParameters(); + virtual void dumpParameters(String8& dump); virtual void configureRawAxes(); - virtual void logRawAxes(); + virtual void dumpRawAxes(String8& dump); virtual bool configureSurfaceLocked(); - virtual void logMotionRangesLocked(); + virtual void dumpSurfaceLocked(String8& dump); virtual void configureVirtualKeysLocked(); + virtual void dumpVirtualKeysLocked(String8& dump); virtual void parseCalibration(); virtual void resolveCalibration(); - virtual void logCalibration(); + virtual void dumpCalibration(String8& dump); enum TouchResult { // Dispatch the touch normally. diff --git a/include/ui/KeycodeLabels.h b/include/ui/KeycodeLabels.h index c8d6ffcbf8..f71d9cdf4d 100755 --- a/include/ui/KeycodeLabels.h +++ b/include/ui/KeycodeLabels.h @@ -142,6 +142,7 @@ static const KeycodeLabel KEYCODES[] = { { NULL, 0 } }; +// See also policy flags in Input.h. static const KeycodeLabel FLAGS[] = { { "WAKE", 0x00000001 }, { "WAKE_DROPPED", 0x00000002 }, @@ -151,6 +152,7 @@ static const KeycodeLabel FLAGS[] = { { "ALT_GR", 0x00000020 }, { "MENU", 0x00000040 }, { "LAUNCHER", 0x00000080 }, + { "VIRTUAL", 0x00000100 }, { NULL, 0 } }; diff --git a/include/ui/egl/android_natives.h b/include/ui/egl/android_natives.h index d59d72b7e5..654d0f31ce 100644 --- a/include/ui/egl/android_natives.h +++ b/include/ui/egl/android_natives.h @@ -218,7 +218,17 @@ struct ANativeWindow int (*perform)(struct ANativeWindow* window, int operation, ... ); - void* reserved_proc[3]; + /* + * hook used to cancel a buffer that has been dequeued. + * No synchronization is performed between dequeue() and cancel(), so + * either external synchronization is needed, or these functions must be + * called from the same thread. + */ + int (*cancelBuffer)(struct ANativeWindow* window, + struct android_native_buffer_t* buffer); + + + void* reserved_proc[2]; }; // Backwards compatibility... please switch to ANativeWindow. diff --git a/include/utils/ZipFileRO.h b/include/utils/ZipFileRO.h index 9668bdeef5..3c1f3caf2e 100644 --- a/include/utils/ZipFileRO.h +++ b/include/utils/ZipFileRO.h @@ -14,13 +14,19 @@ * limitations under the License. */ -// -// Read-only access to Zip archives, with minimal heap allocation. -// -// This is similar to the more-complete ZipFile class, but no attempt -// has been made to make them interchangeable. This class operates under -// a very different set of assumptions and constraints. -// +/* + * Read-only access to Zip archives, with minimal heap allocation. + * + * This is similar to the more-complete ZipFile class, but no attempt + * has been made to make them interchangeable. This class operates under + * a very different set of assumptions and constraints. + * + * One such assumption is that if you're getting file descriptors for + * use with this class as a child of a fork() operation, you must be on + * a pread() to guarantee correct operation. This is because pread() can + * atomically read at a file offset without worrying about a lock around an + * lseek() + read() pair. + */ #ifndef __LIBS_ZIPFILERO_H #define __LIBS_ZIPFILERO_H @@ -55,6 +61,10 @@ typedef void* ZipEntryRO; * the record structure. However, this requires a private mapping of * every page that the Central Directory touches. Easier to tuck a copy * of the string length into the hash table entry. + * + * NOTE: If this is used on file descriptors inherited from a fork() operation, + * you must be on a platform that implements pread() to guarantee correctness + * on the shared file descriptors. */ class ZipFileRO { public: @@ -64,15 +74,8 @@ public: mNumEntries(-1), mDirectoryOffset(-1), mHashTableSize(-1), mHashTable(NULL) {} - ~ZipFileRO() { - free(mHashTable); - if (mDirectoryMap) - mDirectoryMap->release(); - if (mFd >= 0) - close(mFd); - if (mFileName) - free(mFileName); - } + + ~ZipFileRO(); /* * Open an archive. diff --git a/libs/surfaceflinger_client/ISurfaceComposer.cpp b/libs/surfaceflinger_client/ISurfaceComposer.cpp index 040060ef2c..d676f5e90f 100644 --- a/libs/surfaceflinger_client/ISurfaceComposer.cpp +++ b/libs/surfaceflinger_client/ISurfaceComposer.cpp @@ -126,11 +126,14 @@ public: virtual status_t captureScreen(DisplayID dpy, sp<IMemoryHeap>* heap, - uint32_t* width, uint32_t* height, PixelFormat* format) + uint32_t* width, uint32_t* height, PixelFormat* format, + uint32_t reqWidth, uint32_t reqHeight) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeInt32(dpy); + data.writeInt32(reqWidth); + data.writeInt32(reqHeight); remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply); *heap = interface_cast<IMemoryHeap>(reply.readStrongBinder()); *width = reply.readInt32(); @@ -208,10 +211,13 @@ status_t BnSurfaceComposer::onTransact( case CAPTURE_SCREEN: { CHECK_INTERFACE(ISurfaceComposer, data, reply); DisplayID dpy = data.readInt32(); + uint32_t reqWidth = data.readInt32(); + uint32_t reqHeight = data.readInt32(); sp<IMemoryHeap> heap; uint32_t w, h; PixelFormat f; - status_t res = captureScreen(dpy, &heap, &w, &h, &f); + status_t res = captureScreen(dpy, &heap, &w, &h, &f, + reqWidth, reqHeight); reply->writeStrongBinder(heap->asBinder()); reply->writeInt32(w); reply->writeInt32(h); diff --git a/libs/surfaceflinger_client/SharedBufferStack.cpp b/libs/surfaceflinger_client/SharedBufferStack.cpp index 38b2faec8f..4bc5d9ec2e 100644 --- a/libs/surfaceflinger_client/SharedBufferStack.cpp +++ b/libs/surfaceflinger_client/SharedBufferStack.cpp @@ -285,10 +285,12 @@ ssize_t SharedBufferClient::DequeueUpdate::operator()() { return NO_ERROR; } -SharedBufferClient::UndoDequeueUpdate::UndoDequeueUpdate(SharedBufferBase* sbb) - : UpdateBase(sbb) { +SharedBufferClient::CancelUpdate::CancelUpdate(SharedBufferBase* sbb, + int tail, int buf) + : UpdateBase(sbb), tail(tail), buf(buf) { } -ssize_t SharedBufferClient::UndoDequeueUpdate::operator()() { +ssize_t SharedBufferClient::CancelUpdate::operator()() { + stack.index[tail] = buf; android_atomic_inc(&stack.available); return NO_ERROR; } @@ -319,7 +321,7 @@ ssize_t SharedBufferServer::RetireUpdate::operator()() { return BAD_VALUE; // Preventively lock the current buffer before updating queued. - android_atomic_write(stack.index[head], &stack.inUse); + android_atomic_write(stack.headBuf, &stack.inUse); // Decrement the number of queued buffers int32_t queued; @@ -334,7 +336,9 @@ ssize_t SharedBufferServer::RetireUpdate::operator()() { // the buffer we preventively locked upon entering this function head = (head + 1) % numBuffers; - android_atomic_write(stack.index[head], &stack.inUse); + const int8_t headBuf = stack.index[head]; + stack.headBuf = headBuf; + android_atomic_write(headBuf, &stack.inUse); // head is only modified here, so we don't need to use cmpxchg android_atomic_write(head, &stack.head); @@ -359,7 +363,7 @@ ssize_t SharedBufferServer::StatusUpdate::operator()() { SharedBufferClient::SharedBufferClient(SharedClient* sharedClient, int surface, int num, int32_t identity) : SharedBufferBase(sharedClient, surface, identity), - mNumBuffers(num), tail(0), undoDequeueTail(0) + mNumBuffers(num), tail(0) { SharedBufferStack& stack( *mSharedStack ); tail = computeTail(); @@ -395,7 +399,6 @@ ssize_t SharedBufferClient::dequeue() DequeueUpdate update(this); updateCondition( update ); - undoDequeueTail = tail; int dequeued = stack.index[tail]; tail = ((tail+1 >= mNumBuffers) ? 0 : tail+1); LOGD_IF(DEBUG_ATOMICS, "dequeued=%d, tail++=%d, %s", @@ -408,14 +411,19 @@ ssize_t SharedBufferClient::dequeue() status_t SharedBufferClient::undoDequeue(int buf) { + return cancel(buf); +} + +status_t SharedBufferClient::cancel(int buf) +{ RWLock::AutoRLock _rd(mLock); - // TODO: we can only undo the previous dequeue, we should - // enforce that in the api - UndoDequeueUpdate update(this); + // calculate the new position of the tail index (essentially tail--) + int localTail = (tail + mNumBuffers - 1) % mNumBuffers; + CancelUpdate update(this, localTail, buf); status_t err = updateCondition( update ); if (err == NO_ERROR) { - tail = undoDequeueTail; + tail = localTail; } return err; } diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp index 560ea67de2..d44aab994b 100644 --- a/libs/surfaceflinger_client/Surface.cpp +++ b/libs/surfaceflinger_client/Surface.cpp @@ -409,6 +409,7 @@ void Surface::init() { ANativeWindow::setSwapInterval = setSwapInterval; ANativeWindow::dequeueBuffer = dequeueBuffer; + ANativeWindow::cancelBuffer = cancelBuffer; ANativeWindow::lockBuffer = lockBuffer; ANativeWindow::queueBuffer = queueBuffer; ANativeWindow::query = query; @@ -517,6 +518,12 @@ int Surface::dequeueBuffer(ANativeWindow* window, return self->dequeueBuffer(buffer); } +int Surface::cancelBuffer(ANativeWindow* window, + android_native_buffer_t* buffer) { + Surface* self = getSelf(window); + return self->cancelBuffer(buffer); +} + int Surface::lockBuffer(ANativeWindow* window, android_native_buffer_t* buffer) { Surface* self = getSelf(window); @@ -617,6 +624,33 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer) return err; } +int Surface::cancelBuffer(android_native_buffer_t* buffer) +{ + status_t err = validate(); + switch (err) { + case NO_ERROR: + // no error, common case + break; + case INVALID_OPERATION: + // legitimate errors here + return err; + default: + // other errors happen because the surface is now invalid, + // for instance because it has been destroyed. In this case, + // we just fail silently (canceling a buffer is not technically + // an error at this point) + return NO_ERROR; + } + + int32_t bufIdx = getBufferIndex(GraphicBuffer::getSelf(buffer)); + + err = mSharedBufferClient->cancel(bufIdx); + + LOGE_IF(err, "error canceling buffer %d (%s)", bufIdx, strerror(-err)); + return err; +} + + int Surface::lockBuffer(android_native_buffer_t* buffer) { status_t err = validate(); diff --git a/libs/surfaceflinger_client/SurfaceComposerClient.cpp b/libs/surfaceflinger_client/SurfaceComposerClient.cpp index 4096ac6854..f270461607 100644 --- a/libs/surfaceflinger_client/SurfaceComposerClient.cpp +++ b/libs/surfaceflinger_client/SurfaceComposerClient.cpp @@ -545,5 +545,55 @@ status_t SurfaceComposerClient::setFreezeTint(SurfaceID id, uint32_t tint) } // ---------------------------------------------------------------------------- + +ScreenshotClient::ScreenshotClient() + : mWidth(0), mHeight(0), mFormat(PIXEL_FORMAT_NONE) { +} + +status_t ScreenshotClient::update() { + sp<ISurfaceComposer> s(ComposerService::getComposerService()); + if (s == NULL) return NO_INIT; + mHeap = 0; + return s->captureScreen(0, &mHeap, + &mWidth, &mHeight, &mFormat, 0, 0); +} + +status_t ScreenshotClient::update(uint32_t reqWidth, uint32_t reqHeight) { + sp<ISurfaceComposer> s(ComposerService::getComposerService()); + if (s == NULL) return NO_INIT; + mHeap = 0; + return s->captureScreen(0, &mHeap, + &mWidth, &mHeight, &mFormat, reqWidth, reqHeight); +} + +void ScreenshotClient::release() { + mHeap = 0; +} + +void const* ScreenshotClient::getPixels() const { + return mHeap->getBase(); +} + +uint32_t ScreenshotClient::getWidth() const { + return mWidth; +} + +uint32_t ScreenshotClient::getHeight() const { + return mHeight; +} + +PixelFormat ScreenshotClient::getFormat() const { + return mFormat; +} + +uint32_t ScreenshotClient::getStride() const { + return mWidth; +} + +size_t ScreenshotClient::getSize() const { + return mHeap->getSize(); +} + +// ---------------------------------------------------------------------------- }; // namespace android diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp index 1d38b4ba8f..c0be3a022c 100644 --- a/libs/ui/EventHub.cpp +++ b/libs/ui/EventHub.cpp @@ -73,6 +73,10 @@ #define ABS_MT_POSITION_Y 0x36 /* Center Y ellipse position */ #endif +#define INDENT " " +#define INDENT2 " " +#define INDENT3 " " + namespace android { static const char *WAKE_LOCK_ID = "KeyEvents"; @@ -84,6 +88,10 @@ static inline int max(int v1, int v2) return (v1 > v2) ? v1 : v2; } +static inline const char* toString(bool value) { + return value ? "true" : "false"; +} + EventHub::device_t::device_t(int32_t _id, const char* _path, const char* name) : id(_id), path(_path), name(name), classes(0) , keyBitmask(NULL), layoutMap(new KeyLayoutMap()), fd(-1), next(NULL) { @@ -98,7 +106,7 @@ EventHub::EventHub(void) : mError(NO_INIT), mHaveFirstKeyboard(false), mFirstKeyboardId(0) , mDevicesById(0), mNumDevicesById(0) , mOpeningDevices(0), mClosingDevices(0) - , mDevices(0), mFDs(0), mFDCount(0), mOpened(false) + , mDevices(0), mFDs(0), mFDCount(0), mOpened(false), mNeedToSendFinishedDeviceScan(false) , mInputBufferIndex(0), mInputBufferCount(0), mInputDeviceIndex(0) { acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID); @@ -124,7 +132,7 @@ status_t EventHub::errorCheck() const String8 EventHub::getDeviceName(int32_t deviceId) const { AutoMutex _l(mLock); - device_t* device = getDevice(deviceId); + device_t* device = getDeviceLocked(deviceId); if (device == NULL) return String8(); return device->name; } @@ -132,7 +140,7 @@ String8 EventHub::getDeviceName(int32_t deviceId) const uint32_t EventHub::getDeviceClasses(int32_t deviceId) const { AutoMutex _l(mLock); - device_t* device = getDevice(deviceId); + device_t* device = getDeviceLocked(deviceId); if (device == NULL) return 0; return device->classes; } @@ -142,7 +150,7 @@ status_t EventHub::getAbsoluteAxisInfo(int32_t deviceId, int axis, outAxisInfo->clear(); AutoMutex _l(mLock); - device_t* device = getDevice(deviceId); + device_t* device = getDeviceLocked(deviceId); if (device == NULL) return -1; struct input_absinfo info; @@ -167,7 +175,7 @@ int32_t EventHub::getScanCodeState(int32_t deviceId, int32_t scanCode) const { if (scanCode >= 0 && scanCode <= KEY_MAX) { AutoMutex _l(mLock); - device_t* device = getDevice(deviceId); + device_t* device = getDeviceLocked(deviceId); if (device != NULL) { return getScanCodeStateLocked(device, scanCode); } @@ -188,7 +196,7 @@ int32_t EventHub::getScanCodeStateLocked(device_t* device, int32_t scanCode) con int32_t EventHub::getKeyCodeState(int32_t deviceId, int32_t keyCode) const { AutoMutex _l(mLock); - device_t* device = getDevice(deviceId); + device_t* device = getDeviceLocked(deviceId); if (device != NULL) { return getKeyCodeStateLocked(device, keyCode); } @@ -225,7 +233,7 @@ int32_t EventHub::getSwitchState(int32_t deviceId, int32_t sw) const { if (sw >= 0 && sw <= SW_MAX) { AutoMutex _l(mLock); - device_t* device = getDevice(deviceId); + device_t* device = getDeviceLocked(deviceId); if (device != NULL) { return getSwitchStateLocked(device, sw); } @@ -248,7 +256,7 @@ bool EventHub::markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const { AutoMutex _l(mLock); - device_t* device = getDevice(deviceId); + device_t* device = getDeviceLocked(deviceId); if (device != NULL) { return markSupportedKeyCodesLocked(device, numCodes, keyCodes, outFlags); } @@ -284,7 +292,7 @@ status_t EventHub::scancodeToKeycode(int32_t deviceId, int scancode, int32_t* outKeycode, uint32_t* outFlags) const { AutoMutex _l(mLock); - device_t* device = getDevice(deviceId); + device_t* device = getDeviceLocked(deviceId); if (device != NULL && device->layoutMap != NULL) { status_t err = device->layoutMap->map(scancode, outKeycode, outFlags); @@ -294,7 +302,7 @@ status_t EventHub::scancodeToKeycode(int32_t deviceId, int scancode, } if (mHaveFirstKeyboard) { - device = getDevice(mFirstKeyboardId); + device = getDeviceLocked(mFirstKeyboardId); if (device != NULL && device->layoutMap != NULL) { status_t err = device->layoutMap->map(scancode, outKeycode, outFlags); @@ -311,11 +319,13 @@ status_t EventHub::scancodeToKeycode(int32_t deviceId, int scancode, void EventHub::addExcludedDevice(const char* deviceName) { + AutoMutex _l(mLock); + String8 name(deviceName); mExcludedDevices.push_back(name); } -EventHub::device_t* EventHub::getDevice(int32_t deviceId) const +EventHub::device_t* EventHub::getDeviceLocked(int32_t deviceId) const { if (deviceId == 0) deviceId = mFirstKeyboardId; int32_t id = deviceId & ID_MASK; @@ -344,6 +354,7 @@ bool EventHub::getEvent(RawEvent* outEvent) if (!mOpened) { mError = openPlatformInput() ? NO_ERROR : UNKNOWN_ERROR; mOpened = true; + mNeedToSendFinishedDeviceScan = true; } for (;;) { @@ -360,6 +371,7 @@ bool EventHub::getEvent(RawEvent* outEvent) } outEvent->type = DEVICE_REMOVED; delete device; + mNeedToSendFinishedDeviceScan = true; return true; } @@ -374,6 +386,13 @@ bool EventHub::getEvent(RawEvent* outEvent) outEvent->deviceId = device->id; } outEvent->type = DEVICE_ADDED; + mNeedToSendFinishedDeviceScan = true; + return true; + } + + if (mNeedToSendFinishedDeviceScan) { + mNeedToSendFinishedDeviceScan = false; + outEvent->type = FINISHED_DEVICE_SCAN; return true; } @@ -441,10 +460,10 @@ bool EventHub::getEvent(RawEvent* outEvent) } } - // read_notify() will modify mFDs and mFDCount, so this must be done after + // readNotify() will modify mFDs and mFDCount, so this must be done after // processing all other events. if(mFDs[0].revents & POLLIN) { - read_notify(mFDs[0].fd); + readNotify(mFDs[0].fd); } // Poll for events. Mind the wake lock dance! @@ -500,10 +519,9 @@ bool EventHub::openPlatformInput(void) mFDs[0].fd = -1; #endif - res = scan_dir(device_path); + res = scanDir(device_path); if(res < 0) { LOGE("scan dir failed for %s\n", device_path); - //open_device("/dev/input/event0"); } return true; @@ -531,8 +549,7 @@ static const int32_t GAMEPAD_KEYCODES[] = { AKEYCODE_BUTTON_START, AKEYCODE_BUTTON_SELECT, AKEYCODE_BUTTON_MODE }; -int EventHub::open_device(const char *deviceName) -{ +int EventHub::openDevice(const char *deviceName) { int version; int fd; struct pollfd *new_mFDs; @@ -782,22 +799,22 @@ int EventHub::open_device(const char *deviceName) property_set(propName, name); // 'Q' key support = cheap test of whether this is an alpha-capable kbd - if (hasKeycode(device, AKEYCODE_Q)) { + if (hasKeycodeLocked(device, AKEYCODE_Q)) { device->classes |= INPUT_DEVICE_CLASS_ALPHAKEY; } // See if this device has a DPAD. - if (hasKeycode(device, AKEYCODE_DPAD_UP) && - hasKeycode(device, AKEYCODE_DPAD_DOWN) && - hasKeycode(device, AKEYCODE_DPAD_LEFT) && - hasKeycode(device, AKEYCODE_DPAD_RIGHT) && - hasKeycode(device, AKEYCODE_DPAD_CENTER)) { + if (hasKeycodeLocked(device, AKEYCODE_DPAD_UP) && + hasKeycodeLocked(device, AKEYCODE_DPAD_DOWN) && + hasKeycodeLocked(device, AKEYCODE_DPAD_LEFT) && + hasKeycodeLocked(device, AKEYCODE_DPAD_RIGHT) && + hasKeycodeLocked(device, AKEYCODE_DPAD_CENTER)) { device->classes |= INPUT_DEVICE_CLASS_DPAD; } // See if this device has a gamepad. for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES); i++) { - if (hasKeycode(device, GAMEPAD_KEYCODES[i])) { + if (hasKeycodeLocked(device, GAMEPAD_KEYCODES[i])) { device->classes |= INPUT_DEVICE_CLASS_GAMEPAD; break; } @@ -830,7 +847,7 @@ int EventHub::open_device(const char *deviceName) return 0; } -bool EventHub::hasKeycode(device_t* device, int keycode) const +bool EventHub::hasKeycodeLocked(device_t* device, int keycode) const { if (device->keyBitmask == NULL || device->layoutMap == NULL) { return false; @@ -849,10 +866,9 @@ bool EventHub::hasKeycode(device_t* device, int keycode) const return false; } -int EventHub::close_device(const char *deviceName) -{ +int EventHub::closeDevice(const char *deviceName) { AutoMutex _l(mLock); - + int i; for(i = 1; i < mFDCount; i++) { if(strcmp(mDevices[i]->path.string(), deviceName) == 0) { @@ -902,8 +918,7 @@ int EventHub::close_device(const char *deviceName) return -1; } -int EventHub::read_notify(int nfd) -{ +int EventHub::readNotify(int nfd) { #ifdef HAVE_INOTIFY int res; char devname[PATH_MAX]; @@ -913,7 +928,7 @@ int EventHub::read_notify(int nfd) int event_pos = 0; struct inotify_event *event; - LOGV("EventHub::read_notify nfd: %d\n", nfd); + LOGV("EventHub::readNotify nfd: %d\n", nfd); res = read(nfd, event_buf, sizeof(event_buf)); if(res < (int)sizeof(*event)) { if(errno == EINTR) @@ -933,10 +948,10 @@ int EventHub::read_notify(int nfd) if(event->len) { strcpy(filename, event->name); if(event->mask & IN_CREATE) { - open_device(devname); + openDevice(devname); } else { - close_device(devname); + closeDevice(devname); } } event_size = sizeof(*event) + event->len; @@ -948,7 +963,7 @@ int EventHub::read_notify(int nfd) } -int EventHub::scan_dir(const char *dirname) +int EventHub::scanDir(const char *dirname) { char devname[PATH_MAX]; char *filename; @@ -966,10 +981,38 @@ int EventHub::scan_dir(const char *dirname) (de->d_name[1] == '.' && de->d_name[2] == '\0'))) continue; strcpy(filename, de->d_name); - open_device(devname); + openDevice(devname); } closedir(dir); return 0; } +void EventHub::dump(String8& dump) { + dump.append("Event Hub State:\n"); + + { // acquire lock + AutoMutex _l(mLock); + + dump.appendFormat(INDENT "HaveFirstKeyboard: %s\n", toString(mHaveFirstKeyboard)); + dump.appendFormat(INDENT "FirstKeyboardId: 0x%x\n", mFirstKeyboardId); + + dump.append(INDENT "Devices:\n"); + + for (int i = 0; i < mNumDevicesById; i++) { + const device_t* device = mDevicesById[i].device; + if (device) { + if (mFirstKeyboardId == device->id) { + dump.appendFormat(INDENT2 "0x%x: %s (aka device 0 - first keyboard)\n", + device->id, device->name.string()); + } else { + dump.appendFormat(INDENT2 "0x%x: %s\n", device->id, device->name.string()); + } + dump.appendFormat(INDENT3 "Classes: 0x%08x\n", device->classes); + dump.appendFormat(INDENT3 "Path: %s\n", device->path.string()); + dump.appendFormat(INDENT3 "KeyLayoutFile: %s\n", device->keylayoutFilename.string()); + } + } + } // release lock +} + }; // namespace android diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp index 9544a95fbb..aa54f82e91 100644 --- a/libs/ui/InputDispatcher.cpp +++ b/libs/ui/InputDispatcher.cpp @@ -46,6 +46,9 @@ #include <errno.h> #include <limits.h> +#define INDENT " " +#define INDENT2 " " + namespace android { // Delay between reporting long touch events to the power manager. @@ -2490,74 +2493,96 @@ void InputDispatcher::logDispatchStateLocked() { } void InputDispatcher::dumpDispatchStateLocked(String8& dump) { - dump.appendFormat(" dispatchEnabled: %d\n", mDispatchEnabled); - dump.appendFormat(" dispatchFrozen: %d\n", mDispatchFrozen); + dump.appendFormat(INDENT "DispatchEnabled: %d\n", mDispatchEnabled); + dump.appendFormat(INDENT "DispatchFrozen: %d\n", mDispatchFrozen); if (mFocusedApplication) { - dump.appendFormat(" focusedApplication: name='%s', dispatchingTimeout=%0.3fms\n", + dump.appendFormat(INDENT "FocusedApplication: name='%s', dispatchingTimeout=%0.3fms\n", mFocusedApplication->name.string(), mFocusedApplication->dispatchingTimeout / 1000000.0); } else { - dump.append(" focusedApplication: <null>\n"); + dump.append(INDENT "FocusedApplication: <null>\n"); } - dump.appendFormat(" focusedWindow: name='%s'\n", + dump.appendFormat(INDENT "FocusedWindow: name='%s'\n", mFocusedWindow != NULL ? mFocusedWindow->name.string() : "<null>"); - dump.appendFormat(" touchState: down=%s, split=%s\n", toString(mTouchState.down), - toString(mTouchState.split)); - for (size_t i = 0; i < mTouchState.windows.size(); i++) { - const TouchedWindow& touchedWindow = mTouchState.windows[i]; - dump.appendFormat(" touchedWindow[%d]: name='%s', pointerIds=0x%0x, targetFlags=0x%x\n", - i, touchedWindow.window->name.string(), touchedWindow.pointerIds.value, - touchedWindow.targetFlags); - } - for (size_t i = 0; i < mWindows.size(); i++) { - dump.appendFormat(" windows[%d]: name='%s', paused=%s, hasFocus=%s, hasWallpaper=%s, " - "visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, " - "frame=[%d,%d][%d,%d], " - "visibleFrame=[%d,%d][%d,%d], " - "touchableArea=[%d,%d][%d,%d], " - "ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n", - i, mWindows[i].name.string(), - toString(mWindows[i].paused), - toString(mWindows[i].hasFocus), - toString(mWindows[i].hasWallpaper), - toString(mWindows[i].visible), - toString(mWindows[i].canReceiveKeys), - mWindows[i].layoutParamsFlags, mWindows[i].layoutParamsType, - mWindows[i].layer, - mWindows[i].frameLeft, mWindows[i].frameTop, - mWindows[i].frameRight, mWindows[i].frameBottom, - mWindows[i].visibleFrameLeft, mWindows[i].visibleFrameTop, - mWindows[i].visibleFrameRight, mWindows[i].visibleFrameBottom, - mWindows[i].touchableAreaLeft, mWindows[i].touchableAreaTop, - mWindows[i].touchableAreaRight, mWindows[i].touchableAreaBottom, - mWindows[i].ownerPid, mWindows[i].ownerUid, - mWindows[i].dispatchingTimeout / 1000000.0); + + dump.appendFormat(INDENT "TouchDown: %s\n", toString(mTouchState.down)); + dump.appendFormat(INDENT "TouchSplit: %s\n", toString(mTouchState.split)); + if (!mTouchState.windows.isEmpty()) { + dump.append(INDENT "TouchedWindows:\n"); + for (size_t i = 0; i < mTouchState.windows.size(); i++) { + const TouchedWindow& touchedWindow = mTouchState.windows[i]; + dump.appendFormat(INDENT2 "%d: name='%s', pointerIds=0x%0x, targetFlags=0x%x\n", + i, touchedWindow.window->name.string(), touchedWindow.pointerIds.value, + touchedWindow.targetFlags); + } + } else { + dump.append(INDENT "TouchedWindows: <none>\n"); + } + + if (!mWindows.isEmpty()) { + dump.append(INDENT "Windows:\n"); + for (size_t i = 0; i < mWindows.size(); i++) { + const InputWindow& window = mWindows[i]; + dump.appendFormat(INDENT2 "%d: name='%s', paused=%s, hasFocus=%s, hasWallpaper=%s, " + "visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, " + "frame=[%d,%d][%d,%d], " + "visibleFrame=[%d,%d][%d,%d], " + "touchableArea=[%d,%d][%d,%d], " + "ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n", + i, window.name.string(), + toString(window.paused), + toString(window.hasFocus), + toString(window.hasWallpaper), + toString(window.visible), + toString(window.canReceiveKeys), + window.layoutParamsFlags, window.layoutParamsType, + window.layer, + window.frameLeft, window.frameTop, + window.frameRight, window.frameBottom, + window.visibleFrameLeft, window.visibleFrameTop, + window.visibleFrameRight, window.visibleFrameBottom, + window.touchableAreaLeft, window.touchableAreaTop, + window.touchableAreaRight, window.touchableAreaBottom, + window.ownerPid, window.ownerUid, + window.dispatchingTimeout / 1000000.0); + } + } else { + dump.append(INDENT "Windows: <none>\n"); } - for (size_t i = 0; i < mMonitoringChannels.size(); i++) { - const sp<InputChannel>& channel = mMonitoringChannels[i]; - dump.appendFormat(" monitoringChannel[%d]: '%s'\n", - i, channel->getName().string()); + if (!mMonitoringChannels.isEmpty()) { + dump.append(INDENT "MonitoringChannels:\n"); + for (size_t i = 0; i < mMonitoringChannels.size(); i++) { + const sp<InputChannel>& channel = mMonitoringChannels[i]; + dump.appendFormat(INDENT2 "%d: '%s'\n", i, channel->getName().string()); + } + } else { + dump.append(INDENT "MonitoringChannels: <none>\n"); } - dump.appendFormat(" inboundQueue: length=%u", mInboundQueue.count()); + dump.appendFormat(INDENT "InboundQueue: length=%u\n", mInboundQueue.count()); - for (size_t i = 0; i < mActiveConnections.size(); i++) { - const Connection* connection = mActiveConnections[i]; - dump.appendFormat(" activeConnection[%d]: '%s', status=%s, outboundQueueLength=%u" - "inputState.isNeutral=%s, inputState.isOutOfSync=%s\n", - i, connection->getInputChannelName(), connection->getStatusLabel(), - connection->outboundQueue.count(), - toString(connection->inputState.isNeutral()), - toString(connection->inputState.isOutOfSync())); + if (!mActiveConnections.isEmpty()) { + dump.append(INDENT "ActiveConnections:\n"); + for (size_t i = 0; i < mActiveConnections.size(); i++) { + const Connection* connection = mActiveConnections[i]; + dump.appendFormat(INDENT2 "%d: '%s', status=%s, outboundQueueLength=%u" + "inputState.isNeutral=%s, inputState.isOutOfSync=%s\n", + i, connection->getInputChannelName(), connection->getStatusLabel(), + connection->outboundQueue.count(), + toString(connection->inputState.isNeutral()), + toString(connection->inputState.isOutOfSync())); + } + } else { + dump.append(INDENT "ActiveConnections: <none>\n"); } if (isAppSwitchPendingLocked()) { - dump.appendFormat(" appSwitch: pending, due in %01.1fms\n", + dump.appendFormat(INDENT "AppSwitch: pending, due in %01.1fms\n", (mAppSwitchDueTime - now()) / 1000000.0); } else { - dump.append(" appSwitch: not pending\n"); + dump.append(INDENT "AppSwitch: not pending\n"); } } @@ -2774,6 +2799,7 @@ void InputDispatcher::updateDispatchStatisticsLocked(nsecs_t currentTime, const } void InputDispatcher::dump(String8& dump) { + dump.append("Input Dispatcher State:\n"); dumpDispatchStateLocked(dump); } diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp index f2b029a5e1..8e173aa6b0 100644 --- a/libs/ui/InputReader.cpp +++ b/libs/ui/InputReader.cpp @@ -33,6 +33,9 @@ #include <math.h> #define INDENT " " +#define INDENT2 " " +#define INDENT3 " " +#define INDENT4 " " namespace android { @@ -63,6 +66,10 @@ inline static float pythag(float x, float y) { return sqrtf(x * x + y * y); } +static inline const char* toString(bool value) { + return value ? "true" : "false"; +} + int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState) { int32_t mask; @@ -219,11 +226,15 @@ void InputReader::loopOnce() { void InputReader::process(const RawEvent* rawEvent) { switch (rawEvent->type) { case EventHubInterface::DEVICE_ADDED: - addDevice(rawEvent->when, rawEvent->deviceId); + addDevice(rawEvent->deviceId); break; case EventHubInterface::DEVICE_REMOVED: - removeDevice(rawEvent->when, rawEvent->deviceId); + removeDevice(rawEvent->deviceId); + break; + + case EventHubInterface::FINISHED_DEVICE_SCAN: + handleConfigurationChanged(); break; default: @@ -232,20 +243,18 @@ void InputReader::process(const RawEvent* rawEvent) { } } -void InputReader::addDevice(nsecs_t when, int32_t deviceId) { +void InputReader::addDevice(int32_t deviceId) { String8 name = mEventHub->getDeviceName(deviceId); uint32_t classes = mEventHub->getDeviceClasses(deviceId); - // Write a log message about the added device as a heading for subsequent log messages. - LOGI("Device added: id=0x%x, name=%s", deviceId, name.string()); - InputDevice* device = createDevice(deviceId, name, classes); device->configure(); if (device->isIgnored()) { - LOGI(INDENT "Sources: none (device is ignored)"); + LOGI("Device added: id=0x%x, name=%s (ignored non-input device)", deviceId, name.string()); } else { - LOGI(INDENT "Sources: 0x%08x", device->getSources()); + LOGI("Device added: id=0x%x, name=%s, sources=%08x", deviceId, name.string(), + device->getSources()); } bool added = false; @@ -264,11 +273,9 @@ void InputReader::addDevice(nsecs_t when, int32_t deviceId) { delete device; return; } - - handleConfigurationChanged(when); } -void InputReader::removeDevice(nsecs_t when, int32_t deviceId) { +void InputReader::removeDevice(int32_t deviceId) { bool removed = false; InputDevice* device = NULL; { // acquire device registry writer lock @@ -287,7 +294,6 @@ void InputReader::removeDevice(nsecs_t when, int32_t deviceId) { return; } - // Write a log message about the removed device as a heading for subsequent log messages. if (device->isIgnored()) { LOGI("Device removed: id=0x%x, name=%s (ignored non-input device)", device->getId(), device->getName().string()); @@ -299,8 +305,6 @@ void InputReader::removeDevice(nsecs_t when, int32_t deviceId) { device->reset(); delete device; - - handleConfigurationChanged(when); } InputDevice* InputReader::createDevice(int32_t deviceId, const String8& name, uint32_t classes) { @@ -368,7 +372,7 @@ void InputReader::consumeEvent(const RawEvent* rawEvent) { } // release device registry reader lock } -void InputReader::handleConfigurationChanged(nsecs_t when) { +void InputReader::handleConfigurationChanged() { // Reset global meta state because it depends on the list of all configured devices. updateGlobalMetaState(); @@ -376,6 +380,7 @@ void InputReader::handleConfigurationChanged(nsecs_t when) { updateInputConfiguration(); // Enqueue configuration changed. + nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC); mDispatcher->notifyConfigurationChanged(when); } @@ -571,59 +576,20 @@ bool InputReader::markSupportedKeyCodes(int32_t deviceId, uint32_t sourceMask, s } void InputReader::dump(String8& dump) { - dumpDeviceInfo(dump); -} - -static void dumpMotionRange(String8& dump, - const char* name, const InputDeviceInfo::MotionRange* range) { - if (range) { - dump.appendFormat(" %s = { min: %0.3f, max: %0.3f, flat: %0.3f, fuzz: %0.3f }\n", - name, range->min, range->max, range->flat, range->fuzz); - } -} + mEventHub->dump(dump); + dump.append("\n"); -#define DUMP_MOTION_RANGE(range) \ - dumpMotionRange(dump, #range, deviceInfo.getMotionRange(AINPUT_MOTION_RANGE_##range)); + dump.append("Input Reader State:\n"); -void InputReader::dumpDeviceInfo(String8& dump) { - Vector<int32_t> deviceIds; - getInputDeviceIds(deviceIds); - - InputDeviceInfo deviceInfo; - for (size_t i = 0; i < deviceIds.size(); i++) { - int32_t deviceId = deviceIds[i]; + { // acquire device registry reader lock + RWLock::AutoRLock _rl(mDeviceRegistryLock); - status_t result = getInputDeviceInfo(deviceId, & deviceInfo); - if (result == NAME_NOT_FOUND) { - continue; - } else if (result != OK) { - dump.appendFormat(" ** Unexpected error %d getting information about input devices.\n", - result); - continue; + for (size_t i = 0; i < mDevices.size(); i++) { + mDevices.valueAt(i)->dump(dump); } - - dump.appendFormat(" Device %d: '%s'\n", - deviceInfo.getId(), deviceInfo.getName().string()); - dump.appendFormat(" sources = 0x%08x\n", - deviceInfo.getSources()); - dump.appendFormat(" keyboardType = %d\n", - deviceInfo.getKeyboardType()); - - dump.append(" motion ranges:\n"); - DUMP_MOTION_RANGE(X); - DUMP_MOTION_RANGE(Y); - DUMP_MOTION_RANGE(PRESSURE); - DUMP_MOTION_RANGE(SIZE); - DUMP_MOTION_RANGE(TOUCH_MAJOR); - DUMP_MOTION_RANGE(TOUCH_MINOR); - DUMP_MOTION_RANGE(TOOL_MAJOR); - DUMP_MOTION_RANGE(TOOL_MINOR); - DUMP_MOTION_RANGE(ORIENTATION); - } + } // release device registy reader lock } -#undef DUMP_MOTION_RANGE - // --- InputReaderThread --- @@ -654,6 +620,43 @@ InputDevice::~InputDevice() { mMappers.clear(); } +static void dumpMotionRange(String8& dump, const InputDeviceInfo& deviceInfo, + int32_t rangeType, const char* name) { + const InputDeviceInfo::MotionRange* range = deviceInfo.getMotionRange(rangeType); + if (range) { + dump.appendFormat(INDENT3 "%s: min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f\n", + name, range->min, range->max, range->flat, range->fuzz); + } +} + +void InputDevice::dump(String8& dump) { + InputDeviceInfo deviceInfo; + getDeviceInfo(& deviceInfo); + + dump.appendFormat(INDENT "Device 0x%x: %s\n", deviceInfo.getId(), + deviceInfo.getName().string()); + dump.appendFormat(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources()); + dump.appendFormat(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType()); + if (!deviceInfo.getMotionRanges().isEmpty()) { + dump.append(INDENT2 "Motion Ranges:\n"); + dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_X, "X"); + dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_Y, "Y"); + dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_PRESSURE, "Pressure"); + dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_SIZE, "Size"); + dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_TOUCH_MAJOR, "TouchMajor"); + dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_TOUCH_MINOR, "TouchMinor"); + dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_TOOL_MAJOR, "ToolMajor"); + dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_TOOL_MINOR, "ToolMinor"); + dumpMotionRange(dump, deviceInfo, AINPUT_MOTION_RANGE_ORIENTATION, "Orientation"); + } + + size_t numMappers = mMappers.size(); + for (size_t i = 0; i < numMappers; i++) { + InputMapper* mapper = mMappers[i]; + mapper->dump(dump); + } +} + void InputDevice::addMapper(InputMapper* mapper) { mMappers.add(mapper); } @@ -763,6 +766,9 @@ void InputMapper::populateDeviceInfo(InputDeviceInfo* info) { info->addSource(getSources()); } +void InputMapper::dump(String8& dump) { +} + void InputMapper::configure() { } @@ -856,6 +862,18 @@ void KeyboardInputMapper::populateDeviceInfo(InputDeviceInfo* info) { info->setKeyboardType(mKeyboardType); } +void KeyboardInputMapper::dump(String8& dump) { + { // acquire lock + AutoMutex _l(mLock); + dump.append(INDENT2 "Keyboard Input Mapper:\n"); + dump.appendFormat(INDENT3 "AssociatedDisplayId: %d\n", mAssociatedDisplayId); + dump.appendFormat(INDENT3 "KeyboardType: %d\n", mKeyboardType); + dump.appendFormat(INDENT3 "KeyDowns: %d keys currently down\n", mLocked.keyDowns.size()); + dump.appendFormat(INDENT3 "MetaState: 0x%0x\n", mLocked.metaState); + dump.appendFormat(INDENT3 "DownTime: %lld\n", mLocked.downTime); + } // release lock +} + void KeyboardInputMapper::reset() { for (;;) { int32_t keyCode, scanCode; @@ -980,7 +998,10 @@ void KeyboardInputMapper::applyPolicyAndDispatch(nsecs_t when, uint32_t policyFl int32_t keyEventAction = down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP; int32_t keyEventFlags = AKEY_EVENT_FLAG_FROM_SYSTEM; if (policyFlags & POLICY_FLAG_WOKE_HERE) { - keyEventFlags = keyEventFlags | AKEY_EVENT_FLAG_WOKE_HERE; + keyEventFlags |= AKEY_EVENT_FLAG_WOKE_HERE; + } + if (policyFlags & POLICY_FLAG_VIRTUAL) { + keyEventFlags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY; } getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags, @@ -1044,6 +1065,18 @@ void TrackballInputMapper::populateDeviceInfo(InputDeviceInfo* info) { info->addMotionRange(AINPUT_MOTION_RANGE_Y, -1.0f, 1.0f, 0.0f, mYScale); } +void TrackballInputMapper::dump(String8& dump) { + { // acquire lock + AutoMutex _l(mLock); + dump.append(INDENT2 "Trackball Input Mapper:\n"); + dump.appendFormat(INDENT3 "AssociatedDisplayId: %d\n", mAssociatedDisplayId); + dump.appendFormat(INDENT3 "XPrecision: %0.3f\n", mXPrecision); + dump.appendFormat(INDENT3 "YPrecision: %0.3f\n", mYPrecision); + dump.appendFormat(INDENT3 "Down: %s\n", toString(mLocked.down)); + dump.appendFormat(INDENT3 "DownTime: %lld\n", mLocked.downTime); + } // release lock +} + void TrackballInputMapper::initializeLocked() { mAccumulator.clear(); @@ -1275,6 +1308,21 @@ void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) { } // release lock } +void TouchInputMapper::dump(String8& dump) { + { // acquire lock + AutoMutex _l(mLock); + dump.append(INDENT2 "Touch Input Mapper:\n"); + dump.appendFormat(INDENT3 "AssociatedDisplayId: %d\n", mAssociatedDisplayId); + dumpParameters(dump); + dumpVirtualKeysLocked(dump); + dumpRawAxes(dump); + dumpCalibration(dump); + dumpSurfaceLocked(dump); + dump.appendFormat(INDENT3 "XPrecision: %0.3f\n", mLocked.xPrecision); + dump.appendFormat(INDENT3 "YPrecision: %0.3f\n", mLocked.yPrecision); + } // release lock +} + void TouchInputMapper::initializeLocked() { mCurrentTouch.clear(); mLastTouch.clear(); @@ -1301,16 +1349,13 @@ void TouchInputMapper::configure() { // Configure basic parameters. configureParameters(); - logParameters(); // Configure absolute axis information. configureRawAxes(); - logRawAxes(); // Prepare input device calibration. parseCalibration(); resolveCalibration(); - logCalibration(); { // acquire lock AutoMutex _l(mLock); @@ -1326,16 +1371,13 @@ void TouchInputMapper::configureParameters() { mParameters.useJumpyTouchFilter = getPolicy()->filterJumpyTouchEvents(); } -void TouchInputMapper::logParameters() { - if (mParameters.useBadTouchFilter) { - LOGI(INDENT "Bad touch filter enabled."); - } - if (mParameters.useAveragingTouchFilter) { - LOGI(INDENT "Averaging touch filter enabled."); - } - if (mParameters.useJumpyTouchFilter) { - LOGI(INDENT "Jumpy touch filter enabled."); - } +void TouchInputMapper::dumpParameters(String8& dump) { + dump.appendFormat(INDENT3 "UseBadTouchFilter: %s\n", + toString(mParameters.useBadTouchFilter)); + dump.appendFormat(INDENT3 "UseAveragingTouchFilter: %s\n", + toString(mParameters.useAveragingTouchFilter)); + dump.appendFormat(INDENT3 "UseJumpyTouchFilter: %s\n", + toString(mParameters.useJumpyTouchFilter)); } void TouchInputMapper::configureRawAxes() { @@ -1349,24 +1391,25 @@ void TouchInputMapper::configureRawAxes() { mRawAxes.orientation.clear(); } -static void logAxisInfo(RawAbsoluteAxisInfo axis, const char* name) { +static void dumpAxisInfo(String8& dump, RawAbsoluteAxisInfo axis, const char* name) { if (axis.valid) { - LOGI(INDENT "Raw %s axis: min=%d, max=%d, flat=%d, fuzz=%d", + dump.appendFormat(INDENT4 "%s: min=%d, max=%d, flat=%d, fuzz=%d\n", name, axis.minValue, axis.maxValue, axis.flat, axis.fuzz); } else { - LOGI(INDENT "Raw %s axis: unknown range", name); + dump.appendFormat(INDENT4 "%s: unknown range\n", name); } } -void TouchInputMapper::logRawAxes() { - logAxisInfo(mRawAxes.x, "x"); - logAxisInfo(mRawAxes.y, "y"); - logAxisInfo(mRawAxes.pressure, "pressure"); - logAxisInfo(mRawAxes.touchMajor, "touchMajor"); - logAxisInfo(mRawAxes.touchMinor, "touchMinor"); - logAxisInfo(mRawAxes.toolMajor, "toolMajor"); - logAxisInfo(mRawAxes.toolMinor, "toolMinor"); - logAxisInfo(mRawAxes.orientation, "orientation"); +void TouchInputMapper::dumpRawAxes(String8& dump) { + dump.append(INDENT3 "Raw Axes:\n"); + dumpAxisInfo(dump, mRawAxes.x, "X"); + dumpAxisInfo(dump, mRawAxes.y, "Y"); + dumpAxisInfo(dump, mRawAxes.pressure, "Pressure"); + dumpAxisInfo(dump, mRawAxes.touchMajor, "TouchMajor"); + dumpAxisInfo(dump, mRawAxes.touchMinor, "TouchMinor"); + dumpAxisInfo(dump, mRawAxes.toolMajor, "ToolMajor"); + dumpAxisInfo(dump, mRawAxes.toolMinor, "ToolMinor"); + dumpAxisInfo(dump, mRawAxes.orientation, "Orientation"); } bool TouchInputMapper::configureSurfaceLocked() { @@ -1391,10 +1434,8 @@ bool TouchInputMapper::configureSurfaceLocked() { bool sizeChanged = mLocked.surfaceWidth != width || mLocked.surfaceHeight != height; if (sizeChanged) { - LOGI("Device reconfigured (display size changed): id=0x%x, name=%s", - getDeviceId(), getDeviceName().string()); - LOGI(INDENT "Width: %dpx", width); - LOGI(INDENT "Height: %dpx", height); + LOGI("Device reconfigured: id=0x%x, name=%s, display size is now %dx%d", + getDeviceId(), getDeviceName().string(), width, height); mLocked.surfaceWidth = width; mLocked.surfaceHeight = height; @@ -1562,39 +1603,13 @@ bool TouchInputMapper::configureSurfaceLocked() { mLocked.orientedRanges.y.fuzz = orientedYScale; } - if (sizeChanged) { - logMotionRangesLocked(); - } - return true; } -static void logMotionRangeInfo(InputDeviceInfo::MotionRange* range, const char* name) { - if (range) { - LOGI(INDENT "Output %s range: min=%f, max=%f, flat=%f, fuzz=%f", - name, range->min, range->max, range->flat, range->fuzz); - } else { - LOGI(INDENT "Output %s range: unsupported", name); - } -} - -void TouchInputMapper::logMotionRangesLocked() { - logMotionRangeInfo(& mLocked.orientedRanges.x, "x"); - logMotionRangeInfo(& mLocked.orientedRanges.y, "y"); - logMotionRangeInfo(mLocked.orientedRanges.havePressure - ? & mLocked.orientedRanges.pressure : NULL, "pressure"); - logMotionRangeInfo(mLocked.orientedRanges.haveSize - ? & mLocked.orientedRanges.size : NULL, "size"); - logMotionRangeInfo(mLocked.orientedRanges.haveTouchArea - ? & mLocked.orientedRanges.touchMajor : NULL, "touchMajor"); - logMotionRangeInfo(mLocked.orientedRanges.haveTouchArea - ? & mLocked.orientedRanges.touchMinor : NULL, "touchMinor"); - logMotionRangeInfo(mLocked.orientedRanges.haveToolArea - ? & mLocked.orientedRanges.toolMajor : NULL, "toolMajor"); - logMotionRangeInfo(mLocked.orientedRanges.haveToolArea - ? & mLocked.orientedRanges.toolMinor : NULL, "toolMinor"); - logMotionRangeInfo(mLocked.orientedRanges.haveOrientation - ? & mLocked.orientedRanges.orientation : NULL, "orientation"); +void TouchInputMapper::dumpSurfaceLocked(String8& dump) { + dump.appendFormat(INDENT3 "SurfaceWidth: %dpx\n", mLocked.surfaceWidth); + dump.appendFormat(INDENT3 "SurfaceHeight: %dpx\n", mLocked.surfaceHeight); + dump.appendFormat(INDENT3 "SurfaceOrientation: %d\n", mLocked.surfaceOrientation); } void TouchInputMapper::configureVirtualKeysLocked() { @@ -1651,9 +1666,21 @@ void TouchInputMapper::configureVirtualKeysLocked() { virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight) * touchScreenHeight / mLocked.surfaceHeight + touchScreenTop; - LOGI(INDENT "VirtualKey %d: keyCode=%d hitLeft=%d hitRight=%d hitTop=%d hitBottom=%d", - virtualKey.scanCode, virtualKey.keyCode, - virtualKey.hitLeft, virtualKey.hitRight, virtualKey.hitTop, virtualKey.hitBottom); + } +} + +void TouchInputMapper::dumpVirtualKeysLocked(String8& dump) { + if (!mLocked.virtualKeys.isEmpty()) { + dump.append(INDENT3 "Virtual Keys:\n"); + + for (size_t i = 0; i < mLocked.virtualKeys.size(); i++) { + const VirtualKey& virtualKey = mLocked.virtualKeys.itemAt(i); + dump.appendFormat(INDENT4 "%d: scanCode=%d, keyCode=%d, " + "hitLeft=%d, hitRight=%d, hitTop=%d, hitBottom=%d\n", + i, virtualKey.scanCode, virtualKey.keyCode, + virtualKey.hitLeft, virtualKey.hitRight, + virtualKey.hitTop, virtualKey.hitBottom); + } } } @@ -1861,19 +1888,19 @@ void TouchInputMapper::resolveCalibration() { } } -void TouchInputMapper::logCalibration() { - LOGI(INDENT "Calibration:"); +void TouchInputMapper::dumpCalibration(String8& dump) { + dump.append(INDENT3 "Calibration:\n"); // Touch Area switch (mCalibration.touchAreaCalibration) { case Calibration::TOUCH_AREA_CALIBRATION_NONE: - LOGI(INDENT INDENT "touch.touchArea.calibration: none"); + dump.append(INDENT4 "touch.touchArea.calibration: none\n"); break; case Calibration::TOUCH_AREA_CALIBRATION_GEOMETRIC: - LOGI(INDENT INDENT "touch.touchArea.calibration: geometric"); + dump.append(INDENT4 "touch.touchArea.calibration: geometric\n"); break; case Calibration::TOUCH_AREA_CALIBRATION_PRESSURE: - LOGI(INDENT INDENT "touch.touchArea.calibration: pressure"); + dump.append(INDENT4 "touch.touchArea.calibration: pressure\n"); break; default: assert(false); @@ -1882,40 +1909,43 @@ void TouchInputMapper::logCalibration() { // Tool Area switch (mCalibration.toolAreaCalibration) { case Calibration::TOOL_AREA_CALIBRATION_NONE: - LOGI(INDENT INDENT "touch.toolArea.calibration: none"); + dump.append(INDENT4 "touch.toolArea.calibration: none\n"); break; case Calibration::TOOL_AREA_CALIBRATION_GEOMETRIC: - LOGI(INDENT INDENT "touch.toolArea.calibration: geometric"); + dump.append(INDENT4 "touch.toolArea.calibration: geometric\n"); break; case Calibration::TOOL_AREA_CALIBRATION_LINEAR: - LOGI(INDENT INDENT "touch.toolArea.calibration: linear"); + dump.append(INDENT4 "touch.toolArea.calibration: linear\n"); break; default: assert(false); } if (mCalibration.haveToolAreaLinearScale) { - LOGI(INDENT INDENT "touch.toolArea.linearScale: %f", mCalibration.toolAreaLinearScale); + dump.appendFormat(INDENT4 "touch.toolArea.linearScale: %0.3f\n", + mCalibration.toolAreaLinearScale); } if (mCalibration.haveToolAreaLinearBias) { - LOGI(INDENT INDENT "touch.toolArea.linearBias: %f", mCalibration.toolAreaLinearBias); + dump.appendFormat(INDENT4 "touch.toolArea.linearBias: %0.3f\n", + mCalibration.toolAreaLinearBias); } if (mCalibration.haveToolAreaIsSummed) { - LOGI(INDENT INDENT "touch.toolArea.isSummed: %d", mCalibration.toolAreaIsSummed); + dump.appendFormat(INDENT4 "touch.toolArea.isSummed: %d\n", + mCalibration.toolAreaIsSummed); } // Pressure switch (mCalibration.pressureCalibration) { case Calibration::PRESSURE_CALIBRATION_NONE: - LOGI(INDENT INDENT "touch.pressure.calibration: none"); + dump.append(INDENT4 "touch.pressure.calibration: none\n"); break; case Calibration::PRESSURE_CALIBRATION_PHYSICAL: - LOGI(INDENT INDENT "touch.pressure.calibration: physical"); + dump.append(INDENT4 "touch.pressure.calibration: physical\n"); break; case Calibration::PRESSURE_CALIBRATION_AMPLITUDE: - LOGI(INDENT INDENT "touch.pressure.calibration: amplitude"); + dump.append(INDENT4 "touch.pressure.calibration: amplitude\n"); break; default: assert(false); @@ -1923,10 +1953,10 @@ void TouchInputMapper::logCalibration() { switch (mCalibration.pressureSource) { case Calibration::PRESSURE_SOURCE_PRESSURE: - LOGI(INDENT INDENT "touch.pressure.source: pressure"); + dump.append(INDENT4 "touch.pressure.source: pressure\n"); break; case Calibration::PRESSURE_SOURCE_TOUCH: - LOGI(INDENT INDENT "touch.pressure.source: touch"); + dump.append(INDENT4 "touch.pressure.source: touch\n"); break; case Calibration::PRESSURE_SOURCE_DEFAULT: break; @@ -1935,16 +1965,17 @@ void TouchInputMapper::logCalibration() { } if (mCalibration.havePressureScale) { - LOGI(INDENT INDENT "touch.pressure.scale: %f", mCalibration.pressureScale); + dump.appendFormat(INDENT4 "touch.pressure.scale: %0.3f\n", + mCalibration.pressureScale); } // Size switch (mCalibration.sizeCalibration) { case Calibration::SIZE_CALIBRATION_NONE: - LOGI(INDENT INDENT "touch.size.calibration: none"); + dump.append(INDENT4 "touch.size.calibration: none\n"); break; case Calibration::SIZE_CALIBRATION_NORMALIZED: - LOGI(INDENT INDENT "touch.size.calibration: normalized"); + dump.append(INDENT4 "touch.size.calibration: normalized\n"); break; default: assert(false); @@ -1953,10 +1984,10 @@ void TouchInputMapper::logCalibration() { // Orientation switch (mCalibration.orientationCalibration) { case Calibration::ORIENTATION_CALIBRATION_NONE: - LOGI(INDENT INDENT "touch.orientation.calibration: none"); + dump.append(INDENT4 "touch.orientation.calibration: none\n"); break; case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED: - LOGI(INDENT INDENT "touch.orientation.calibration: interpolated"); + dump.append(INDENT4 "touch.orientation.calibration: interpolated\n"); break; default: assert(false); @@ -2139,10 +2170,7 @@ void TouchInputMapper::applyPolicyAndDispatchVirtualKey(nsecs_t when, uint32_t p int32_t keyCode, int32_t scanCode, nsecs_t downTime) { int32_t metaState = mContext->getGlobalMetaState(); - if (keyEventAction == AKEY_EVENT_ACTION_DOWN) { - getPolicy()->virtualKeyDownFeedback(); - } - + policyFlags |= POLICY_FLAG_VIRTUAL; int32_t policyActions = getPolicy()->interceptKey(when, getDeviceId(), keyEventAction == AKEY_EVENT_ACTION_DOWN, keyCode, scanCode, policyFlags); diff --git a/libs/utils/ZipFileRO.cpp b/libs/utils/ZipFileRO.cpp index 9fcae7238d..9b1f82fab9 100644 --- a/libs/utils/ZipFileRO.cpp +++ b/libs/utils/ZipFileRO.cpp @@ -86,6 +86,16 @@ using namespace android; */ #define kZipEntryAdj 10000 +ZipFileRO::~ZipFileRO() { + free(mHashTable); + if (mDirectoryMap) + mDirectoryMap->release(); + if (mFd >= 0) + TEMP_FAILURE_RETRY(close(mFd)); + if (mFileName) + free(mFileName); +} + /* * Convert a ZipEntryRO to a hash table index, verifying that it's in a * valid range. @@ -122,7 +132,7 @@ status_t ZipFileRO::open(const char* zipFileName) mFileLength = lseek(fd, 0, SEEK_END); if (mFileLength < kEOCDLen) { - close(fd); + TEMP_FAILURE_RETRY(close(fd)); return UNKNOWN_ERROR; } @@ -152,7 +162,7 @@ status_t ZipFileRO::open(const char* zipFileName) bail: free(mFileName); mFileName = NULL; - close(fd); + TEMP_FAILURE_RETRY(close(fd)); return UNKNOWN_ERROR; } @@ -498,6 +508,36 @@ bool ZipFileRO::getEntryInfo(ZipEntryRO entry, int* pMethod, size_t* pUncompLen, unsigned char lfhBuf[kLFHLen]; +#ifdef HAVE_PREAD + /* + * This file descriptor might be from zygote's preloaded assets, + * so we need to do an pread() instead of a lseek() + read() to + * guarantee atomicity across the processes with the shared file + * descriptors. + */ + ssize_t actual = + TEMP_FAILURE_RETRY(pread(mFd, lfhBuf, sizeof(lfhBuf), localHdrOffset)); + + if (actual != sizeof(lfhBuf)) { + LOGW("failed reading lfh from offset %ld\n", localHdrOffset); + return false; + } + + if (get4LE(lfhBuf) != kLFHSignature) { + LOGW("didn't find signature at start of lfh; wanted: offset=%ld data=0x%08x; " + "got: data=0x%08lx\n", + localHdrOffset, kLFHSignature, get4LE(lfhBuf)); + return false; + } +#else /* HAVE_PREAD */ + /* + * For hosts don't have pread() we cannot guarantee atomic reads from + * an offset in a file. Android should never run on those platforms. + * File descriptors inherited from a fork() share file offsets and + * there would be nothing to protect from two different processes + * calling lseek() concurrently. + */ + { AutoMutex _l(mFdLock); @@ -507,18 +547,21 @@ bool ZipFileRO::getEntryInfo(ZipEntryRO entry, int* pMethod, size_t* pUncompLen, } ssize_t actual = - TEMP_FAILURE_RETRY(read(mFd, lfhBuf, sizeof(lfhBuf))); + TEMP_FAILURE_RETRY(read(mFd, lfhBuf, sizeof(lfhBuf))); if (actual != sizeof(lfhBuf)) { LOGW("failed reading lfh from offset %ld\n", localHdrOffset); return false; } - } - if (get4LE(lfhBuf) != kLFHSignature) { - LOGW("didn't find signature at start of lfh, offset=%ld (got 0x%08lx, expected 0x%08x)\n", - localHdrOffset, get4LE(lfhBuf), kLFHSignature); - return false; + if (get4LE(lfhBuf) != kLFHSignature) { + off_t actualOffset = lseek(mFd, 0, SEEK_CUR); + LOGW("didn't find signature at start of lfh; wanted: offset=%ld data=0x%08x; " + "got: offset=%zd data=0x%08lx\n", + localHdrOffset, kLFHSignature, (size_t)actualOffset, get4LE(lfhBuf)); + return false; + } } +#endif /* HAVE_PREAD */ off_t dataOffset = localHdrOffset + kLFHLen + get2LE(lfhBuf + kLFHNameLen) + get2LE(lfhBuf + kLFHExtraLen); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 695cbfa0a8..a060d316dd 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -214,6 +214,17 @@ slowpath: } } +void Layer::drawForSreenShot() const +{ + bool currentFixedSize = mFixedSize; + bool currentBlending = mNeedsBlending; + const_cast<Layer*>(this)->mFixedSize = false; + const_cast<Layer*>(this)->mFixedSize = true; + LayerBase::drawForSreenShot(); + const_cast<Layer*>(this)->mFixedSize = currentFixedSize; + const_cast<Layer*>(this)->mNeedsBlending = currentBlending; +} + void Layer::onDraw(const Region& clip) const { Texture tex(mBufferManager.getActiveTexture()); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index e1d283bedd..263c372716 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -68,6 +68,7 @@ public: bool isFixedSize() const; // LayerBase interface + virtual void drawForSreenShot() const; virtual void onDraw(const Region& clip) const; virtual uint32_t doTransaction(uint32_t transactionFlags); virtual void lockPageFlip(bool& recomputeVisibleRegions); diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp index 6fc50109eb..758b408782 100644 --- a/services/surfaceflinger/LayerBase.cpp +++ b/services/surfaceflinger/LayerBase.cpp @@ -317,6 +317,12 @@ void LayerBase::draw(const Region& clip) const onDraw(clip); } +void LayerBase::drawForSreenShot() const +{ + const DisplayHardware& hw(graphicPlane(0).displayHardware()); + onDraw( Region(hw.bounds()) ); +} + void LayerBase::clearWithOpenGL(const Region& clip, GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) const diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h index 8cba287f8e..d688f6523d 100644 --- a/services/surfaceflinger/LayerBase.h +++ b/services/surfaceflinger/LayerBase.h @@ -115,6 +115,7 @@ public: * to perform the actual drawing. */ virtual void draw(const Region& clip) const; + virtual void drawForSreenShot() const; /** * onDraw - draws the surface. diff --git a/services/surfaceflinger/LayerBuffer.cpp b/services/surfaceflinger/LayerBuffer.cpp index 0240748ce6..87cabedc04 100644 --- a/services/surfaceflinger/LayerBuffer.cpp +++ b/services/surfaceflinger/LayerBuffer.cpp @@ -132,6 +132,12 @@ void LayerBuffer::unlockPageFlip(const Transform& planeTransform, LayerBase::unlockPageFlip(planeTransform, outDirtyRegion); } +void LayerBuffer::drawForSreenShot() const +{ + const DisplayHardware& hw(graphicPlane(0).displayHardware()); + clearWithOpenGL( Region(hw.bounds()) ); +} + void LayerBuffer::onDraw(const Region& clip) const { sp<Source> source(getSource()); diff --git a/services/surfaceflinger/LayerBuffer.h b/services/surfaceflinger/LayerBuffer.h index 1c0bf830e1..fece858a20 100644 --- a/services/surfaceflinger/LayerBuffer.h +++ b/services/surfaceflinger/LayerBuffer.h @@ -64,6 +64,7 @@ public: virtual sp<LayerBaseClient::Surface> createSurface() const; virtual status_t ditch(); virtual void onDraw(const Region& clip) const; + virtual void drawForSreenShot() const; virtual uint32_t doTransaction(uint32_t flags); virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 2b06f6fa42..e5e87c60ec 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1546,9 +1546,117 @@ status_t SurfaceFlinger::onTransact( // --------------------------------------------------------------------------- +status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy, + sp<IMemoryHeap>* heap, + uint32_t* w, uint32_t* h, PixelFormat* f, + uint32_t sw, uint32_t sh) +{ + status_t result = PERMISSION_DENIED; + + // only one display supported for now + if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT)) + return BAD_VALUE; + + if (!GLExtensions::getInstance().haveFramebufferObject()) + return INVALID_OPERATION; + + // get screen geometry + const DisplayHardware& hw(graphicPlane(dpy).displayHardware()); + const uint32_t hw_w = hw.getWidth(); + const uint32_t hw_h = hw.getHeight(); + + if ((sw > hw_w) || (sh > hw_h)) + return BAD_VALUE; + + sw = (!sw) ? hw_w : sw; + sh = (!sh) ? hw_h : sh; + const size_t size = sw * sh * 4; + + // make sure to clear all GL error flags + while ( glGetError() != GL_NO_ERROR ) ; + + // create a FBO + GLuint name, tname; + glGenRenderbuffersOES(1, &tname); + glBindRenderbufferOES(GL_RENDERBUFFER_OES, tname); + glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_RGBA8_OES, sw, sh); + glGenFramebuffersOES(1, &name); + glBindFramebufferOES(GL_FRAMEBUFFER_OES, name); + glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, + GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, tname); + + GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES); + if (status == GL_FRAMEBUFFER_COMPLETE_OES) { + + // invert everything, b/c glReadPixel() below will invert the FB + glViewport(0, 0, sw, sh); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glOrthof(0, hw_w, 0, hw_h, 0, 1); + glMatrixMode(GL_MODELVIEW); + + // redraw the screen entirely... + glClearColor(0,0,0,1); + glClear(GL_COLOR_BUFFER_BIT); + const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ); + const size_t count = layers.size(); + for (size_t i=0 ; i<count ; ++i) { + const sp<LayerBase>& layer(layers[i]); + layer->drawForSreenShot(); + } + + // XXX: this is needed on tegra + glScissor(0, 0, sw, sh); + + // check for errors and return screen capture + if (glGetError() != GL_NO_ERROR) { + // error while rendering + result = INVALID_OPERATION; + } else { + // allocate shared memory large enough to hold the + // screen capture + sp<MemoryHeapBase> base( + new MemoryHeapBase(size, 0, "screen-capture") ); + void* const ptr = base->getBase(); + if (ptr) { + // capture the screen with glReadPixels() + glReadPixels(0, 0, sw, sh, GL_RGBA, GL_UNSIGNED_BYTE, ptr); + if (glGetError() == GL_NO_ERROR) { + *heap = base; + *w = sw; + *h = sh; + *f = PIXEL_FORMAT_RGBA_8888; + result = NO_ERROR; + } + } else { + result = NO_MEMORY; + } + } + + glEnable(GL_SCISSOR_TEST); + glViewport(0, 0, hw_w, hw_h); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + + + } else { + result = BAD_VALUE; + } + + // release FBO resources + glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); + glDeleteRenderbuffersOES(1, &tname); + glDeleteFramebuffersOES(1, &name); + return result; +} + + status_t SurfaceFlinger::captureScreen(DisplayID dpy, sp<IMemoryHeap>* heap, - uint32_t* width, uint32_t* height, PixelFormat* format) + uint32_t* width, uint32_t* height, PixelFormat* format, + uint32_t sw, uint32_t sh) { // only one display supported for now if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT)) @@ -1564,12 +1672,15 @@ status_t SurfaceFlinger::captureScreen(DisplayID dpy, uint32_t* w; uint32_t* h; PixelFormat* f; + uint32_t sw; + uint32_t sh; status_t result; public: MessageCaptureScreen(SurfaceFlinger* flinger, DisplayID dpy, - sp<IMemoryHeap>* heap, uint32_t* w, uint32_t* h, PixelFormat* f) + sp<IMemoryHeap>* heap, uint32_t* w, uint32_t* h, PixelFormat* f, + uint32_t sw, uint32_t sh) : flinger(flinger), dpy(dpy), - heap(heap), w(w), h(h), f(f), result(PERMISSION_DENIED) + heap(heap), w(w), h(h), f(f), sw(sw), sh(sh), result(PERMISSION_DENIED) { } status_t getResult() const { @@ -1582,94 +1693,15 @@ status_t SurfaceFlinger::captureScreen(DisplayID dpy, if (flinger->mSecureFrameBuffer) return true; - // make sure to clear all GL error flags - while ( glGetError() != GL_NO_ERROR ) ; - - // get screen geometry - const DisplayHardware& hw(flinger->graphicPlane(dpy).displayHardware()); - const uint32_t sw = hw.getWidth(); - const uint32_t sh = hw.getHeight(); - const Region screenBounds(hw.bounds()); - const size_t size = sw * sh * 4; - - // create a FBO - GLuint name, tname; - glGenRenderbuffersOES(1, &tname); - glBindRenderbufferOES(GL_RENDERBUFFER_OES, tname); - glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_RGBA8_OES, sw, sh); - glGenFramebuffersOES(1, &name); - glBindFramebufferOES(GL_FRAMEBUFFER_OES, name); - glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, - GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, tname); - - GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES); - if (status == GL_FRAMEBUFFER_COMPLETE_OES) { - - // invert everything, b/c glReadPixel() below will invert the FB - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glOrthof(0, sw, 0, sh, 0, 1); - glMatrixMode(GL_MODELVIEW); - - // redraw the screen entirely... - glClearColor(0,0,0,1); - glClear(GL_COLOR_BUFFER_BIT); - const Vector< sp<LayerBase> >& layers( - flinger->mVisibleLayersSortedByZ); - const size_t count = layers.size(); - for (size_t i=0 ; i<count ; ++i) { - const sp<LayerBase>& layer(layers[i]); - if (!strcmp(layer->getTypeId(), "LayerBuffer")) { - // we cannot render LayerBuffer because it doens't - // use OpenGL, and won't show-up in the FBO. - continue; - } - layer->draw(screenBounds); - } - - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - - // check for errors and return screen capture - if (glGetError() != GL_NO_ERROR) { - // error while rendering - result = INVALID_OPERATION; - } else { - // allocate shared memory large enough to hold the - // screen capture - sp<MemoryHeapBase> base( - new MemoryHeapBase(size, 0, "screen-capture") ); - void* const ptr = base->getBase(); - if (ptr) { - // capture the screen with glReadPixels() - glReadPixels(0, 0, sw, sh, GL_RGBA, GL_UNSIGNED_BYTE, ptr); - if (glGetError() == GL_NO_ERROR) { - *heap = base; - *w = sw; - *h = sh; - *f = PIXEL_FORMAT_RGBA_8888; - result = NO_ERROR; - } - } else { - result = NO_MEMORY; - } - } - } else { - result = BAD_VALUE; - } + result = flinger->captureScreenImplLocked(dpy, + heap, w, h, f, sw, sh); - // release FBO resources - glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); - glDeleteRenderbuffersOES(1, &tname); - glDeleteFramebuffersOES(1, &name); return true; } }; sp<MessageBase> msg = new MessageCaptureScreen(this, - dpy, heap, width, height, format); + dpy, heap, width, height, format, sw, sh); status_t res = postMessageSync(msg); if (res == NO_ERROR) { res = static_cast<MessageCaptureScreen*>( msg.get() )->getResult(); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index f09fdbc050..f0a167b969 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -197,7 +197,9 @@ public: sp<IMemoryHeap>* heap, uint32_t* width, uint32_t* height, - PixelFormat* format); + PixelFormat* format, + uint32_t reqWidth, + uint32_t reqHeight); void screenReleased(DisplayID dpy); void screenAcquired(DisplayID dpy); @@ -318,6 +320,11 @@ private: void commitTransaction(); + status_t captureScreenImplLocked(DisplayID dpy, + sp<IMemoryHeap>* heap, + uint32_t* width, uint32_t* height, PixelFormat* format, + uint32_t reqWidth = 0, uint32_t reqHeight = 0); + friend class FreezeLock; sp<FreezeLock> getFreezeLock() const; inline void incFreezeCount() { diff --git a/services/surfaceflinger/tests/screencap/screencap.cpp b/services/surfaceflinger/tests/screencap/screencap.cpp index 9e893f48f0..6cf1504173 100644 --- a/services/surfaceflinger/tests/screencap/screencap.cpp +++ b/services/surfaceflinger/tests/screencap/screencap.cpp @@ -42,7 +42,7 @@ int main(int argc, char** argv) sp<IMemoryHeap> heap; uint32_t w, h; PixelFormat f; - status_t err = composer->captureScreen(0, &heap, &w, &h, &f); + status_t err = composer->captureScreen(0, &heap, &w, &h, &f, 0, 0); if (err != NO_ERROR) { fprintf(stderr, "screen capture failed: %s\n", strerror(-err)); exit(0); |