Merge "Create world readable, system writeable /data/resource-cache."
diff --git a/adb/sockets.c b/adb/sockets.c
index aa4d5fc..f0357d6 100644
--- a/adb/sockets.c
+++ b/adb/sockets.c
@@ -221,10 +221,12 @@
     if(s->peer) {
         s->peer->peer = 0;
         // tweak to avoid deadlock
-        if (s->peer->close == local_socket_close)
+        if (s->peer->close == local_socket_close) {
             local_socket_close_locked(s->peer);
-        else
+        } else {
             s->peer->close(s->peer);
+        }
+        s->peer = 0;
     }
 
         /* If we are already closing, or if there are no
@@ -782,6 +784,7 @@
     if(s->peer) {
         s->peer->peer = 0;
         s->peer->close(s->peer);
+        s->peer = 0;
     }
     free(s);
 }
diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c
index d642566..28ba80d 100644
--- a/adb/usb_vendors.c
+++ b/adb/usb_vendors.c
@@ -87,6 +87,16 @@
 #define VENDOR_ID_PHILIPS       0x0471
 // Texas Instruments's USB Vendor ID
 #define VENDOR_ID_TI            0x0451
+// Funai's USB Vendor ID
+#define VENDOR_ID_FUNAI         0x0F1C
+// Gigabyte's USB Vendor ID
+#define VENDOR_ID_GIGABYTE      0x0414
+// IRiver's USB Vendor ID
+#define VENDOR_ID_IRIVER        0x2420
+// Compal's USB Vendor ID
+#define VENDOR_ID_COMPAL        0x1219
+// T & A Mobile Phones' USB Vendor ID
+#define VENDOR_ID_T_AND_A       0x1BBB
 
 
 /** built-in vendor list */
@@ -117,6 +127,11 @@
     VENDOR_ID_ASUS,
     VENDOR_ID_PHILIPS,
     VENDOR_ID_TI,
+    VENDOR_ID_FUNAI,
+    VENDOR_ID_GIGABYTE,
+    VENDOR_ID_IRIVER,
+    VENDOR_ID_COMPAL,
+    VENDOR_ID_T_AND_A,
 };
 
 #define BUILT_IN_VENDOR_COUNT    (sizeof(builtInVendorIds)/sizeof(builtInVendorIds[0]))
diff --git a/adb/usb_vendors.h b/adb/usb_vendors.h
index 43790b9..cee23a1 100644
--- a/adb/usb_vendors.h
+++ b/adb/usb_vendors.h
@@ -22,4 +22,4 @@
 
 void usb_vendors_init(void);
 
-#endif
\ No newline at end of file
+#endif
diff --git a/debuggerd/x86/unwind.c b/debuggerd/x86/unwind.c
index 8f84e01..0a7f04c 100644
--- a/debuggerd/x86/unwind.c
+++ b/debuggerd/x86/unwind.c
@@ -24,7 +24,6 @@
 
 //ebp==0, it indicates that the stack is poped to the bottom or there is no stack at all.
     while (ebp) {
-        _LOG(tfd, !at_fault, "#0%d ",stack_level);
         mi = pc_to_mapinfo(map, eip, &rel_pc);
 
         /* See if we can determine what symbol this stack frame resides in */
@@ -32,9 +31,11 @@
             sym = symbol_table_lookup(mi->symbols, rel_pc);
         }
         if (sym) {
-            _LOG(tfd, !at_fault, "    eip: %08x  %s (%s)\n", eip, mi ? mi->name : "", sym->name);
+            _LOG(tfd, !at_fault, "    #%02d  eip: %08x  %s (%s)\n",
+                 stack_level, eip, mi ? mi->name : "", sym->name);
         } else {
-            _LOG(tfd, !at_fault, "    eip: %08x  %s\n", eip, mi ? mi->name : "");
+            _LOG(tfd, !at_fault, "    #%02d  eip: %08x  %s\n",
+                 stack_level, eip, mi ? mi->name : "");
         }
 
         stack_level++;
@@ -49,7 +50,6 @@
     if (ebp)
         _LOG(tfd, !at_fault, "stack: \n");
     while (ebp) {
-        _LOG(tfd, !at_fault, "#0%d \n",stack_level);
         stack_ptr = cur_sp;
         while((int)(ebp - stack_ptr) >= 0) {
             stack_content = ptrace(PTRACE_PEEKTEXT, pid, (void*)stack_ptr, NULL);
@@ -60,10 +60,11 @@
                 sym = symbol_table_lookup(mi->symbols, rel_pc);
             }
             if (sym) {
-                _LOG(tfd, !at_fault, "    %08x  %08x  %s (%s)\n",
-                    stack_ptr, stack_content, mi ? mi->name : "", sym->name);
+                _LOG(tfd, !at_fault, "    #%02d  %08x  %08x  %s (%s)\n",
+                     stack_level, stack_ptr, stack_content, mi ? mi->name : "", sym->name);
             } else {
-                _LOG(tfd, !at_fault, "    %08x  %08x  %s\n", stack_ptr, stack_content, mi ? mi->name : "");
+                _LOG(tfd, !at_fault, "    #%02d  %08x  %08x  %s\n",
+                     stack_level, stack_ptr, stack_content, mi ? mi->name : "");
             }
 
             stack_ptr = stack_ptr + 4;
diff --git a/include/cutils/str_parms.h b/include/cutils/str_parms.h
new file mode 100644
index 0000000..247c996
--- /dev/null
+++ b/include/cutils/str_parms.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CUTILS_STR_PARMS_H
+#define __CUTILS_STR_PARMS_H
+
+#include <stdint.h>
+
+struct str_parms;
+
+struct str_parms *str_parms_create(void);
+struct str_parms *str_parms_create_str(const char *_string);
+void str_parms_destroy(struct str_parms *str_parms);
+
+void str_parms_del(struct str_parms *str_parms, const char *key);
+
+int str_parms_add_str(struct str_parms *str_parms, const char *key,
+                      const char *value);
+int str_parms_add_int(struct str_parms *str_parms, const char *key, int value);
+
+int str_parms_add_float(struct str_parms *str_parms, const char *key,
+                        float value);
+
+int str_parms_get_str(struct str_parms *str_parms, const char *key,
+                      char *out_val, int len);
+int str_parms_get_int(struct str_parms *str_parms, const char *key,
+                      int *out_val);
+int str_parms_get_float(struct str_parms *str_parms, const char *key,
+                        float *out_val);
+
+char *str_parms_to_str(struct str_parms *str_parms);
+
+/* debug */
+void str_parms_dump(struct str_parms *str_parms);
+
+#endif /* __CUTILS_STR_PARMS_H */
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index 8b739e9..84cccd9 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -46,7 +46,8 @@
 	properties.c \
 	threads.c \
 	sched_policy.c \
-	iosched_policy.c
+	iosched_policy.c \
+	str_parms.c
 
 commonHostSources := \
         ashmem-host.c
diff --git a/libcutils/str_parms.c b/libcutils/str_parms.c
new file mode 100644
index 0000000..dfa1f73
--- /dev/null
+++ b/libcutils/str_parms.c
@@ -0,0 +1,329 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "str_params"
+//#define LOG_NDEBUG 0
+
+#define _GNU_SOURCE 1
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <cutils/hashmap.h>
+#include <cutils/log.h>
+#include <cutils/memory.h>
+
+#include <cutils/str_parms.h>
+
+struct str_parms {
+    Hashmap *map;
+};
+
+
+static bool str_eq(void *key_a, void *key_b)
+{
+    return !strcmp((const char *)key_a, (const char *)key_b);
+}
+
+/* use djb hash unless we find it inadequate */
+static int str_hash_fn(void *str)
+{
+    uint32_t hash = 5381;
+    char *p;
+
+    for (p = str; p && *p; p++)
+        hash = ((hash << 5) + hash) + *p;
+    return (int)hash;
+}
+
+struct str_parms *str_parms_create(void)
+{
+    struct str_parms *str_parms;
+
+    str_parms = calloc(1, sizeof(struct str_parms));
+    if (!str_parms)
+        return NULL;
+
+    str_parms->map = hashmapCreate(5, str_hash_fn, str_eq);
+    if (!str_parms->map)
+        goto err;
+
+    return str_parms;
+
+err:
+    free(str_parms);
+    return NULL;
+}
+
+static bool remove_pair(void *key, void *value, void *context)
+{
+    struct str_parms *str_parms = context;
+
+    hashmapRemove(str_parms->map, key);
+    free(key);
+    free(value);
+    return true;
+}
+
+void str_parms_destroy(struct str_parms *str_parms)
+{
+    hashmapForEach(str_parms->map, remove_pair, str_parms);
+    hashmapFree(str_parms->map);
+    free(str_parms);
+}
+
+struct str_parms *str_parms_create_str(const char *_string)
+{
+    struct str_parms *str_parms;
+    char *str;
+    char *kvpair;
+    char *tmpstr;
+    int items = 0;
+
+    str_parms = str_parms_create();
+    if (!str_parms)
+        goto err_create_str_parms;
+
+    str = strdup(_string);
+    if (!str)
+        goto err_strdup;
+
+    LOGV("%s: source string == '%s'\n", __func__, _string);
+
+    kvpair = strtok_r(str, ";", &tmpstr);
+    while (kvpair && *kvpair) {
+        char *eq = strchr(kvpair, '='); /* would love strchrnul */
+        char *value;
+        char *key;
+        void *old_val;
+
+        if (eq == kvpair)
+            goto next_pair;
+
+        if (eq) {
+            key = strndup(kvpair, eq - kvpair);
+            if (*(++eq))
+                value = strdup(eq);
+            else
+                value = strdup("");
+        } else {
+            key = strdup(kvpair);
+            value = strdup("");
+        }
+
+        /* if we replaced a value, free it */
+        old_val = hashmapPut(str_parms->map, key, value);
+        if (old_val)
+            free(old_val);
+
+        items++;
+next_pair:
+        kvpair = strtok_r(NULL, ";", &tmpstr);
+    }
+
+    if (!items)
+        LOGV("%s: no items found in string\n", __func__);
+
+    free(str);
+
+    return str_parms;
+
+err_strdup:
+    str_parms_destroy(str_parms);
+err_create_str_parms:
+    return NULL;
+}
+
+void str_parms_del(struct str_parms *str_parms, const char *key)
+{
+    hashmapRemove(str_parms->map, (void *)key);
+}
+
+int str_parms_add_str(struct str_parms *str_parms, const char *key,
+                      const char *value)
+{
+    void *old_val;
+    char *tmp;
+
+    tmp = strdup(value);
+    old_val = hashmapPut(str_parms->map, (void *)key, tmp);
+
+    if (old_val) {
+        free(old_val);
+    } else if (errno == ENOMEM) {
+        free(tmp);
+        return -ENOMEM;
+    }
+    return 0;
+}
+
+int str_parms_add_int(struct str_parms *str_parms, const char *key, int value)
+{
+    char val_str[12];
+    int ret;
+
+    ret = snprintf(val_str, sizeof(val_str), "%d", value);
+    if (ret < 0)
+        return -EINVAL;
+
+    ret = str_parms_add_str(str_parms, key, val_str);
+    return ret;
+}
+
+int str_parms_add_float(struct str_parms *str_parms, const char *key,
+                        float value)
+{
+    char val_str[23];
+    int ret;
+
+    ret = snprintf(val_str, sizeof(val_str), "%.10f", value);
+    if (ret < 0)
+        return -EINVAL;
+
+    ret = str_parms_add_str(str_parms, key, val_str);
+    return ret;
+}
+
+int str_parms_get_str(struct str_parms *str_parms, const char *key, char *val,
+                      int len)
+{
+    char *value;
+
+    value = hashmapGet(str_parms->map, (void *)key);
+    if (value)
+        return strlcpy(val, value, len);
+
+    return -ENOENT;
+}
+
+int str_parms_get_int(struct str_parms *str_parms, const char *key, int *val)
+{
+    char *value;
+    char *end;
+
+    value = hashmapGet(str_parms->map, (void *)key);
+    if (!value)
+        return -ENOENT;
+
+    *val = (int)strtol(value, &end, 0);
+    if (*value != '\0' && *end == '\0')
+        return 0;
+
+    return -EINVAL;
+}
+
+int str_parms_get_float(struct str_parms *str_parms, const char *key,
+                        float *val)
+{
+    float out;
+    char *value;
+    char *end;
+
+    value = hashmapGet(str_parms->map, (void *)key);
+    if (!value)
+        return -ENOENT;
+
+    out = strtof(value, &end);
+    if (*value != '\0' && *end == '\0')
+        return 0;
+
+    return -EINVAL;
+}
+
+static bool combine_strings(void *key, void *value, void *context)
+{
+    char **old_str = context;
+    char *new_str;
+    int ret;
+
+    ret = asprintf(&new_str, "%s%s%s=%s",
+                   *old_str ? *old_str : "",
+                   *old_str ? ";" : "",
+                   (char *)key,
+                   (char *)value);
+    if (*old_str)
+        free(*old_str);
+
+    if (ret >= 0) {
+        *old_str = new_str;
+        return true;
+    }
+
+    *old_str = NULL;
+    return false;
+}
+
+char *str_parms_to_str(struct str_parms *str_parms)
+{
+    char *str = NULL;
+
+    if (hashmapSize(str_parms->map) > 0)
+        hashmapForEach(str_parms->map, combine_strings, &str);
+    else
+        str = strdup("");
+    return str;
+}
+
+static bool dump_entry(void *key, void *value, void *context)
+{
+    LOGI("key: '%s' value: '%s'\n", (char *)key, (char *)value);
+    return true;
+}
+
+void str_parms_dump(struct str_parms *str_parms)
+{
+    hashmapForEach(str_parms->map, dump_entry, str_parms);
+}
+
+#ifdef TEST_STR_PARMS
+static void test_str_parms_str(const char *str)
+{
+    struct str_parms *str_parms;
+    char *out_str;
+    int ret;
+
+    str_parms = str_parms_create_str(str);
+    str_parms_dump(str_parms);
+    out_str = str_parms_to_str(str_parms);
+    str_parms_destroy(str_parms);
+    LOGI("%s: '%s' stringified is '%s'", __func__, str, out_str);
+    free(out_str);
+}
+
+int main(void)
+{
+    struct str_parms *str_parms;
+
+    test_str_parms_str("");
+    test_str_parms_str(";");
+    test_str_parms_str("=");
+    test_str_parms_str("=;");
+    test_str_parms_str("=bar");
+    test_str_parms_str("=bar;");
+    test_str_parms_str("foo=");
+    test_str_parms_str("foo=;");
+    test_str_parms_str("foo=bar");
+    test_str_parms_str("foo=bar;");
+    test_str_parms_str("foo=bar;baz");
+    test_str_parms_str("foo=bar;baz=");
+    test_str_parms_str("foo=bar;baz=bat");
+    test_str_parms_str("foo=bar;baz=bat;");
+
+    return 0;
+}
+#endif
diff --git a/run-as/package.c b/run-as/package.c
index 46f8239..ca08436 100644
--- a/run-as/package.c
+++ b/run-as/package.c
@@ -44,7 +44,7 @@
 #define PACKAGES_LIST_FILE  "/data/system/packages.list"
 
 /* This should be large enough to hold the content of the package database file */
-#define PACKAGES_LIST_BUFFER_SIZE  8192
+#define PACKAGES_LIST_BUFFER_SIZE  65536
 
 /* Copy 'srclen' string bytes from 'src' into buffer 'dst' of size 'dstlen'
  * This function always zero-terminate the destination buffer unless
diff --git a/toolbox/ls.c b/toolbox/ls.c
index 962bf47..59ba35e 100644
--- a/toolbox/ls.c
+++ b/toolbox/ls.c
@@ -144,6 +144,7 @@
 #define LIST_RECURSIVE      (1 << 2)
 #define LIST_DIRECTORIES    (1 << 3)
 #define LIST_SIZE           (1 << 4)
+#define LIST_CLASSIFY       (1 << 6)
 
 // fwd
 static int listpath(const char *name, int flags);
@@ -253,7 +254,27 @@
     }
 
     /* blocks are 512 bytes, we want output to be KB */
-    printf("%lld %s\n", s.st_blocks / 2, filename);
+    if ((flags & LIST_SIZE) != 0) {
+        printf("%lld ", s.st_blocks / 2);
+    }
+
+    if ((flags & LIST_CLASSIFY) != 0) {
+        char filetype = mode2kind(s.st_mode);
+        if (filetype != 'l') {
+            printf("%c ", filetype);
+        } else {
+            struct stat link_dest;
+            if (!stat(path, &link_dest)) {
+                printf("l%c ", mode2kind(link_dest.st_mode));
+            } else {
+                fprintf(stderr, "stat '%s' failed: %s\n", path, strerror(errno));
+                printf("l? ");
+            }
+        }
+    }
+
+    printf("%s\n", filename);
+
     return 0;
 }
 
@@ -330,7 +351,7 @@
 
 static int listfile(const char *dirname, const char *filename, int flags)
 {
-    if ((flags & (LIST_LONG | LIST_SIZE)) == 0) {
+    if ((flags & (LIST_LONG | LIST_SIZE | LIST_CLASSIFY)) == 0) {
         printf("%s\n", filename);
         return 0;
     }
@@ -480,6 +501,7 @@
                     case 'R': flags |= LIST_RECURSIVE; break;
                     case 'd': flags |= LIST_DIRECTORIES; break;
                     case 'a': flags |= LIST_ALL; break;
+                    case 'F': flags |= LIST_CLASSIFY; break;
                     default:
                         fprintf(stderr, "%s: Unknown option '-%c'. Aborting.\n", "ls", arg[0]);
                         exit(1);