am 8d49c8b0: am f66486ef: Merge "Fix incorrect path name check."

* commit '8d49c8b0bfdc7bed855acec603bacc355b5bcb8c':
  Fix incorrect path name check.
diff --git a/adb/adb.h b/adb/adb.h
index f584c57..044760e 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -339,6 +339,9 @@
 int check_header(apacket *p);
 int check_data(apacket *p);
 
+// Define it if you want to dump packets.
+#define DEBUG_PACKETS 0
+
 #if !DEBUG_PACKETS
 #define print_packet(tag,p) do {} while (0)
 #endif
diff --git a/adb/adb_client.c b/adb/adb_client.c
index eb1720d..ac5e15a 100644
--- a/adb/adb_client.c
+++ b/adb/adb_client.c
@@ -279,7 +279,7 @@
 
     fd = _adb_connect(service);
     if(fd == -1) {
-        D("_adb_connect error: %s\n", __adb_error);
+        D("_adb_connect error: %s", __adb_error);
     } else if(fd == -2) {
         fprintf(stderr,"** daemon still not running\n");
     }
diff --git a/adb/adb_trace.h b/adb/adb_trace.h
index 8a5d9f8..b8a2f4c 100644
--- a/adb/adb_trace.h
+++ b/adb/adb_trace.h
@@ -73,8 +73,9 @@
             if (ADB_TRACING) {                         \
                 int save_errno = errno;                \
                 adb_mutex_lock(&D_lock);               \
-                fprintf(stderr, "%s::%s():",           \
-                        __FILE__, __FUNCTION__);       \
+                fprintf(stderr, "%16s: %5d:%5lu | ",   \
+                        __FUNCTION__,                  \
+                        getpid(), adb_thread_id());    \
                 errno = save_errno;                    \
                 fprintf(stderr, __VA_ARGS__ );         \
                 fflush(stderr);                        \
@@ -96,15 +97,16 @@
         } while (0)
 #  define  DD(...)                                     \
         do {                                           \
-          int save_errno = errno;                      \
-          adb_mutex_lock(&D_lock);                     \
-          fprintf(stderr, "%s::%s():",                 \
-                  __FILE__, __FUNCTION__);             \
-          errno = save_errno;                          \
-          fprintf(stderr, __VA_ARGS__ );               \
-          fflush(stderr);                              \
-          adb_mutex_unlock(&D_lock);                   \
-          errno = save_errno;                          \
+            int save_errno = errno;                    \
+            adb_mutex_lock(&D_lock);                   \
+            fprintf(stderr, "%16s: %5d:%5lu | ",       \
+                    __FUNCTION__,                      \
+                    getpid(), adb_thread_id());        \
+            errno = save_errno;                        \
+            fprintf(stderr, __VA_ARGS__ );             \
+            fflush(stderr);                            \
+            adb_mutex_unlock(&D_lock);                 \
+            errno = save_errno;                        \
         } while (0)
 #else
 #  define  D(...)                                      \
diff --git a/adb/fdevent.c b/adb/fdevent.c
index 43e600c..f5ecd14 100644
--- a/adb/fdevent.c
+++ b/adb/fdevent.c
@@ -661,6 +661,8 @@
     if(adb_socketpair(s)) {
         FATAL("cannot create shell-exit socket-pair\n");
     }
+    D("socketpair: (%d,%d)", s[0], s[1]);
+
     SHELL_EXIT_NOTIFY_FD = s[0];
     fdevent *fde;
     fde = fdevent_create(s[1], fdevent_subproc_event_func, NULL);
diff --git a/adb/jdwp_service.c b/adb/jdwp_service.c
index cd62b55..3074e42 100644
--- a/adb/jdwp_service.c
+++ b/adb/jdwp_service.c
@@ -415,6 +415,7 @@
               __FUNCTION__, strerror(errno));
             return -1;
         }
+        D("socketpair: (%d,%d)", fds[0], fds[1]);
 
         proc->out_fds[ proc->out_count ] = fds[1];
         if (++proc->out_count == 1)
diff --git a/adb/services.c b/adb/services.c
index 703aec8..1aeb376 100644
--- a/adb/services.c
+++ b/adb/services.c
@@ -164,6 +164,7 @@
         printf("cannot create service socket pair\n");
         return -1;
     }
+    D("socketpair: (%d,%d)", s[0], s[1]);
 
     sti = malloc(sizeof(stinfo));
     if(sti == 0) fatal("cannot allocate stinfo");
@@ -264,10 +265,11 @@
 
     // 0 is parent socket, 1 is child socket
     int sv[2];
-    if (unix_socketpair(AF_UNIX, SOCK_STREAM, 0, sv) < 0) {
+    if (adb_socketpair(sv) < 0) {
         printf("[ cannot create socket pair - %s ]\n", strerror(errno));
         return -1;
     }
+    D("socketpair: (%d,%d)", sv[0], sv[1]);
 
     *pid = fork();
     if (*pid < 0) {
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index cc1f839..8d63d14 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -77,6 +77,11 @@
     return 0;
 }
 
+static __inline__  unsigned long adb_thread_id()
+{
+    return GetCurrentThreadId();
+}
+
 static __inline__ void  close_on_exec(int  fd)
 {
     /* nothing really */
@@ -516,6 +521,12 @@
 {
     return strtok_r(str, delim, saveptr);
 }
+
+static __inline__ unsigned long adb_thread_id()
+{
+    return (unsigned long)pthread_self();
+}
+
 #undef   strtok_r
 #define  strtok_r  ___xxx_strtok_r
 
diff --git a/adb/transport.c b/adb/transport.c
index f35880c..7db6a47 100644
--- a/adb/transport.c
+++ b/adb/transport.c
@@ -629,7 +629,7 @@
             fatal_errno("cannot open transport socketpair");
         }
 
-        D("transport: %s (%d,%d) starting\n", t->serial, s[0], s[1]);
+        D("transport: %s socketpair: (%d,%d) starting", t->serial, s[0], s[1]);
 
         t->transport_socket = s[0];
         t->fd = s[1];
@@ -673,6 +673,7 @@
     if(adb_socketpair(s)){
         fatal_errno("cannot open transport registration socketpair");
     }
+    D("socketpair: (%d,%d)", s[0], s[1]);
 
     transport_registration_send = s[0];
     transport_registration_recv = s[1];
diff --git a/adb/usb_linux_client.c b/adb/usb_linux_client.c
index 8426e0e..ecfae5d 100644
--- a/adb/usb_linux_client.c
+++ b/adb/usb_linux_client.c
@@ -55,71 +55,85 @@
     int bulk_in;  /* "in" from the host's perspective => sink for adbd */
 };
 
-static const struct {
-    struct usb_functionfs_descs_head header;
-    struct {
-        struct usb_interface_descriptor intf;
-        struct usb_endpoint_descriptor_no_audio source;
-        struct usb_endpoint_descriptor_no_audio sink;
-    } __attribute__((packed)) fs_descs, hs_descs;
-} __attribute__((packed)) descriptors = {
-    .header = {
-        .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC),
-        .length = cpu_to_le32(sizeof(descriptors)),
-        .fs_count = 3,
-        .hs_count = 3,
+struct func_desc {
+    struct usb_interface_descriptor intf;
+    struct usb_endpoint_descriptor_no_audio source;
+    struct usb_endpoint_descriptor_no_audio sink;
+} __attribute__((packed));
+
+struct desc_v1 {
+    struct usb_functionfs_descs_head_v1 {
+        __le32 magic;
+        __le32 length;
+        __le32 fs_count;
+        __le32 hs_count;
+    } __attribute__((packed)) header;
+    struct func_desc fs_descs, hs_descs;
+} __attribute__((packed));
+
+struct desc_v2 {
+    struct usb_functionfs_descs_head_v2 {
+        __le32 magic;
+        __le32 length;
+        __le32 flags;
+        __le32 fs_count;
+        __le32 hs_count;
+        __le32 ss_count;
+    } __attribute__((packed)) header;
+    struct func_desc fs_descs, hs_descs;
+} __attribute__((packed));
+
+struct func_desc fs_descriptors = {
+    .intf = {
+        .bLength = sizeof(fs_descriptors.intf),
+        .bDescriptorType = USB_DT_INTERFACE,
+        .bInterfaceNumber = 0,
+        .bNumEndpoints = 2,
+        .bInterfaceClass = ADB_CLASS,
+        .bInterfaceSubClass = ADB_SUBCLASS,
+        .bInterfaceProtocol = ADB_PROTOCOL,
+        .iInterface = 1, /* first string from the provided table */
     },
-    .fs_descs = {
-        .intf = {
-            .bLength = sizeof(descriptors.fs_descs.intf),
-            .bDescriptorType = USB_DT_INTERFACE,
-            .bInterfaceNumber = 0,
-            .bNumEndpoints = 2,
-            .bInterfaceClass = ADB_CLASS,
-            .bInterfaceSubClass = ADB_SUBCLASS,
-            .bInterfaceProtocol = ADB_PROTOCOL,
-            .iInterface = 1, /* first string from the provided table */
-        },
-        .source = {
-            .bLength = sizeof(descriptors.fs_descs.source),
-            .bDescriptorType = USB_DT_ENDPOINT,
-            .bEndpointAddress = 1 | USB_DIR_OUT,
-            .bmAttributes = USB_ENDPOINT_XFER_BULK,
-            .wMaxPacketSize = MAX_PACKET_SIZE_FS,
-        },
-        .sink = {
-            .bLength = sizeof(descriptors.fs_descs.sink),
-            .bDescriptorType = USB_DT_ENDPOINT,
-            .bEndpointAddress = 2 | USB_DIR_IN,
-            .bmAttributes = USB_ENDPOINT_XFER_BULK,
-            .wMaxPacketSize = MAX_PACKET_SIZE_FS,
-        },
+    .source = {
+        .bLength = sizeof(fs_descriptors.source),
+        .bDescriptorType = USB_DT_ENDPOINT,
+        .bEndpointAddress = 1 | USB_DIR_OUT,
+        .bmAttributes = USB_ENDPOINT_XFER_BULK,
+        .wMaxPacketSize = MAX_PACKET_SIZE_FS,
     },
-    .hs_descs = {
-        .intf = {
-            .bLength = sizeof(descriptors.hs_descs.intf),
-            .bDescriptorType = USB_DT_INTERFACE,
-            .bInterfaceNumber = 0,
-            .bNumEndpoints = 2,
-            .bInterfaceClass = ADB_CLASS,
-            .bInterfaceSubClass = ADB_SUBCLASS,
-            .bInterfaceProtocol = ADB_PROTOCOL,
-            .iInterface = 1, /* first string from the provided table */
-        },
-        .source = {
-            .bLength = sizeof(descriptors.hs_descs.source),
-            .bDescriptorType = USB_DT_ENDPOINT,
-            .bEndpointAddress = 1 | USB_DIR_OUT,
-            .bmAttributes = USB_ENDPOINT_XFER_BULK,
-            .wMaxPacketSize = MAX_PACKET_SIZE_HS,
-        },
-        .sink = {
-            .bLength = sizeof(descriptors.hs_descs.sink),
-            .bDescriptorType = USB_DT_ENDPOINT,
-            .bEndpointAddress = 2 | USB_DIR_IN,
-            .bmAttributes = USB_ENDPOINT_XFER_BULK,
-            .wMaxPacketSize = MAX_PACKET_SIZE_HS,
-        },
+    .sink = {
+        .bLength = sizeof(fs_descriptors.sink),
+        .bDescriptorType = USB_DT_ENDPOINT,
+        .bEndpointAddress = 2 | USB_DIR_IN,
+        .bmAttributes = USB_ENDPOINT_XFER_BULK,
+        .wMaxPacketSize = MAX_PACKET_SIZE_FS,
+    },
+};
+
+struct func_desc hs_descriptors = {
+    .intf = {
+        .bLength = sizeof(hs_descriptors.intf),
+        .bDescriptorType = USB_DT_INTERFACE,
+        .bInterfaceNumber = 0,
+        .bNumEndpoints = 2,
+        .bInterfaceClass = ADB_CLASS,
+        .bInterfaceSubClass = ADB_SUBCLASS,
+        .bInterfaceProtocol = ADB_PROTOCOL,
+        .iInterface = 1, /* first string from the provided table */
+    },
+    .source = {
+        .bLength = sizeof(hs_descriptors.source),
+        .bDescriptorType = USB_DT_ENDPOINT,
+        .bEndpointAddress = 1 | USB_DIR_OUT,
+        .bmAttributes = USB_ENDPOINT_XFER_BULK,
+        .wMaxPacketSize = MAX_PACKET_SIZE_HS,
+    },
+    .sink = {
+        .bLength = sizeof(hs_descriptors.sink),
+        .bDescriptorType = USB_DT_ENDPOINT,
+        .bEndpointAddress = 2 | USB_DIR_IN,
+        .bmAttributes = USB_ENDPOINT_XFER_BULK,
+        .wMaxPacketSize = MAX_PACKET_SIZE_HS,
     },
 };
 
@@ -263,6 +277,17 @@
 static void init_functionfs(struct usb_handle *h)
 {
     ssize_t ret;
+    struct desc_v1 v1_descriptor;
+    struct desc_v2 v2_descriptor;
+
+    v2_descriptor.header.magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2);
+    v2_descriptor.header.length = cpu_to_le32(sizeof(v2_descriptor));
+    v2_descriptor.header.flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC;
+    v2_descriptor.header.fs_count = 3;
+    v2_descriptor.header.hs_count = 3;
+    v2_descriptor.header.ss_count = 0;
+    v2_descriptor.fs_descs = fs_descriptors;
+    v2_descriptor.hs_descs = hs_descriptors;
 
     if (h->control < 0) { // might have already done this before
         D("OPENING %s\n", USB_FFS_ADB_EP0);
@@ -272,10 +297,20 @@
             goto err;
         }
 
-        ret = adb_write(h->control, &descriptors, sizeof(descriptors));
+        ret = adb_write(h->control, &v2_descriptor, sizeof(v2_descriptor));
         if (ret < 0) {
-            D("[ %s: write descriptors failed: errno=%d ]\n", USB_FFS_ADB_EP0, errno);
-            goto err;
+            v1_descriptor.header.magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC);
+            v1_descriptor.header.length = cpu_to_le32(sizeof(v1_descriptor));
+            v1_descriptor.header.fs_count = 3;
+            v1_descriptor.header.hs_count = 3;
+            v1_descriptor.fs_descs = fs_descriptors;
+            v1_descriptor.hs_descs = hs_descriptors;
+            D("[ %s: Switching to V1_descriptor format errno=%d ]\n", USB_FFS_ADB_EP0, errno);
+            ret = adb_write(h->control, &v1_descriptor, sizeof(v1_descriptor));
+            if (ret < 0) {
+                D("[ %s: write descriptors failed: errno=%d ]\n", USB_FFS_ADB_EP0, errno);
+                goto err;
+            }
         }
 
         ret = adb_write(h->control, &strings, sizeof(strings));
diff --git a/fastboot/fastboot.c b/fastboot/fastboot.c
index 92a61f8..2fbb7a6 100644
--- a/fastboot/fastboot.c
+++ b/fastboot/fastboot.c
@@ -295,9 +295,8 @@
             "                                           Can override the fs type and/or\n"
             "                                           size the bootloader reports.\n"
             "  getvar <variable>                        display a bootloader variable\n"
-            "  boot <kernel> [ <ramdisk> [ <second> ] ] download and boot kernel\n"
-            "  flash:raw boot <kernel> [ <ramdisk> [ <second> ] ] create bootimage and \n"
-            "                                           flash it\n"
+            "  boot <kernel> [ <ramdisk> ]              download and boot kernel\n"
+            "  flash:raw boot <kernel> [ <ramdisk> ]    create bootimage and flash it\n"
             "  devices                                  list all connected devices\n"
             "  continue                                 continue with autoboot\n"
             "  reboot                                   reboot device normally\n"
@@ -325,11 +324,10 @@
 }
 
 void *load_bootable_image(const char *kernel, const char *ramdisk,
-                          const char *secondstage, unsigned *sz,
-                          const char *cmdline)
+                          unsigned *sz, const char *cmdline)
 {
-    void *kdata = 0, *rdata = 0, *sdata = 0;
-    unsigned ksize = 0, rsize = 0, ssize = 0;
+    void *kdata = 0, *rdata = 0;
+    unsigned ksize = 0, rsize = 0;
     void *bdata;
     unsigned bsize;
 
@@ -365,18 +363,10 @@
         }
     }
 
-    if (secondstage) {
-        sdata = load_file(secondstage, &ssize);
-        if(sdata == 0) {
-            fprintf(stderr,"cannot load '%s': %s\n", secondstage, strerror(errno));
-            return  0;
-        }
-    }
-
     fprintf(stderr,"creating boot image...\n");
     bdata = mkbootimg(kdata, ksize, kernel_offset,
                       rdata, rsize, ramdisk_offset,
-                      sdata, ssize, second_offset,
+                      0, 0, second_offset,
                       page_size, base_addr, tags_offset, &bsize);
     if(bdata == 0) {
         fprintf(stderr,"failed to create boot.img\n");
@@ -1162,7 +1152,6 @@
         } else if(!strcmp(*argv, "boot")) {
             char *kname = 0;
             char *rname = 0;
-            char *sname = 0;
             skip(1);
             if (argc > 0) {
                 kname = argv[0];
@@ -1172,11 +1161,7 @@
                 rname = argv[0];
                 skip(1);
             }
-            if (argc > 0) {
-                sname = argv[0];
-                skip(1);
-            }
-            data = load_bootable_image(kname, rname, sname, &sz, cmdline);
+            data = load_bootable_image(kname, rname, &sz, cmdline);
             if (data == 0) return 1;
             fb_queue_download("boot.img", data, sz);
             fb_queue_command("boot", "booting");
@@ -1200,18 +1185,14 @@
             char *pname = argv[1];
             char *kname = argv[2];
             char *rname = 0;
-            char *sname = 0;
             require(3);
-            skip(3);
-            if (argc > 0) {
-                rname = argv[0];
-                skip(1);
+            if(argc > 3) {
+                rname = argv[3];
+                skip(4);
+            } else {
+                skip(3);
             }
-            if (argc > 0) {
-                sname = argv[0];
-                skip(1);
-            }
-            data = load_bootable_image(kname, rname, sname, &sz, cmdline);
+            data = load_bootable_image(kname, rname, &sz, cmdline);
             if (data == 0) die("cannot load bootable image");
             fb_queue_flash(pname, data, sz);
         } else if(!strcmp(*argv, "flashall")) {
diff --git a/fastbootd/usb_linux_client.c b/fastbootd/usb_linux_client.c
index 64420e9..2c678b9 100644
--- a/fastbootd/usb_linux_client.c
+++ b/fastbootd/usb_linux_client.c
@@ -69,71 +69,85 @@
     struct transport_handle handle;
 };
 
-static const struct {
-    struct usb_functionfs_descs_head header;
-    struct {
-        struct usb_interface_descriptor intf;
-        struct usb_endpoint_descriptor_no_audio source;
-        struct usb_endpoint_descriptor_no_audio sink;
-    } __attribute__((packed)) fs_descs, hs_descs;
-} __attribute__((packed)) descriptors = {
-    .header = {
-        .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC),
-        .length = cpu_to_le32(sizeof(descriptors)),
-        .fs_count = 3,
-        .hs_count = 3,
+struct func_desc {
+    struct usb_interface_descriptor intf;
+    struct usb_endpoint_descriptor_no_audio source;
+    struct usb_endpoint_descriptor_no_audio sink;
+} __attribute__((packed));
+
+struct desc_v1 {
+    struct usb_functionfs_descs_head_v1 {
+        __le32 magic;
+        __le32 length;
+        __le32 fs_count;
+        __le32 hs_count;
+    } __attribute__((packed)) header;
+    struct func_desc fs_descs, hs_descs;
+} __attribute__((packed));
+
+struct desc_v2 {
+    struct usb_functionfs_descs_head_v2 {
+        __le32 magic;
+        __le32 length;
+        __le32 flags;
+        __le32 fs_count;
+        __le32 hs_count;
+        __le32 ss_count;
+    } __attribute__((packed)) header;
+    struct func_desc fs_descs, hs_descs;
+} __attribute__((packed));
+
+struct func_desc fs_descriptors = {
+    .intf = {
+        .bLength = sizeof(fs_descriptors.intf),
+        .bDescriptorType = USB_DT_INTERFACE,
+        .bInterfaceNumber = 0,
+        .bNumEndpoints = 2,
+        .bInterfaceClass = FASTBOOT_CLASS,
+        .bInterfaceSubClass = FASTBOOT_SUBCLASS,
+        .bInterfaceProtocol = FASTBOOT_PROTOCOL,
+        .iInterface = 1, /* first string from the provided table */
     },
-    .fs_descs = {
-        .intf = {
-            .bLength = sizeof(descriptors.fs_descs.intf),
-            .bDescriptorType = USB_DT_INTERFACE,
-            .bInterfaceNumber = 0,
-            .bNumEndpoints = 2,
-            .bInterfaceClass = FASTBOOT_CLASS,
-            .bInterfaceSubClass = FASTBOOT_SUBCLASS,
-            .bInterfaceProtocol = FASTBOOT_PROTOCOL,
-            .iInterface = 1, /* first string from the provided table */
-        },
-        .source = {
-            .bLength = sizeof(descriptors.fs_descs.source),
-            .bDescriptorType = USB_DT_ENDPOINT,
-            .bEndpointAddress = 1 | USB_DIR_OUT,
-            .bmAttributes = USB_ENDPOINT_XFER_BULK,
-            .wMaxPacketSize = MAX_PACKET_SIZE_FS,
-        },
-        .sink = {
-            .bLength = sizeof(descriptors.fs_descs.sink),
-            .bDescriptorType = USB_DT_ENDPOINT,
-            .bEndpointAddress = 2 | USB_DIR_IN,
-            .bmAttributes = USB_ENDPOINT_XFER_BULK,
-            .wMaxPacketSize = MAX_PACKET_SIZE_FS,
-        },
+    .source = {
+        .bLength = sizeof(fs_descriptors.source),
+        .bDescriptorType = USB_DT_ENDPOINT,
+        .bEndpointAddress = 1 | USB_DIR_OUT,
+        .bmAttributes = USB_ENDPOINT_XFER_BULK,
+        .wMaxPacketSize = MAX_PACKET_SIZE_FS,
     },
-    .hs_descs = {
-        .intf = {
-            .bLength = sizeof(descriptors.hs_descs.intf),
-            .bDescriptorType = USB_DT_INTERFACE,
-            .bInterfaceNumber = 0,
-            .bNumEndpoints = 2,
-            .bInterfaceClass = FASTBOOT_CLASS,
-            .bInterfaceSubClass = FASTBOOT_SUBCLASS,
-            .bInterfaceProtocol = FASTBOOT_PROTOCOL,
-            .iInterface = 1, /* first string from the provided table */
-        },
-        .source = {
-            .bLength = sizeof(descriptors.hs_descs.source),
-            .bDescriptorType = USB_DT_ENDPOINT,
-            .bEndpointAddress = 1 | USB_DIR_OUT,
-            .bmAttributes = USB_ENDPOINT_XFER_BULK,
-            .wMaxPacketSize = MAX_PACKET_SIZE_HS,
-        },
-        .sink = {
-            .bLength = sizeof(descriptors.hs_descs.sink),
-            .bDescriptorType = USB_DT_ENDPOINT,
-            .bEndpointAddress = 2 | USB_DIR_IN,
-            .bmAttributes = USB_ENDPOINT_XFER_BULK,
-            .wMaxPacketSize = MAX_PACKET_SIZE_HS,
-        },
+    .sink = {
+        .bLength = sizeof(fs_descriptors.sink),
+        .bDescriptorType = USB_DT_ENDPOINT,
+        .bEndpointAddress = 2 | USB_DIR_IN,
+        .bmAttributes = USB_ENDPOINT_XFER_BULK,
+        .wMaxPacketSize = MAX_PACKET_SIZE_FS,
+    },
+};
+
+struct func_desc hs_descriptors = {
+    .intf = {
+        .bLength = sizeof(hs_descriptors.intf),
+        .bDescriptorType = USB_DT_INTERFACE,
+        .bInterfaceNumber = 0,
+        .bNumEndpoints = 2,
+        .bInterfaceClass = FASTBOOT_CLASS,
+        .bInterfaceSubClass = FASTBOOT_SUBCLASS,
+        .bInterfaceProtocol = FASTBOOT_PROTOCOL,
+        .iInterface = 1, /* first string from the provided table */
+    },
+    .source = {
+        .bLength = sizeof(hs_descriptors.source),
+        .bDescriptorType = USB_DT_ENDPOINT,
+        .bEndpointAddress = 1 | USB_DIR_OUT,
+        .bmAttributes = USB_ENDPOINT_XFER_BULK,
+        .wMaxPacketSize = MAX_PACKET_SIZE_HS,
+    },
+    .sink = {
+        .bLength = sizeof(hs_descriptors.sink),
+        .bDescriptorType = USB_DT_ENDPOINT,
+        .bEndpointAddress = 2 | USB_DIR_IN,
+        .bmAttributes = USB_ENDPOINT_XFER_BULK,
+        .wMaxPacketSize = MAX_PACKET_SIZE_HS,
     },
 };
 
@@ -161,6 +175,17 @@
 static int init_functionfs(struct usb_transport *usb_transport)
 {
     ssize_t ret;
+    struct desc_v1 v1_descriptor;
+    struct desc_v2 v2_descriptor;
+
+    v2_descriptor.header.magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2);
+    v2_descriptor.header.length = cpu_to_le32(sizeof(v2_descriptor));
+    v2_descriptor.header.flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC;
+    v2_descriptor.header.fs_count = 3;
+    v2_descriptor.header.hs_count = 3;
+    v2_descriptor.header.ss_count = 0;
+    v2_descriptor.fs_descs = fs_descriptors;
+    v2_descriptor.hs_descs = hs_descriptors;
 
     D(VERBOSE, "OPENING %s", USB_FFS_FASTBOOT_EP0);
     usb_transport->control = open(USB_FFS_FASTBOOT_EP0, O_RDWR);
@@ -169,10 +194,20 @@
         goto err;
     }
 
-    ret = write(usb_transport->control, &descriptors, sizeof(descriptors));
+    ret = write(usb_transport->control, &v2_descriptor, sizeof(v2_descriptor));
     if (ret < 0) {
-        D(ERR, "[ %s: write descriptors failed: errno=%d ]", USB_FFS_FASTBOOT_EP0, errno);
-        goto err;
+        v1_descriptor.header.magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC);
+        v1_descriptor.header.length = cpu_to_le32(sizeof(v1_descriptor));
+        v1_descriptor.header.fs_count = 3;
+        v1_descriptor.header.hs_count = 3;
+        v1_descriptor.fs_descs = fs_descriptors;
+        v1_descriptor.hs_descs = hs_descriptors;
+        D(ERR, "[ %s: Switching to V1_descriptor format errno=%d ]\n", USB_FFS_FASTBOOT_EP0, errno);
+        ret = write(usb_transport->control, &v1_descriptor, sizeof(v1_descriptor));
+        if (ret < 0) {
+            D(ERR, "[ %s: write descriptors failed: errno=%d ]", USB_FFS_FASTBOOT_EP0, errno);
+            goto err;
+        }
     }
 
     ret = write(usb_transport->control, &strings, sizeof(strings));
diff --git a/healthd/healthd.cpp b/healthd/healthd.cpp
index 1fee855..b0002cc 100644
--- a/healthd/healthd.cpp
+++ b/healthd/healthd.cpp
@@ -53,6 +53,7 @@
     .batteryCurrentAvgPath = String8(String8::kEmptyString),
     .batteryChargeCounterPath = String8(String8::kEmptyString),
     .energyCounter = NULL,
+    .boot_min_cap = 0,
     .screen_on = NULL,
 };
 
diff --git a/healthd/healthd.h b/healthd/healthd.h
index 4704f0b..84b6d76 100644
--- a/healthd/healthd.h
+++ b/healthd/healthd.h
@@ -67,6 +67,7 @@
     android::String8 batteryChargeCounterPath;
 
     int (*energyCounter)(int64_t *);
+    int boot_min_cap;
     bool (*screen_on)(android::BatteryProperties *props);
 };
 
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
index 9ed5944..8931983 100644
--- a/healthd/healthd_mode_charger.cpp
+++ b/healthd/healthd_mode_charger.cpp
@@ -116,6 +116,7 @@
 
     struct animation *batt_anim;
     gr_surface surf_unknown;
+    int boot_min_cap;
 };
 
 static struct frame batt_anim_frames[] = {
@@ -520,19 +521,29 @@
                     LOGW("[%" PRId64 "] booting from charger mode\n", now);
                     property_set("sys.boot_from_charger_mode", "1");
                 } else {
-                    LOGW("[%" PRId64 "] rebooting\n", now);
-                    android_reboot(ANDROID_RB_RESTART, 0, 0);
+                    if (charger->batt_anim->capacity >= charger->boot_min_cap) {
+                        LOGW("[%" PRId64 "] rebooting\n", now);
+                        android_reboot(ANDROID_RB_RESTART, 0, 0);
+                    } else {
+                        LOGV("[%lld] ignore power-button press, battery level "
+                            "less than minimum\n", now);
+                    }
                 }
             } else {
                 /* if the key is pressed but timeout hasn't expired,
                  * make sure we wake up at the right-ish time to check
                  */
                 set_next_key_check(charger, key, POWER_ON_KEY_TIME);
+
+               /* Turn on the display and kick animation on power-key press
+                * rather than on key release
+                */
+                kick_animation(charger->batt_anim);
+                request_suspend(false);
             }
         } else {
             /* if the power key got released, force screen state cycle */
             if (key->pending) {
-                request_suspend(false);
                 kick_animation(charger->batt_anim);
             }
         }
@@ -555,6 +566,11 @@
         return;
 
     if (!charger->charger_connected) {
+
+        /* Last cycle would have stopped at the extreme top of battery-icon
+         * Need to show the correct level corresponding to capacity.
+         */
+        kick_animation(charger->batt_anim);
         request_suspend(false);
         if (charger->next_pwr_check == -1) {
             charger->next_pwr_check = now + UNPLUGGED_SHUTDOWN_TIME;
@@ -705,4 +721,5 @@
     charger->next_key_check = -1;
     charger->next_pwr_check = -1;
     healthd_config = config;
+    charger->boot_min_cap = config->boot_min_cap;
 }
diff --git a/init/init.c b/init/init.c
index 2b82937..269c11b 100644
--- a/init/init.c
+++ b/init/init.c
@@ -540,17 +540,35 @@
     return (list_tail(&act->commands) == &cmd->clist);
 }
 
+
+void build_triggers_string(char *name_str, int length, struct action *cur_action) {
+    struct listnode *node;
+    struct trigger *cur_trigger;
+
+    list_for_each(node, &cur_action->triggers) {
+        cur_trigger = node_to_item(node, struct trigger, nlist);
+        if (node != cur_action->triggers.next) {
+            strlcat(name_str, " " , length);
+        }
+        strlcat(name_str, cur_trigger->name , length);
+    }
+}
+
 void execute_one_command(void)
 {
     int ret, i;
     char cmd_str[256] = "";
+    char name_str[256] = "";
 
     if (!cur_action || !cur_command || is_last_command(cur_action, cur_command)) {
         cur_action = action_remove_queue_head();
         cur_command = NULL;
         if (!cur_action)
             return;
-        INFO("processing action %p (%s)\n", cur_action, cur_action->name);
+
+        build_triggers_string(name_str, sizeof(name_str), cur_action);
+
+        INFO("processing action %p (%s)\n", cur_action, name_str);
         cur_command = get_first_command(cur_action);
     } else {
         cur_command = get_next_command(cur_action, cur_command);
@@ -568,7 +586,7 @@
             }
         }
         INFO("command '%s' action=%s status=%d (%s:%d)\n",
-             cmd_str, cur_action ? cur_action->name : "", ret, cur_command->filename,
+             cmd_str, cur_action ? name_str : "", ret, cur_command->filename,
              cur_command->line);
     }
 }
diff --git a/init/init.h b/init/init.h
index a7615a3..e03bd53 100644
--- a/init/init.h
+++ b/init/init.h
@@ -37,6 +37,11 @@
     char *args[1];
 };
 
+struct trigger {
+    struct listnode nlist;
+    const char *name;
+};
+
 struct action {
         /* node in list of all actions */
     struct listnode alist;
@@ -46,12 +51,15 @@
     struct listnode tlist;
 
     unsigned hash;
-    const char *name;
 
+        /* list of actions which triggers the commands*/
+    struct listnode triggers;
     struct listnode commands;
     struct command *current;
 };
 
+void build_triggers_string(char *name_str, int length, struct action *cur_action);
+
 struct socketinfo {
     struct socketinfo *next;
     const char *name;
diff --git a/init/init_parser.c b/init/init_parser.c
index 2b4db8e..a124fa2 100644
--- a/init/init_parser.c
+++ b/init/init_parser.c
@@ -499,77 +499,92 @@
 void action_for_each_trigger(const char *trigger,
                              void (*func)(struct action *act))
 {
-    struct listnode *node;
+    struct listnode *node, *node2;
     struct action *act;
+    struct trigger *cur_trigger;
+
     list_for_each(node, &action_list) {
         act = node_to_item(node, struct action, alist);
-        if (!strcmp(act->name, trigger)) {
-            func(act);
+        list_for_each(node2, &act->triggers) {
+            cur_trigger = node_to_item(node2, struct trigger, nlist);
+            if (!strcmp(cur_trigger->name, trigger)) {
+                func(act);
+            }
         }
     }
 }
 
+
 void queue_property_triggers(const char *name, const char *value)
 {
-    struct listnode *node;
+    struct listnode *node, *node2;
     struct action *act;
+    struct trigger *cur_trigger;
+    bool match;
+    int name_length;
+
     list_for_each(node, &action_list) {
         act = node_to_item(node, struct action, alist);
-        if (!strncmp(act->name, "property:", strlen("property:"))) {
-            const char *test = act->name + strlen("property:");
-            int name_length = strlen(name);
+            match = !name;
+        list_for_each(node2, &act->triggers) {
+            cur_trigger = node_to_item(node2, struct trigger, nlist);
+            if (!strncmp(cur_trigger->name, "property:", strlen("property:"))) {
+                const char *test = cur_trigger->name + strlen("property:");
+                if (!match) {
+                    name_length = strlen(name);
+                    if (!strncmp(name, test, name_length) &&
+                        test[name_length] == '=' &&
+                        (!strcmp(test + name_length + 1, value) ||
+                        !strcmp(test + name_length + 1, "*"))) {
+                        match = true;
+                        continue;
+                    }
+                } else {
+                     const char* equals = strchr(test, '=');
+                     if (equals) {
+                         char prop_name[PROP_NAME_MAX + 1];
+                         char value[PROP_VALUE_MAX];
+                         int length = equals - test;
+                         if (length <= PROP_NAME_MAX) {
+                             int ret;
+                             memcpy(prop_name, test, length);
+                             prop_name[length] = 0;
 
-            if (!strncmp(name, test, name_length) &&
-                    test[name_length] == '=' &&
-                    (!strcmp(test + name_length + 1, value) ||
-                     !strcmp(test + name_length + 1, "*"))) {
-                action_add_queue_tail(act);
-            }
+                             /* does the property exist, and match the trigger value? */
+                             ret = property_get(prop_name, value);
+                             if (ret > 0 && (!strcmp(equals + 1, value) ||
+                                !strcmp(equals + 1, "*"))) {
+                                 continue;
+                             }
+                         }
+                     }
+                 }
+             }
+             match = false;
+             break;
+        }
+        if (match) {
+            action_add_queue_tail(act);
         }
     }
 }
 
 void queue_all_property_triggers()
 {
-    struct listnode *node;
-    struct action *act;
-    list_for_each(node, &action_list) {
-        act = node_to_item(node, struct action, alist);
-        if (!strncmp(act->name, "property:", strlen("property:"))) {
-            /* parse property name and value
-               syntax is property:<name>=<value> */
-            const char* name = act->name + strlen("property:");
-            const char* equals = strchr(name, '=');
-            if (equals) {
-                char prop_name[PROP_NAME_MAX + 1];
-                char value[PROP_VALUE_MAX];
-                int length = equals - name;
-                if (length > PROP_NAME_MAX) {
-                    ERROR("property name too long in trigger %s", act->name);
-                } else {
-                    int ret;
-                    memcpy(prop_name, name, length);
-                    prop_name[length] = 0;
-
-                    /* does the property exist, and match the trigger value? */
-                    ret = property_get(prop_name, value);
-                    if (ret > 0 && (!strcmp(equals + 1, value) ||
-                                    !strcmp(equals + 1, "*"))) {
-                        action_add_queue_tail(act);
-                    }
-                }
-            }
-        }
-    }
+    queue_property_triggers(NULL, NULL);
 }
 
 void queue_builtin_action(int (*func)(int nargs, char **args), char *name)
 {
     struct action *act;
     struct command *cmd;
+    struct trigger *cur_trigger;
 
     act = calloc(1, sizeof(*act));
-    act->name = name;
+    cur_trigger = calloc(1, sizeof(*cur_trigger));
+    cur_trigger->name = name;
+    list_init(&act->triggers);
+    list_add_tail(&act->triggers, &cur_trigger->nlist);
     list_init(&act->commands);
     list_init(&act->qlist);
 
@@ -611,6 +626,7 @@
 static void *parse_service(struct parse_state *state, int nargs, char **args)
 {
     struct service *svc;
+    struct trigger *cur_trigger;
     if (nargs < 3) {
         parse_error(state, "services must have a name and a program\n");
         return 0;
@@ -635,9 +651,12 @@
     svc->name = args[1];
     svc->classname = "default";
     memcpy(svc->args, args + 2, sizeof(char*) * nargs);
+    cur_trigger = calloc(1, sizeof(*cur_trigger));
     svc->args[nargs] = 0;
     svc->nargs = nargs;
-    svc->onrestart.name = "onrestart";
+    list_init(&svc->onrestart.triggers);
+    cur_trigger->name = "onrestart";
+    list_add_tail(&svc->onrestart.triggers, &cur_trigger->nlist);
     list_init(&svc->onrestart.commands);
     list_add_tail(&service_list, &svc->slist);
     return svc;
@@ -821,16 +840,29 @@
 static void *parse_action(struct parse_state *state, int nargs, char **args)
 {
     struct action *act;
+    struct trigger *cur_trigger;
+    int i;
     if (nargs < 2) {
         parse_error(state, "actions must have a trigger\n");
         return 0;
     }
-    if (nargs > 2) {
-        parse_error(state, "actions may not have extra parameters\n");
-        return 0;
-    }
+
     act = calloc(1, sizeof(*act));
-    act->name = args[1];
+    list_init(&act->triggers);
+
+    for (i = 1; i < nargs; i++) {
+        if (!(i % 2)) {
+            if (strcmp(args[i], "&&")) {
+                parse_error(state, "& is the only symbol allowed to concatenate actions\n");
+                return 0;
+            } else
+                continue;
+        }
+        cur_trigger = calloc(1, sizeof(*cur_trigger));
+        cur_trigger->name = args[i];
+        list_add_tail(&act->triggers, &cur_trigger->nlist);
+    }
+
     list_init(&act->commands);
     list_init(&act->qlist);
     list_add_tail(&action_list, &act->alist);
diff --git a/init/parser.c b/init/parser.c
index 48e7aec..80bfb09 100644
--- a/init/parser.c
+++ b/init/parser.c
@@ -15,9 +15,10 @@
     struct command *cmd;
     struct listnode *node;
     struct listnode *node2;
+    char name_str[256] = "";
     struct socketinfo *si;
     int n;
-    
+
     list_for_each(node, &service_list) {
         svc = node_to_item(node, struct service, slist);
         RAW("service %s\n", svc->name);
@@ -34,7 +35,11 @@
 
     list_for_each(node, &action_list) {
         act = node_to_item(node, struct action, alist);
-        RAW("on %s\n", act->name);
+        RAW("on ");
+        build_triggers_string(name_str, sizeof(name_str), act);
+        RAW("%s", name_str);
+        RAW("\n");
+
         list_for_each(node2, &act->commands) {
             cmd = node_to_item(node2, struct command, clist);
             RAW("  %p", cmd->func);
diff --git a/init/readme.txt b/init/readme.txt
index 750d953..0b43fd5 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -123,6 +123,15 @@
    Triggers of this form occur when the property <name> is set
    to the specific value <value>.
 
+   One can also test Mutliple properties to execute a group
+   of commands. For example:
+
+   on property:test.a=1 && property:test.b=1
+       setprop test.c 1
+
+   The above stub sets test.c to 1 only when
+   both test.a=1 and test.b=1
+
 Commands
 --------
 
diff --git a/libion/ion.c b/libion/ion.c
index a79525d..27ec47a 100644
--- a/libion/ion.c
+++ b/libion/ion.c
@@ -90,6 +90,7 @@
             int flags, off_t offset, unsigned char **ptr, int *map_fd)
 {
     int ret;
+    unsigned char *tmp_ptr;
     struct ion_fd_data data = {
         .handle = handle,
     };
@@ -102,16 +103,17 @@
     ret = ion_ioctl(fd, ION_IOC_MAP, &data);
     if (ret < 0)
         return ret;
-    *map_fd = data.fd;
-    if (*map_fd < 0) {
+    if (data.fd < 0) {
         ALOGE("map ioctl returned negative fd\n");
         return -EINVAL;
     }
-    *ptr = mmap(NULL, length, prot, flags, *map_fd, offset);
-    if (*ptr == MAP_FAILED) {
+    tmp_ptr = mmap(NULL, length, prot, flags, data.fd, offset);
+    if (tmp_ptr == MAP_FAILED) {
         ALOGE("mmap failed: %s\n", strerror(errno));
         return -errno;
     }
+    *map_fd = data.fd;
+    *ptr = tmp_ptr;
     return ret;
 }
 
@@ -128,11 +130,11 @@
     ret = ion_ioctl(fd, ION_IOC_SHARE, &data);
     if (ret < 0)
         return ret;
-    *share_fd = data.fd;
-    if (*share_fd < 0) {
+    if (data.fd < 0) {
         ALOGE("share ioctl returned negative fd\n");
         return -EINVAL;
     }
+    *share_fd = data.fd;
     return ret;
 }
 
diff --git a/rootdir/init.rc b/rootdir/init.rc
index cbcb842..9f444c1 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -520,6 +520,7 @@
     onrestart restart zygote
     onrestart restart media
     onrestart restart surfaceflinger
+    onrestart restart inputflinger
     onrestart restart drm
 
 service vold /system/bin/vold
@@ -553,6 +554,12 @@
     group graphics drmrpc
     onrestart restart zygote
 
+service inputflinger /system/bin/inputflinger
+    class main
+    user system
+    group input
+    onrestart restart zygote
+
 service drm /system/bin/drmserver
     class main
     user drm