auto import from //depot/cupcake/@135843
diff --git a/vold/uevent.c b/vold/uevent.c
new file mode 100644
index 0000000..b1a6944
--- /dev/null
+++ b/vold/uevent.c
@@ -0,0 +1,443 @@
+
+/*
+ * Copyright (C) 2008 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.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "vold.h"
+#include "uevent.h"
+#include "mmc.h"
+#include "blkdev.h"
+#include "volmgr.h"
+#include "media.h"
+
+#define DEBUG_UEVENT 0
+
+#define UEVENT_PARAMS_MAX 32
+
+enum uevent_action { action_add, action_remove, action_change };
+
+struct uevent {
+    char *path;
+    enum uevent_action action;
+    char *subsystem;
+    char *param[UEVENT_PARAMS_MAX];
+    unsigned int seqnum;
+};
+
+struct uevent_dispatch {
+    char *subsystem;
+    int (* dispatch) (struct uevent *);
+};
+
+static void dump_uevent(struct uevent *);
+static int dispatch_uevent(struct uevent *event);
+static void free_uevent(struct uevent *event);
+static char *get_uevent_param(struct uevent *event, char *param_name);
+
+static int handle_powersupply_event(struct uevent *event);
+static int handle_switch_event(struct uevent *);
+static int handle_battery_event(struct uevent *);
+static int handle_mmc_event(struct uevent *);
+static int handle_block_event(struct uevent *);
+static int handle_bdi_event(struct uevent *);
+static void _cb_blkdev_ok_to_destroy(blkdev_t *dev);
+
+static struct uevent_dispatch dispatch_table[] = {
+    { "switch", handle_switch_event }, 
+    { "battery", handle_battery_event }, 
+    { "mmc", handle_mmc_event },
+    { "block", handle_block_event },
+    { "bdi", handle_bdi_event },
+    { "power_supply", handle_powersupply_event },
+    { NULL, NULL }
+};
+
+static boolean low_batt = false;
+static boolean door_open = true;
+
+int process_uevent_message(int socket)
+{
+    char buffer[64 * 1024]; // Thank god we're not in the kernel :)
+    int count;
+    char *s = buffer;
+    char *end;
+    struct uevent *event;
+    int param_idx = 0;
+    int i;
+    int first = 1;
+    int rc = 0;
+
+    if ((count = recv(socket, buffer, sizeof(buffer), 0)) < 0) {
+        LOGE("Error receiving uevent (%s)", strerror(errno));
+        return -errno;
+    }
+
+    if (!(event = malloc(sizeof(struct uevent)))) {
+        LOGE("Error allocating memory (%s)", strerror(errno));
+        return -errno;
+    }
+
+    memset(event, 0, sizeof(struct uevent));
+
+    end = s + count;
+    while (s < end) {
+        if (first) {
+            char *p;
+            for (p = s; *p != '@'; p++);
+            p++;
+            event->path = strdup(p);
+            first = 0;
+        } else {
+            if (!strncmp(s, "ACTION=", strlen("ACTION="))) {
+                char *a = s + strlen("ACTION=");
+               
+                if (!strcmp(a, "add"))
+                    event->action = action_add;
+                else if (!strcmp(a, "change"))
+                    event->action = action_change;
+                else if (!strcmp(a, "remove"))
+                    event->action = action_remove;
+            } else if (!strncmp(s, "SEQNUM=", strlen("SEQNUM=")))
+                event->seqnum = atoi(s + strlen("SEQNUM="));
+            else if (!strncmp(s, "SUBSYSTEM=", strlen("SUBSYSTEM=")))
+                event->subsystem = strdup(s + strlen("SUBSYSTEM="));
+            else
+                event->param[param_idx++] = strdup(s);
+        }
+        s+= strlen(s) + 1;
+    }
+
+    rc = dispatch_uevent(event);
+    
+    free_uevent(event);
+    return rc;
+}
+
+int simulate_uevent(char *subsys, char *path, char *action, char **params)
+{
+    struct uevent *event;
+    char tmp[255];
+    int i, rc;
+
+    if (!(event = malloc(sizeof(struct uevent)))) {
+        LOGE("Error allocating memory (%s)", strerror(errno));
+        return -errno;
+    }
+
+    memset(event, 0, sizeof(struct uevent));
+
+    event->subsystem = strdup(subsys);
+
+    if (!strcmp(action, "add"))
+        event->action = action_add;
+    else if (!strcmp(action, "change"))
+        event->action = action_change;
+    else if (!strcmp(action, "remove"))
+        event->action = action_remove;
+    else {
+        LOGE("Invalid action '%s'", action);
+        return -1;
+    }
+
+    event->path = strdup(path);
+
+    for (i = 0; i < UEVENT_PARAMS_MAX; i++) {
+        if (!params[i])
+            break;
+        event->param[i] = strdup(params[i]);
+    }
+
+    rc = dispatch_uevent(event);
+    free_uevent(event);
+    return rc;
+}
+
+static int dispatch_uevent(struct uevent *event)
+{
+    int i;
+
+#if DEBUG_UEVENT
+    dump_uevent(event);
+#endif
+    for (i = 0; dispatch_table[i].subsystem != NULL; i++) {
+        if (!strcmp(dispatch_table[i].subsystem, event->subsystem))
+            return dispatch_table[i].dispatch(event);
+    }
+
+#if DEBUG_UEVENT
+    LOG_VOL("No uevent handlers registered for '%s' subsystem", event->subsystem);
+#endif
+    return 0;
+}
+
+static void dump_uevent(struct uevent *event)
+{
+    int i;
+
+    LOG_VOL("[UEVENT] Sq: %u S: %s A: %d P: %s",
+              event->seqnum, event->subsystem, event->action, event->path);
+    for (i = 0; i < UEVENT_PARAMS_MAX; i++) {
+        if (!event->param[i])
+            break;
+        LOG_VOL("%s", event->param[i]);
+    }
+}
+
+static void free_uevent(struct uevent *event)
+{
+    int i;
+    free(event->path);
+    free(event->subsystem);
+    for (i = 0; i < UEVENT_PARAMS_MAX; i++) {
+        if (!event->param[i])
+            break;
+        free(event->param[i]);
+    }
+    free(event);
+}
+
+static char *get_uevent_param(struct uevent *event, char *param_name)
+{
+    int i;
+
+    for (i = 0; i < UEVENT_PARAMS_MAX; i++) {
+        if (!event->param[i])
+            break;
+        if (!strncmp(event->param[i], param_name, strlen(param_name)))
+            return &event->param[i][strlen(param_name) + 1];
+    }
+
+    LOGE("get_uevent_param(): No parameter '%s' found", param_name);
+    return NULL;
+}
+
+/*
+ * ---------------
+ * Uevent Handlers
+ * ---------------
+ */
+
+static int handle_powersupply_event(struct uevent *event)
+{
+    char *ps_type = get_uevent_param(event, "POWER_SUPPLY_TYPE");
+    char *ps_cap = get_uevent_param(event, "POWER_SUPPLY_CAPACITY");
+
+    if (!strcasecmp(ps_type, "battery")) {
+        int capacity = atoi(ps_cap);
+  
+        if (capacity < 5)
+            low_batt = true;
+        else
+            low_batt = false;
+LOG_VOL("handle_powersupply_event(): low_batt = %d, door_open = %d", low_batt, door_open);
+        volmgr_safe_mode(low_batt || door_open);
+    }
+    return 0;
+}
+
+static int handle_switch_event(struct uevent *event)
+{
+    char *name = get_uevent_param(event, "SWITCH_NAME");
+    char *state = get_uevent_param(event, "SWITCH_STATE");
+
+
+    if (!strcmp(name, "usb_mass_storage")) {
+        if (!strcmp(state, "online")) {
+            ums_hostconnected_set(true);
+        } else {
+            ums_hostconnected_set(false);
+            volmgr_enable_ums(false);
+        }
+    } else if (!strcmp(name, "sd-door")) {
+        if (!strcmp(state, "open"))
+            door_open = true;
+        else
+            door_open = false;
+LOG_VOL("handle_powersupply_event(): low_batt = %d, door_open = %d", low_batt, door_open);
+        volmgr_safe_mode(low_batt || door_open);
+    } else
+        LOG_VOL("handle_switch_event(): Ignoring switch '%s'", name);
+
+    return 0;
+}
+
+static int handle_battery_event(struct uevent *event)
+{
+    return 0;
+}
+
+static int handle_block_event(struct uevent *event)
+{
+    char mediapath[255];
+    media_t *media;
+    int n;
+    int maj, min;
+    blkdev_t *blkdev;
+
+    /*
+     * Look for backing media for this block device
+     */
+    if (!strncmp(get_uevent_param(event, "DEVPATH"),
+                 "/devices/virtual/",
+                 strlen("/devices/virtual/"))) {
+        n = 0;
+    } else if (!strcmp(get_uevent_param(event, "DEVTYPE"), "disk"))
+        n = 2;
+    else if (!strcmp(get_uevent_param(event, "DEVTYPE"), "partition"))
+        n = 3;
+    else {
+        LOGE("Bad blockdev type '%s'", get_uevent_param(event, "DEVTYPE"));
+        return -EINVAL;
+    }
+
+    truncate_sysfs_path(event->path, n, mediapath);
+
+    if (!(media = media_lookup_by_path(mediapath, false))) {
+#if DEBUG_UEVENT
+        LOG_VOL("No backend media found @ device path '%s'", mediapath);
+#endif
+        return 0;
+    }
+
+    maj = atoi(get_uevent_param(event, "MAJOR"));
+    min = atoi(get_uevent_param(event, "MINOR"));
+
+    if (event->action == action_add) {
+        blkdev_t *disk;
+
+        /*
+         * If there isn't a disk already its because *we*
+         * are the disk
+         */
+        disk = blkdev_lookup_by_devno(maj, 0);
+
+        if (!(blkdev = blkdev_create(disk,
+                                     event->path,
+                                     maj,
+                                     min,
+                                     media,
+                                     get_uevent_param(event, "DEVTYPE")))) {
+            LOGE("Unable to allocate new blkdev (%m)");
+            return -1;
+        }
+
+        blkdev_refresh(blkdev);
+
+        /*
+         * Add the blkdev to media
+         */
+        int rc;
+        if ((rc = media_add_blkdev(media, blkdev)) < 0) {
+            LOGE("Unable to add blkdev to card (%d)", rc);
+            return rc;
+        }
+
+        LOG_VOL("New blkdev %d.%d on media %s, media path %s, Dpp %d",
+                blkdev->major, blkdev->minor, media->name, mediapath,
+                blkdev_get_num_pending_partitions(blkdev->disk));
+
+        if (blkdev_get_num_pending_partitions(blkdev->disk) == 0) {
+            if ((rc = volmgr_consider_disk(blkdev->disk)) < 0) {
+                LOGE("Volmgr failed to handle device (%d)", rc);
+                return rc;
+            }
+        }
+    } else if (event->action == action_remove) {
+        if (!(blkdev = blkdev_lookup_by_devno(maj, min)))
+            return 0;
+
+        LOG_VOL("Destroying blkdev %d.%d @ %s on media %s", blkdev->major,
+                blkdev->minor, blkdev->devpath, media->name);
+        volmgr_notify_eject(blkdev, _cb_blkdev_ok_to_destroy);
+
+    } else if (event->action == action_change) {
+        if (!(blkdev = blkdev_lookup_by_devno(maj, min)))
+            return 0;
+
+        LOG_VOL("Modified blkdev %d.%d @ %s on media %s", blkdev->major,
+                blkdev->minor, blkdev->devpath, media->name);
+        
+        blkdev_refresh(blkdev);
+    } else  {
+#if DEBUG_UEVENT
+        LOG_VOL("No handler implemented for action %d", event->action);
+#endif
+    }
+    return 0;
+}
+
+static void _cb_blkdev_ok_to_destroy(blkdev_t *dev)
+{
+    media_t *media = media_lookup_by_dev(dev);
+    if (media)
+        media_remove_blkdev(media, dev);
+    blkdev_destroy(dev);
+}
+
+static int handle_bdi_event(struct uevent *event)
+{
+    return 0;
+}
+
+static int handle_mmc_event(struct uevent *event)
+{
+    if (event->action == action_add) {
+        media_t *media;
+        char serial[80];
+        char *type;
+
+        /*
+         * Pull card information from sysfs
+         */
+        type = get_uevent_param(event, "MMC_TYPE");
+        if (strcmp(type, "SD") && strcmp(type, "MMC"))
+            return 0;
+        
+        read_sysfs_var(serial, sizeof(serial), event->path, "serial");
+        if (!(media = media_create(event->path,
+                                   get_uevent_param(event, "MMC_NAME"),
+                                   serial,
+                                   media_mmc))) {
+            LOGE("Unable to allocate new media (%m)");
+            return -1;
+        }
+        LOG_VOL("New MMC card '%s' (serial %u) added @ %s", media->name,
+                  media->serial, media->devpath);
+    } else if (event->action == action_remove) {
+        media_t *media;
+
+        if (!(media = media_lookup_by_path(event->path, false))) {
+            LOGE("Unable to lookup media '%s'", event->path);
+            return -1;
+        }
+
+        LOG_VOL("MMC card '%s' (serial %u) @ %s removed", media->name, 
+                  media->serial, media->devpath);
+        media_destroy(media);
+    } else {
+#if DEBUG_UEVENT
+        LOG_VOL("No handler implemented for action %d", event->action);
+#endif
+    }
+
+    return 0;
+}