Merge "DO NOT MERGE. Fix logic for switching between overscroll and scroll modes." into gingerbread
diff --git a/cmds/keystore/keystore.c b/cmds/keystore/keystore.c
index 971a177..afa64f8 100644
--- a/cmds/keystore/keystore.c
+++ b/cmds/keystore/keystore.c
@@ -143,15 +143,20 @@
     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 @@
         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 @@
     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 @@
     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 @@
 
     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 @@
     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 @@
 
 #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/ui/EventHub.h b/include/ui/EventHub.h
index d6b09dc..d78e35f 100644
--- a/include/ui/EventHub.h
+++ b/include/ui/EventHub.h
@@ -142,8 +142,13 @@
 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 @@
      */
     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 @@
 
     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 @@
         ~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 @@
     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 21baf32..ee40b85 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -73,7 +73,8 @@
  * 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 @@
     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 d3fbaf7..3619189 100644
--- a/include/ui/InputReader.h
+++ b/include/ui/InputReader.h
@@ -103,10 +103,6 @@
     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 @@
     // 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;
diff --git a/include/ui/KeycodeLabels.h b/include/ui/KeycodeLabels.h
index c8d6ffc..f71d9cd 100755
--- a/include/ui/KeycodeLabels.h
+++ b/include/ui/KeycodeLabels.h
@@ -142,6 +142,7 @@
     { NULL, 0 }
 };
 
+// See also policy flags in Input.h.
 static const KeycodeLabel FLAGS[] = {
     { "WAKE", 0x00000001 },
     { "WAKE_DROPPED", 0x00000002 },
@@ -151,6 +152,7 @@
     { "ALT_GR", 0x00000020 },
     { "MENU", 0x00000040 },
     { "LAUNCHER", 0x00000080 },
+    { "VIRTUAL", 0x00000100 },
     { NULL, 0 }
 };
 
diff --git a/include/utils/ZipFileRO.h b/include/utils/ZipFileRO.h
index 9668bde..e1ff780 100644
--- a/include/utils/ZipFileRO.h
+++ b/include/utils/ZipFileRO.h
@@ -64,15 +64,8 @@
           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/ui/EventHub.cpp b/libs/ui/EventHub.cpp
index 1d38b4b..c0be3a0 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 @@
     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 @@
     : 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 @@
 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 @@
 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 @@
     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 @@
     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::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 @@
     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 @@
         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 @@
         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 @@
     }
     
     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 @@
 
 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 @@
     if (!mOpened) {
         mError = openPlatformInput() ? NO_ERROR : UNKNOWN_ERROR;
         mOpened = true;
+        mNeedToSendFinishedDeviceScan = true;
     }
 
     for (;;) {
@@ -360,6 +371,7 @@
             }
             outEvent->type = DEVICE_REMOVED;
             delete device;
+            mNeedToSendFinishedDeviceScan = true;
             return true;
         }
 
@@ -374,6 +386,13 @@
                 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 @@
             }
         }
 
-        // 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 @@
     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 @@
         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 @@
         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 @@
     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 @@
     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 @@
     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 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 @@
         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::scan_dir(const char *dirname)
+int EventHub::scanDir(const char *dirname)
 {
     char devname[PATH_MAX];
     char *filename;
@@ -966,10 +981,38 @@
             (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 9544a95..aa54f82 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::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");
     }
 
-    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 (!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");
     }
 
-    dump.appendFormat("  inboundQueue: length=%u", mInboundQueue.count());
+    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");
+    }
 
-    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()));
+    dump.appendFormat(INDENT "InboundQueue: length=%u\n", mInboundQueue.count());
+
+    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::dump(String8& dump) {
+    dump.append("Input Dispatcher State:\n");
     dumpDispatchStateLocked(dump);
 }
 
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index 1d35e10..8e173aa 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -226,11 +226,15 @@
 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:
@@ -239,7 +243,7 @@
     }
 }
 
-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);
 
@@ -269,11 +273,9 @@
         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
@@ -303,8 +305,6 @@
     device->reset();
 
     delete device;
-
-    handleConfigurationChanged(when);
 }
 
 InputDevice* InputReader::createDevice(int32_t deviceId, const String8& name, uint32_t classes) {
@@ -372,7 +372,7 @@
     } // 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();
 
@@ -380,6 +380,7 @@
     updateInputConfiguration();
 
     // Enqueue configuration changed.
+    nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC);
     mDispatcher->notifyConfigurationChanged(when);
 }
 
@@ -575,6 +576,11 @@
 }
 
 void InputReader::dump(String8& dump) {
+    mEventHub->dump(dump);
+    dump.append("\n");
+
+    dump.append("Input Reader State:\n");
+
     { // acquire device registry reader lock
         RWLock::AutoRLock _rl(mDeviceRegistryLock);
 
@@ -861,7 +867,6 @@
         AutoMutex _l(mLock);
         dump.append(INDENT2 "Keyboard Input Mapper:\n");
         dump.appendFormat(INDENT3 "AssociatedDisplayId: %d\n", mAssociatedDisplayId);
-        dump.appendFormat(INDENT3 "Sources: 0x%x\n", mSources);
         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);
@@ -993,7 +998,10 @@
     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,
@@ -2162,10 +2170,7 @@
         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 9fcae72..bee86b2 100644
--- a/libs/utils/ZipFileRO.cpp
+++ b/libs/utils/ZipFileRO.cpp
@@ -86,6 +86,16 @@
  */
 #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 @@
 
     mFileLength = lseek(fd, 0, SEEK_END);
     if (mFileLength < kEOCDLen) {
-        close(fd);
+        TEMP_FAILURE_RETRY(close(fd));
         return UNKNOWN_ERROR;
     }
 
@@ -152,7 +162,7 @@
 bail:
     free(mFileName);
     mFileName = NULL;
-    close(fd);
+    TEMP_FAILURE_RETRY(close(fd));
     return UNKNOWN_ERROR;
 }
 
@@ -512,12 +522,14 @@
                 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;
+            }
         }
 
         off_t dataOffset = localHdrOffset + kLFHLen