Merge "Define enum class for NetlinkEvent actions."
diff --git a/include/utils/Looper.h b/include/utils/Looper.h
index 5722c8e..a381251 100644
--- a/include/utils/Looper.h
+++ b/include/utils/Looper.h
@@ -420,9 +420,12 @@
     struct Request {
         int fd;
         int ident;
+        int events;
         int seq;
         sp<LooperCallback> callback;
         void* data;
+
+        void initEventItem(struct epoll_event* eventItem) const;
     };
 
     struct Response {
@@ -455,7 +458,8 @@
     // any use of it is racy anyway.
     volatile bool mPolling;
 
-    int mEpollFd; // immutable
+    int mEpollFd; // guarded by mLock but only modified on the looper thread
+    bool mEpollRebuildRequired; // guarded by mLock
 
     // Locked list of file descriptor monitoring requests.
     KeyedVector<int, Request> mRequests;  // guarded by mLock
@@ -471,9 +475,12 @@
     int removeFd(int fd, int seq);
     void awoken();
     void pushResponse(int events, const Request& request);
+    void rebuildEpollLocked();
+    void scheduleEpollRebuildLocked();
 
     static void initTLSKey();
     static void threadDestructor(void *st);
+    static void initEpollEvent(struct epoll_event* eventItem);
 };
 
 } // namespace android
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 86c9c2e..3d2e552 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -854,34 +854,6 @@
     return ret;
 }
 
-int do_setsebool(int nargs, char **args) {
-    const char *name = args[1];
-    const char *value = args[2];
-    SELboolean b;
-    int ret;
-
-    if (is_selinux_enabled() <= 0)
-        return 0;
-
-    b.name = name;
-    if (!strcmp(value, "1") || !strcasecmp(value, "true") || !strcasecmp(value, "on"))
-        b.value = 1;
-    else if (!strcmp(value, "0") || !strcasecmp(value, "false") || !strcasecmp(value, "off"))
-        b.value = 0;
-    else {
-        ERROR("setsebool: invalid value %s\n", value);
-        return -EINVAL;
-    }
-
-    if (security_set_boolean_list(1, &b, 0) < 0) {
-        ret = -errno;
-        ERROR("setsebool: could not set %s to %s\n", name, value);
-        return ret;
-    }
-
-    return 0;
-}
-
 int do_loglevel(int nargs, char **args) {
     int log_level;
     char log_level_str[PROP_VALUE_MAX] = "";
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index 5cd46fa..2ee4f86 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -190,7 +190,6 @@
         if (!strcmp(s, "etkey")) return K_setkey;
         if (!strcmp(s, "etprop")) return K_setprop;
         if (!strcmp(s, "etrlimit")) return K_setrlimit;
-        if (!strcmp(s, "etsebool")) return K_setsebool;
         if (!strcmp(s, "ocket")) return K_socket;
         if (!strcmp(s, "tart")) return K_start;
         if (!strcmp(s, "top")) return K_stop;
diff --git a/init/keywords.h b/init/keywords.h
index b203d2d..486e536 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -26,7 +26,6 @@
 int do_setkey(int nargs, char **args);
 int do_setprop(int nargs, char **args);
 int do_setrlimit(int nargs, char **args);
-int do_setsebool(int nargs, char **args);
 int do_start(int nargs, char **args);
 int do_stop(int nargs, char **args);
 int do_swapon_all(int nargs, char **args);
@@ -87,7 +86,6 @@
     KEYWORD(setkey,      COMMAND, 0, do_setkey)
     KEYWORD(setprop,     COMMAND, 2, do_setprop)
     KEYWORD(setrlimit,   COMMAND, 3, do_setrlimit)
-    KEYWORD(setsebool,   COMMAND, 2, do_setsebool)
     KEYWORD(socket,      OPTION,  0, 0)
     KEYWORD(start,       COMMAND, 1, do_start)
     KEYWORD(stop,        COMMAND, 1, do_stop)
diff --git a/init/readme.txt b/init/readme.txt
index 3af7924..fdcc9eb 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -238,10 +238,6 @@
 setrlimit <resource> <cur> <max>
    Set the rlimit for a resource.
 
-setsebool <name> <value>
-   Set SELinux boolean <name> to <value>.
-   <value> may be 1|true|on or 0|false|off
-
 start <service>
    Start a service running if it is not already running.
 
diff --git a/libutils/Looper.cpp b/libutils/Looper.cpp
index ac81090..d739f11 100644
--- a/libutils/Looper.cpp
+++ b/libutils/Looper.cpp
@@ -69,6 +69,7 @@
 
 Looper::Looper(bool allowNonCallbacks) :
         mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),
+        mPolling(false), mEpollFd(-1), mEpollRebuildRequired(false),
         mNextRequestSeq(0), mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {
     int wakeFds[2];
     int result = pipe(wakeFds);
@@ -85,25 +86,16 @@
     LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking.  errno=%d",
             errno);
 
-    mPolling = false;
-
-    // Allocate the epoll instance and register the wake pipe.
-    mEpollFd = epoll_create(EPOLL_SIZE_HINT);
-    LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance.  errno=%d", errno);
-
-    struct epoll_event eventItem;
-    memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
-    eventItem.events = EPOLLIN;
-    eventItem.data.fd = mWakeReadPipeFd;
-    result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem);
-    LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance.  errno=%d",
-            errno);
+    AutoMutex _l(mLock);
+    rebuildEpollLocked();
 }
 
 Looper::~Looper() {
     close(mWakeReadPipeFd);
     close(mWakeWritePipeFd);
-    close(mEpollFd);
+    if (mEpollFd >= 0) {
+        close(mEpollFd);
+    }
 }
 
 void Looper::initTLSKey() {
@@ -157,6 +149,50 @@
     return mAllowNonCallbacks;
 }
 
+void Looper::rebuildEpollLocked() {
+    // Close old epoll instance if we have one.
+    if (mEpollFd >= 0) {
+#if DEBUG_CALLBACKS
+        ALOGD("%p ~ rebuildEpollLocked - rebuilding epoll set", this);
+#endif
+        close(mEpollFd);
+    }
+
+    // Allocate the new epoll instance and register the wake pipe.
+    mEpollFd = epoll_create(EPOLL_SIZE_HINT);
+    LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance.  errno=%d", errno);
+
+    struct epoll_event eventItem;
+    memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
+    eventItem.events = EPOLLIN;
+    eventItem.data.fd = mWakeReadPipeFd;
+    int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem);
+    LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance.  errno=%d",
+            errno);
+
+    for (size_t i = 0; i < mRequests.size(); i++) {
+        const Request& request = mRequests.valueAt(i);
+        struct epoll_event eventItem;
+        request.initEventItem(&eventItem);
+
+        int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, request.fd, & eventItem);
+        if (epollResult < 0) {
+            ALOGE("Error adding epoll events for fd %d while rebuilding epoll set, errno=%d",
+                    request.fd, errno);
+        }
+    }
+}
+
+void Looper::scheduleEpollRebuildLocked() {
+    if (!mEpollRebuildRequired) {
+#if DEBUG_CALLBACKS
+        ALOGD("%p ~ scheduleEpollRebuildLocked - scheduling epoll set rebuild", this);
+#endif
+        mEpollRebuildRequired = true;
+        wake();
+    }
+}
+
 int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
     int result = 0;
     for (;;) {
@@ -229,6 +265,13 @@
     // Acquire lock.
     mLock.lock();
 
+    // Rebuild epoll set if needed.
+    if (mEpollRebuildRequired) {
+        mEpollRebuildRequired = false;
+        rebuildEpollLocked();
+        goto Done;
+    }
+
     // Check for poll error.
     if (eventCount < 0) {
         if (errno == EINTR) {
@@ -430,25 +473,20 @@
         ident = POLL_CALLBACK;
     }
 
-    int epollEvents = 0;
-    if (events & EVENT_INPUT) epollEvents |= EPOLLIN;
-    if (events & EVENT_OUTPUT) epollEvents |= EPOLLOUT;
-
     { // acquire lock
         AutoMutex _l(mLock);
 
         Request request;
         request.fd = fd;
         request.ident = ident;
+        request.events = events;
+        request.seq = mNextRequestSeq++;
         request.callback = callback;
         request.data = data;
-        request.seq = mNextRequestSeq++;
         if (mNextRequestSeq == -1) mNextRequestSeq = 0; // reserve sequence number -1
 
         struct epoll_event eventItem;
-        memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
-        eventItem.events = epollEvents;
-        eventItem.data.fd = fd;
+        request.initEventItem(&eventItem);
 
         ssize_t requestIndex = mRequests.indexOfKey(fd);
         if (requestIndex < 0) {
@@ -462,13 +500,19 @@
             int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, & eventItem);
             if (epollResult < 0) {
                 if (errno == ENOENT) {
-                    // Ignore ENOENT because it means that the file descriptor was
+                    // Tolerate ENOENT because it means that an older file descriptor was
                     // closed before its callback was unregistered and meanwhile a new
                     // file descriptor with the same number has been created and is now
-                    // being registered for the first time.  We tolerate the error since
-                    // it may occur naturally when a callback has the side-effect of
-                    // closing the file descriptor before returning and unregistering itself.
-                    // Callback sequence number checks further ensure that the race is benign.
+                    // being registered for the first time.  This error may occur naturally
+                    // when a callback has the side-effect of closing the file descriptor
+                    // before returning and unregistering itself.  Callback sequence number
+                    // checks further ensure that the race is benign.
+                    //
+                    // Unfortunately due to kernel limitations we need to rebuild the epoll
+                    // set from scratch because it may contain an old file handle that we are
+                    // now unable to remove since its file descriptor is no longer valid.
+                    // No such problem would have occurred if we were using the poll system
+                    // call instead, but that approach carries others disadvantages.
 #if DEBUG_CALLBACKS
                     ALOGD("%p ~ addFd - EPOLL_CTL_MOD failed due to file descriptor "
                             "being recycled, falling back on EPOLL_CTL_ADD, errno=%d",
@@ -480,6 +524,7 @@
                                 fd, errno);
                         return -1;
                     }
+                    scheduleEpollRebuildLocked();
                 } else {
                     ALOGE("Error modifying epoll events for fd %d, errno=%d", fd, errno);
                     return -1;
@@ -523,15 +568,22 @@
         int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, NULL);
         if (epollResult < 0) {
             if (seq != -1 && (errno == EBADF || errno == ENOENT)) {
-                // Ignore EBADF or ENOENT when the sequence number is known because it
+                // Tolerate EBADF or ENOENT when the sequence number is known because it
                 // means that the file descriptor was closed before its callback was
-                // unregistered.  We tolerate the error since it may occur naturally when
-                // a callback has the side-effect of closing the file descriptor before
-                // returning and unregistering itself.
+                // unregistered.  This error may occur naturally when a callback has the
+                // side-effect of closing the file descriptor before returning and
+                // unregistering itself.
+                //
+                // Unfortunately due to kernel limitations we need to rebuild the epoll
+                // set from scratch because it may contain an old file handle that we are
+                // now unable to remove since its file descriptor is no longer valid.
+                // No such problem would have occurred if we were using the poll system
+                // call instead, but that approach carries others disadvantages.
 #if DEBUG_CALLBACKS
                 ALOGD("%p ~ removeFd - EPOLL_CTL_DEL failed due to file descriptor "
-                        "being closed, ignoring error, errno=%d", this, errno);
+                        "being closed, errno=%d", this, errno);
 #endif
+                scheduleEpollRebuildLocked();
             } else {
                 ALOGE("Error removing epoll events for fd %d, errno=%d", fd, errno);
                 return -1;
@@ -625,4 +677,14 @@
     return mPolling;
 }
 
+void Looper::Request::initEventItem(struct epoll_event* eventItem) const {
+    int epollEvents = 0;
+    if (events & EVENT_INPUT) epollEvents |= EPOLLIN;
+    if (events & EVENT_OUTPUT) epollEvents |= EPOLLOUT;
+
+    memset(eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
+    eventItem->events = epollEvents;
+    eventItem->data.fd = fd;
+}
+
 } // namespace android
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index 2c7544c..424ba23 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -44,7 +44,6 @@
     df \
     getevent \
     getprop \
-    getsebool \
     iftop \
     ioctl \
     ionice \
@@ -64,7 +63,6 @@
     schedtop \
     sendevent \
     setprop \
-    setsebool \
     smd \
     start \
     stop \
diff --git a/toolbox/getsebool.c b/toolbox/getsebool.c
deleted file mode 100644
index aab5200..0000000
--- a/toolbox/getsebool.c
+++ /dev/null
@@ -1,104 +0,0 @@
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <getopt.h>
-#include <errno.h>
-#include <string.h>
-#include <selinux/selinux.h>
-
-static void usage(const char *progname)
-{
-    fprintf(stderr, "usage:  %s -a or %s boolean...\n", progname, progname);
-    exit(1);
-}
-
-int getsebool_main(int argc, char **argv)
-{
-    int i, get_all = 0, rc = 0, active, pending, len = 0, opt;
-    char **names;
-
-    while ((opt = getopt(argc, argv, "a")) > 0) {
-        switch (opt) {
-        case 'a':
-            if (argc > 2)
-                usage(argv[0]);
-            if (is_selinux_enabled() <= 0) {
-                fprintf(stderr, "%s:  SELinux is disabled\n",
-                        argv[0]);
-                return 1;
-            }
-            errno = 0;
-            rc = security_get_boolean_names(&names, &len);
-            if (rc) {
-                fprintf(stderr,
-                        "%s:  Unable to get boolean names:  %s\n",
-                        argv[0], strerror(errno));
-                return 1;
-            }
-            if (!len) {
-                printf("No booleans\n");
-                return 0;
-            }
-            get_all = 1;
-            break;
-        default:
-            usage(argv[0]);
-        }
-    }
-
-    if (is_selinux_enabled() <= 0) {
-        fprintf(stderr, "%s:  SELinux is disabled\n", argv[0]);
-        return 1;
-    }
-    if (!len) {
-        if (argc < 2)
-            usage(argv[0]);
-        len = argc - 1;
-        names = malloc(sizeof(char *) * len);
-        if (!names) {
-            fprintf(stderr, "%s:  out of memory\n", argv[0]);
-            return 2;
-        }
-        for (i = 0; i < len; i++) {
-            names[i] = strdup(argv[i + 1]);
-            if (!names[i]) {
-                fprintf(stderr, "%s:  out of memory\n",
-                        argv[0]);
-                return 2;
-            }
-        }
-    }
-
-    for (i = 0; i < len; i++) {
-        active = security_get_boolean_active(names[i]);
-        if (active < 0) {
-            if (get_all && errno == EACCES)
-                continue;
-            fprintf(stderr, "Error getting active value for %s\n",
-                    names[i]);
-            rc = -1;
-            goto out;
-        }
-        pending = security_get_boolean_pending(names[i]);
-        if (pending < 0) {
-            fprintf(stderr, "Error getting pending value for %s\n",
-                    names[i]);
-            rc = -1;
-            goto out;
-        }
-        if (pending != active) {
-            printf("%s --> %s pending: %s\n", names[i],
-                   (active ? "on" : "off"),
-                   (pending ? "on" : "off"));
-        } else {
-            printf("%s --> %s\n", names[i],
-                   (active ? "on" : "off"));
-        }
-    }
-
-out:
-    for (i = 0; i < len; i++)
-        free(names[i]);
-    free(names);
-    return rc;
-}
diff --git a/toolbox/setsebool.c b/toolbox/setsebool.c
deleted file mode 100644
index f79a612..0000000
--- a/toolbox/setsebool.c
+++ /dev/null
@@ -1,46 +0,0 @@
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <selinux/selinux.h>
-#include <errno.h>
-
-static int do_setsebool(int nargs, char **args) {
-    const char *name = args[1];
-    const char *value = args[2];
-    SELboolean b;
-
-    if (is_selinux_enabled() <= 0)
-        return 0;
-
-    b.name = name;
-    if (!strcmp(value, "1") || !strcasecmp(value, "true") || !strcasecmp(value, "on"))
-        b.value = 1;
-    else if (!strcmp(value, "0") || !strcasecmp(value, "false") || !strcasecmp(value, "off"))
-        b.value = 0;
-    else {
-        fprintf(stderr, "setsebool: invalid value %s\n", value);
-        return -1;
-    }
-
-    if (security_set_boolean_list(1, &b, 0) < 0)
-    {
-        fprintf(stderr, "setsebool: could not set %s to %s:  %s", name, value, strerror(errno));
-        return -1;
-    }
-
-    return 0;
-}
-
-int setsebool_main(int argc, char **argv)
-{
-    if (argc != 3) {
-        fprintf(stderr, "Usage:  %s name value\n", argv[0]);
-        exit(1);
-    }
-
-    return do_setsebool(argc, argv);
-}