Merge "Change tzdatacheck to account for bundle format changes"
diff --git a/adb/Android.mk b/adb/Android.mk
index 16ed991..fab8c87 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -330,6 +330,7 @@
 LOCAL_STATIC_LIBRARIES := \
     libadbd \
     libbase \
+    libbootloader_message \
     libfs_mgr \
     libfec \
     libfec_rs \
diff --git a/adb/services.cpp b/adb/services.cpp
index 2fbc15a..df1b134 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -39,6 +39,7 @@
 
 #if !ADB_HOST
 #include <android-base/properties.h>
+#include <bootloader_message/bootloader_message.h>
 #include <cutils/android_reboot.h>
 #include <private/android_logger.h>
 #endif
@@ -133,17 +134,12 @@
             return false;
         }
 
-        const char* const recovery_dir = "/cache/recovery";
-        const char* const command_file = "/cache/recovery/command";
-        // Ensure /cache/recovery exists.
-        if (adb_mkdir(recovery_dir, 0770) == -1 && errno != EEXIST) {
-            D("Failed to create directory '%s': %s", recovery_dir, strerror(errno));
-            return false;
-        }
-
-        bool write_status = android::base::WriteStringToFile(
-                auto_reboot ? "--sideload_auto_reboot" : "--sideload", command_file);
-        if (!write_status) {
+        const std::vector<std::string> options = {
+            auto_reboot ? "--sideload_auto_reboot" : "--sideload"
+        };
+        std::string err;
+        if (!write_bootloader_message(options, &err)) {
+            D("Failed to set bootloader message: %s", err.c_str());
             return false;
         }
 
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index 7c0e85d..483c01d 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -207,6 +207,19 @@
   return boot_complete_prefix;
 }
 
+// Records the value of a given ro.boottime.init property in milliseconds.
+void RecordInitBootTimeProp(
+    BootEventRecordStore* boot_event_store, const char* property) {
+  std::string value = GetProperty(property);
+
+  int32_t time_in_ns;
+  if (android::base::ParseInt(value, &time_in_ns)) {
+    static constexpr int32_t kNanosecondsPerMillisecond = 1e6;
+    int32_t time_in_ms = static_cast<int32_t>(time_in_ns / kNanosecondsPerMillisecond);
+    boot_event_store->AddBootEventWithValue(property, time_in_ms);
+  }
+}
+
 // Records several metrics related to the time it takes to boot the device,
 // including disambiguating boot time on encrypted or non-encrypted devices.
 void RecordBootComplete() {
@@ -256,6 +269,10 @@
   // Record the total time from device startup to boot complete, regardless of
   // encryption state.
   boot_event_store.AddBootEventWithValue(boot_complete_prefix, uptime);
+
+  RecordInitBootTimeProp(&boot_event_store, "ro.boottime.init");
+  RecordInitBootTimeProp(&boot_event_store, "ro.boottime.init.selinux");
+  RecordInitBootTimeProp(&boot_event_store, "ro.boottime.init.cold_boot_wait");
 }
 
 // Records the boot_reason metric by querying the ro.boot.bootreason system
diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk
index d6b699b..8997cab 100644
--- a/fs_mgr/Android.mk
+++ b/fs_mgr/Android.mk
@@ -32,6 +32,11 @@
 LOCAL_STATIC_LIBRARIES := $(common_static_libraries)
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 LOCAL_CFLAGS := -Werror
+ifeq ($(TARGET_USERIMAGES_USE_EXT4), true)
+  ifeq ($(TARGET_USES_MKE2FS), true)
+    LOCAL_CFLAGS += -DTARGET_USES_MKE2FS
+  endif
+endif
 ifneq (,$(filter userdebug,$(TARGET_BUILD_VARIANT)))
 LOCAL_CFLAGS += -DALLOW_ADBD_DISABLE_VERITY=1
 endif
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index ba44a5a..7fac2fb 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -101,7 +101,9 @@
     char tmpmnt_opts[64] = "errors=remount-ro";
     char *e2fsck_argv[] = {
         E2FSCK_BIN,
+#ifndef TARGET_USES_MKE2FS // "-f" only for old ext4 generation tool
         "-f",
+#endif
         "-y",
         blk_device
     };
@@ -701,7 +703,7 @@
         }
 
         if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
-            int rc = fs_mgr_setup_verity(&fstab->recs[i]);
+            int rc = fs_mgr_setup_verity(&fstab->recs[i], true);
             if (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
                 INFO("Verity disabled");
             } else if (rc != FS_MGR_SETUP_VERITY_SUCCESS) {
@@ -870,7 +872,7 @@
         }
 
         if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
-            int rc = fs_mgr_setup_verity(&fstab->recs[i]);
+            int rc = fs_mgr_setup_verity(&fstab->recs[i], true);
             if (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
                 INFO("Verity disabled");
             } else if (rc != FS_MGR_SETUP_VERITY_SUCCESS) {
@@ -1086,7 +1088,7 @@
 int fs_mgr_early_setup_verity(struct fstab_rec *fstab_rec)
 {
     if ((fstab_rec->fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
-        int rc = fs_mgr_setup_verity(fstab_rec);
+        int rc = fs_mgr_setup_verity(fstab_rec, false);
         if (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
             INFO("Verity disabled");
             return FS_MGR_EARLY_SETUP_VERITY_NO_VERITY;
diff --git a/fs_mgr/fs_mgr_priv_verity.h b/fs_mgr/fs_mgr_priv_verity.h
index d9e17bb..1a6d215 100644
--- a/fs_mgr/fs_mgr_priv_verity.h
+++ b/fs_mgr/fs_mgr_priv_verity.h
@@ -22,6 +22,6 @@
 
 __BEGIN_DECLS
 
-int fs_mgr_setup_verity(struct fstab_rec *fstab);
+int fs_mgr_setup_verity(struct fstab_rec *fstab, bool verify_dev);
 
 __END_DECLS
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 031b042..30c9731 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -892,7 +892,7 @@
     *table = strdup(result.c_str());
 }
 
-int fs_mgr_setup_verity(struct fstab_rec *fstab)
+int fs_mgr_setup_verity(struct fstab_rec *fstab, bool verify_dev)
 {
     int retval = FS_MGR_SETUP_VERITY_FAIL;
     int fd = -1;
@@ -1043,7 +1043,7 @@
     verity_blk_name = 0;
 
     // make sure we've set everything up properly
-    if (test_access(fstab->blk_device) < 0) {
+    if (verify_dev && test_access(fstab->blk_device) < 0) {
         goto out;
     }
 
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index f7cf9b8..eb71fb8 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -173,104 +173,15 @@
 #define AID_USER            100000 /* TODO: switch users over to AID_USER_OFFSET */
 #define AID_USER_OFFSET     100000 /* offset for uid ranges for each user */
 
-#if !defined(EXCLUDE_FS_CONFIG_STRUCTURES)
 /*
- * Used in:
- *  bionic/libc/bionic/stubs.cpp
- *  external/libselinux/src/android.c
- *  system/core/logd/LogStatistics.cpp
- *  system/core/init/ueventd.cpp
- *  system/core/init/util.cpp
+ * android_ids has moved to pwd/grp functionality.
+ * If you need to add one, the structure is now
+ * auto-generated based on the AID_ constraints
+ * documented at the top of this header file.
+ * Also see build/tools/fs_config for more details.
  */
-struct android_id_info {
-    const char *name;
-    unsigned aid;
-};
 
-static const struct android_id_info android_ids[] = {
-    { "root",          AID_ROOT, },
-
-    { "system",        AID_SYSTEM, },
-
-    { "radio",         AID_RADIO, },
-    { "bluetooth",     AID_BLUETOOTH, },
-    { "graphics",      AID_GRAPHICS, },
-    { "input",         AID_INPUT, },
-    { "audio",         AID_AUDIO, },
-    { "camera",        AID_CAMERA, },
-    { "log",           AID_LOG, },
-    { "compass",       AID_COMPASS, },
-    { "mount",         AID_MOUNT, },
-    { "wifi",          AID_WIFI, },
-    { "adb",           AID_ADB, },
-    { "install",       AID_INSTALL, },
-    { "media",         AID_MEDIA, },
-    { "dhcp",          AID_DHCP, },
-    { "sdcard_rw",     AID_SDCARD_RW, },
-    { "vpn",           AID_VPN, },
-    { "keystore",      AID_KEYSTORE, },
-    { "usb",           AID_USB, },
-    { "drm",           AID_DRM, },
-    { "mdnsr",         AID_MDNSR, },
-    { "gps",           AID_GPS, },
-    // AID_UNUSED1
-    { "media_rw",      AID_MEDIA_RW, },
-    { "mtp",           AID_MTP, },
-    // AID_UNUSED2
-    { "drmrpc",        AID_DRMRPC, },
-    { "nfc",           AID_NFC, },
-    { "sdcard_r",      AID_SDCARD_R, },
-    { "clat",          AID_CLAT, },
-    { "loop_radio",    AID_LOOP_RADIO, },
-    { "mediadrm",      AID_MEDIA_DRM, },
-    { "package_info",  AID_PACKAGE_INFO, },
-    { "sdcard_pics",   AID_SDCARD_PICS, },
-    { "sdcard_av",     AID_SDCARD_AV, },
-    { "sdcard_all",    AID_SDCARD_ALL, },
-    { "logd",          AID_LOGD, },
-    { "shared_relro",  AID_SHARED_RELRO, },
-    { "dbus",          AID_DBUS, },
-    { "tlsdate",       AID_TLSDATE, },
-    { "mediaex",       AID_MEDIA_EX, },
-    { "audioserver",   AID_AUDIOSERVER, },
-    { "metrics_coll",  AID_METRICS_COLL },
-    { "metricsd",      AID_METRICSD },
-    { "webserv",       AID_WEBSERV },
-    { "debuggerd",     AID_DEBUGGERD, },
-    { "mediacodec",    AID_MEDIA_CODEC, },
-    { "cameraserver",  AID_CAMERASERVER, },
-    { "firewall",      AID_FIREWALL, },
-    { "trunks",        AID_TRUNKS, },
-    { "nvram",         AID_NVRAM, },
-    { "dns",           AID_DNS, },
-    { "dns_tether",    AID_DNS_TETHER, },
-    { "webview_zygote", AID_WEBVIEW_ZYGOTE, },
-    { "vehicle_network", AID_VEHICLE_NETWORK, },
-    { "media_audio",   AID_MEDIA_AUDIO, },
-    { "media_video",   AID_MEDIA_VIDEO, },
-    { "media_image",   AID_MEDIA_IMAGE, },
-
-    { "shell",         AID_SHELL, },
-    { "cache",         AID_CACHE, },
-    { "diag",          AID_DIAG, },
-
-    { "net_bt_admin",  AID_NET_BT_ADMIN, },
-    { "net_bt",        AID_NET_BT, },
-    { "inet",          AID_INET, },
-    { "net_raw",       AID_NET_RAW, },
-    { "net_admin",     AID_NET_ADMIN, },
-    { "net_bw_stats",  AID_NET_BW_STATS, },
-    { "net_bw_acct",   AID_NET_BW_ACCT, },
-    { "readproc",      AID_READPROC, },
-    { "wakelock",      AID_WAKELOCK, },
-
-    { "everybody",     AID_EVERYBODY, },
-    { "misc",          AID_MISC, },
-    { "nobody",        AID_NOBODY, },
-};
-
-#define android_id_count \
-    (sizeof(android_ids) / sizeof(android_ids[0]))
+#if !defined(EXCLUDE_FS_CONFIG_STRUCTURES)
 
 struct fs_path_config {
     unsigned mode;
diff --git a/include/system/radio.h b/include/system/radio.h
index d73d3ae..36e2188 100644
--- a/include/system/radio.h
+++ b/include/system/radio.h
@@ -170,7 +170,8 @@
     bool             stereo;    /* program is stereo or not */
     bool             digital;   /* digital program or not (e.g HD Radio program) */
     unsigned int     signal_strength; /* signal strength from 0 to 100 */
-    radio_metadata_t *metadata; /* non null if meta data are present (e.g PTY, song title ...) */
+                                /* meta data (e.g PTY, song title ...), must not be NULL */
+    __attribute__((aligned(8))) radio_metadata_t *metadata;
 } radio_program_info_t;
 
 
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c
index 6155d16..6fb52cc 100644
--- a/libcutils/fs_config.c
+++ b/libcutils/fs_config.c
@@ -163,6 +163,10 @@
                                            CAP_MASK_LONG(CAP_NET_RAW),
                                               "system/bin/hw/android.hardware.wifi@1.0-service" },
 
+    /* Support Bluetooth legacy hal accessing /sys/class/rfkill */
+    { 00700, AID_BLUETOOTH, AID_BLUETOOTH, CAP_MASK_LONG(CAP_NET_ADMIN),
+                                              "system/bin/hw/android.hardware.bluetooth@1.0-service" },
+
     /* A non-privileged zygote that spawns isolated processes for web rendering. */
     { 0750,  AID_ROOT,      AID_ROOT,      CAP_MASK_LONG(CAP_SETUID) |
                                            CAP_MASK_LONG(CAP_SETGID) |
diff --git a/liblog/Android.bp b/liblog/Android.bp
index be47fc3..bbe7d79 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -115,4 +115,5 @@
     name: "liblog.ndk",
     symbol_file: "liblog.map.txt",
     first_version: "9",
+    unversioned_until: "current",
 }
diff --git a/liblog/logd_writer.c b/liblog/logd_writer.c
index 8fdfb92..2bab92e 100644
--- a/liblog/logd_writer.c
+++ b/liblog/logd_writer.c
@@ -50,7 +50,7 @@
 
 LIBLOG_HIDDEN struct android_log_transport_write logdLoggerWrite = {
     .node = { &logdLoggerWrite.node, &logdLoggerWrite.node },
-    .context.sock = -1,
+    .context.sock = -EBADF,
     .name = "logd",
     .available = logdAvailable,
     .open = logdOpen,
@@ -65,8 +65,10 @@
 
     i = atomic_load(&logdLoggerWrite.context.sock);
     if (i < 0) {
-        i = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0));
-        if (i < 0) {
+        int sock = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM |
+                                                      SOCK_CLOEXEC |
+                                                      SOCK_NONBLOCK, 0));
+        if (sock < 0) {
             ret = -errno;
         } else {
             struct sockaddr_un un;
@@ -74,13 +76,22 @@
             un.sun_family = AF_UNIX;
             strcpy(un.sun_path, "/dev/socket/logdw");
 
-            if (TEMP_FAILURE_RETRY(connect(i, (struct sockaddr *)&un,
+            if (TEMP_FAILURE_RETRY(connect(sock, (struct sockaddr *)&un,
                                            sizeof(struct sockaddr_un))) < 0) {
                 ret = -errno;
-                close(i);
+                switch (ret) {
+                case -ENOTCONN:
+                case -ECONNREFUSED:
+                case -ENOENT:
+                    i = atomic_exchange(&logdLoggerWrite.context.sock, ret);
+                    /* FALLTHRU */
+                default:
+                    break;
+                }
+                close(sock);
             } else {
-                ret = atomic_exchange(&logdLoggerWrite.context.sock, i);
-                if ((ret >= 0) && (ret != i)) {
+                ret = atomic_exchange(&logdLoggerWrite.context.sock, sock);
+                if ((ret >= 0) && (ret != sock)) {
                     close(ret);
                 }
                 ret = 0;
@@ -91,14 +102,19 @@
     return ret;
 }
 
-static void logdClose()
+static void __logdClose(int negative_errno)
 {
-    int sock = atomic_exchange(&logdLoggerWrite.context.sock, -1);
+    int sock = atomic_exchange(&logdLoggerWrite.context.sock, negative_errno);
     if (sock >= 0) {
         close(sock);
     }
 }
 
+static void logdClose()
+{
+    __logdClose(-EBADF);
+}
+
 static int logdAvailable(log_id_t logId)
 {
     if (logId > LOG_ID_SECURITY) {
@@ -117,6 +133,7 @@
                      struct iovec *vec, size_t nr)
 {
     ssize_t ret;
+    int sock;
     static const unsigned headerLength = 1;
     struct iovec newVec[nr + headerLength];
     android_log_header_t header;
@@ -124,7 +141,13 @@
     static atomic_int_fast32_t dropped;
     static atomic_int_fast32_t droppedSecurity;
 
-    if (atomic_load(&logdLoggerWrite.context.sock) < 0) {
+    sock = atomic_load(&logdLoggerWrite.context.sock);
+    if (sock < 0) switch (sock) {
+    case -ENOTCONN:
+    case -ECONNREFUSED:
+    case -ENOENT:
+        break;
+    default:
         return -EBADF;
     }
 
@@ -163,7 +186,7 @@
     newVec[0].iov_base = (unsigned char *)&header;
     newVec[0].iov_len  = sizeof(header);
 
-    if (atomic_load(&logdLoggerWrite.context.sock) > 0) {
+    if (sock >= 0) {
         int32_t snapshot = atomic_exchange_explicit(&droppedSecurity, 0,
                                                     memory_order_relaxed);
         if (snapshot) {
@@ -177,8 +200,7 @@
             newVec[headerLength].iov_base = &buffer;
             newVec[headerLength].iov_len  = sizeof(buffer);
 
-            ret = TEMP_FAILURE_RETRY(writev(
-                    atomic_load(&logdLoggerWrite.context.sock), newVec, 2));
+            ret = TEMP_FAILURE_RETRY(writev(sock, newVec, 2));
             if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
                 atomic_fetch_add_explicit(&droppedSecurity, snapshot,
                                           memory_order_relaxed);
@@ -186,7 +208,8 @@
         }
         snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed);
         if (snapshot && __android_log_is_loggable_len(ANDROID_LOG_INFO,
-                                                      "liblog", strlen("liblog"),
+                                                      "liblog",
+                                                      strlen("liblog"),
                                                       ANDROID_LOG_VERBOSE)) {
             android_log_event_int_t buffer;
 
@@ -198,8 +221,7 @@
             newVec[headerLength].iov_base = &buffer;
             newVec[headerLength].iov_len  = sizeof(buffer);
 
-            ret = TEMP_FAILURE_RETRY(writev(
-                      atomic_load(&logdLoggerWrite.context.sock), newVec, 2));
+            ret = TEMP_FAILURE_RETRY(writev(sock, newVec, 2));
             if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
                 atomic_fetch_add_explicit(&dropped, snapshot,
                                           memory_order_relaxed);
@@ -225,30 +247,43 @@
     /*
      * The write below could be lost, but will never block.
      *
-     * ENOTCONN occurs if logd dies.
+     * ENOTCONN occurs if logd has died.
+     * ENOENT occurs if logd is not running and socket is missing.
+     * ECONNREFUSED occurs if we can not reconnect to logd.
      * EAGAIN occurs if logd is overloaded.
      */
-    ret = TEMP_FAILURE_RETRY(writev(
-            atomic_load(&logdLoggerWrite.context.sock), newVec, i));
-    if (ret < 0) {
-        ret = -errno;
-        if (ret == -ENOTCONN) {
-            __android_log_lock();
-            logdClose();
-            ret = logdOpen();
-            __android_log_unlock();
-
-            if (ret < 0) {
-                return ret;
-            }
-
-            ret = TEMP_FAILURE_RETRY(writev(
-                    atomic_load(&logdLoggerWrite.context.sock), newVec, i));
-            if (ret < 0) {
-                ret = -errno;
-            }
+    if (sock < 0) {
+        ret = sock;
+    } else {
+        ret = TEMP_FAILURE_RETRY(writev(sock, newVec, i));
+        if (ret < 0) {
+            ret = -errno;
         }
     }
+    switch(ret) {
+    case -ENOTCONN:
+    case -ECONNREFUSED:
+    case -ENOENT:
+        if (__android_log_trylock()) {
+            return ret; /* in a signal handler? try again when less stressed */
+        }
+        __logdClose(ret);
+        ret = logdOpen();
+        __android_log_unlock();
+
+        if (ret < 0) {
+            return ret;
+        }
+
+        ret = TEMP_FAILURE_RETRY(writev(
+                atomic_load(&logdLoggerWrite.context.sock), newVec, i));
+        if (ret < 0) {
+            ret = -errno;
+        }
+        /* FALLTHRU */
+    default:
+        break;
+    }
 
     if (ret > (ssize_t)sizeof(header)) {
         ret -= sizeof(header);
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 371e6ca..02feb97 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -270,18 +270,19 @@
 
         ASSERT_EQ(log_msg.entry.pid, pid);
 
-        if ((log_msg.entry.len != (4 + 1 + 8))
+        if ((log_msg.entry.len != sizeof(android_log_event_long_t))
          || (log_msg.id() != LOG_ID_EVENTS)) {
             continue;
         }
 
-        char *eventData = log_msg.msg();
+        android_log_event_long_t* eventData;
+        eventData = reinterpret_cast<android_log_event_long_t*>(log_msg.msg());
 
-        if (!eventData || (eventData[4] != EVENT_TYPE_LONG)) {
+        if (!eventData || (eventData->payload.type != EVENT_TYPE_LONG)) {
             continue;
         }
 
-        log_time tx(eventData + 4 + 1);
+        log_time tx(reinterpret_cast<char*>(&eventData->payload.data));
         if (ts == tx) {
             ++count;
         } else if (ts1 == tx) {
@@ -352,18 +353,20 @@
 
         if ((log_msg.entry.sec < (ts.tv_sec - 1))
          || ((ts.tv_sec + 1) < log_msg.entry.sec)
-         || ((size_t)log_msg.entry.len != (4 + 1 + 4 + length))
+         || ((size_t)log_msg.entry.len != (sizeof(android_log_event_string_t) +
+                                           length))
          || (log_msg.id() != LOG_ID_EVENTS)) {
             continue;
         }
 
-        char *eventData = log_msg.msg();
+        android_log_event_string_t* eventData;
+        eventData = reinterpret_cast<android_log_event_string_t*>(log_msg.msg());
 
-        if (!eventData || (eventData[4] != EVENT_TYPE_STRING)) {
+        if (!eventData || (eventData->type != EVENT_TYPE_STRING)) {
             continue;
         }
 
-        size_t len = get4LE(eventData + 4 + 1);
+        size_t len = get4LE(reinterpret_cast<char*>(&eventData->length));
         if (len == total) {
             ++count;
 
@@ -501,189 +504,6 @@
     buf_write_test("\n Hello World \n");
 }
 
-TEST(liblog, __security) {
-#ifdef __ANDROID__
-    static const char persist_key[] = "persist.logd.security";
-    static const char readonly_key[] = "ro.device_owner";
-    static const char nothing_val[] = "_NOTHING_TO_SEE_HERE_";
-    char persist[PROP_VALUE_MAX];
-    char readonly[PROP_VALUE_MAX];
-
-    property_get(persist_key, persist, "");
-    property_get(readonly_key, readonly, nothing_val);
-
-    if (!strcmp(readonly, nothing_val)) {
-        EXPECT_FALSE(__android_log_security());
-        fprintf(stderr, "Warning, setting ro.device_owner to a domain\n");
-        property_set(readonly_key, "com.google.android.SecOps.DeviceOwner");
-    } else if (!strcasecmp(readonly, "false") || !readonly[0]) {
-        EXPECT_FALSE(__android_log_security());
-        return;
-    }
-
-    if (!strcasecmp(persist, "true")) {
-        EXPECT_TRUE(__android_log_security());
-    } else {
-        EXPECT_FALSE(__android_log_security());
-    }
-    property_set(persist_key, "TRUE");
-    EXPECT_TRUE(__android_log_security());
-    property_set(persist_key, "FALSE");
-    EXPECT_FALSE(__android_log_security());
-    property_set(persist_key, "true");
-    EXPECT_TRUE(__android_log_security());
-    property_set(persist_key, "false");
-    EXPECT_FALSE(__android_log_security());
-    property_set(persist_key, "");
-    EXPECT_FALSE(__android_log_security());
-    property_set(persist_key, persist);
-#else
-    GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog, __security_buffer) {
-#ifdef __ANDROID__
-    struct logger_list *logger_list;
-    android_event_long_t buffer;
-
-    static const char persist_key[] = "persist.logd.security";
-    char persist[PROP_VALUE_MAX];
-    bool set_persist = false;
-    bool allow_security = false;
-
-    if (__android_log_security()) {
-        allow_security = true;
-    } else {
-        property_get(persist_key, persist, "");
-        if (strcasecmp(persist, "true")) {
-            property_set(persist_key, "TRUE");
-            if (__android_log_security()) {
-                allow_security = true;
-                set_persist = true;
-            } else {
-                property_set(persist_key, persist);
-            }
-        }
-    }
-
-    if (!allow_security) {
-        fprintf(stderr, "WARNING: "
-                "security buffer disabled, bypassing end-to-end test\n");
-
-        log_time ts(CLOCK_MONOTONIC);
-
-        buffer.type = EVENT_TYPE_LONG;
-        buffer.data = *(static_cast<uint64_t *>((void *)&ts));
-
-        // expect failure!
-        ASSERT_GE(0, __android_log_security_bwrite(0, &buffer, sizeof(buffer)));
-
-        return;
-    }
-
-    /* Matches clientHasLogCredentials() in logd */
-    uid_t uid = getuid();
-    gid_t gid = getgid();
-    bool clientHasLogCredentials = true;
-    if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)
-     && (gid != AID_SYSTEM) && (gid != AID_ROOT) && (gid != AID_LOG)) {
-        uid_t euid = geteuid();
-        if ((euid != AID_SYSTEM) && (euid != AID_ROOT) && (euid != AID_LOG)) {
-            gid_t egid = getegid();
-            if ((egid != AID_SYSTEM) && (egid != AID_ROOT) && (egid != AID_LOG)) {
-                int num_groups = getgroups(0, NULL);
-                if (num_groups > 0) {
-                    gid_t groups[num_groups];
-                    num_groups = getgroups(num_groups, groups);
-                    while (num_groups > 0) {
-                        if (groups[num_groups - 1] == AID_LOG) {
-                            break;
-                        }
-                        --num_groups;
-                    }
-                }
-                if (num_groups <= 0) {
-                    clientHasLogCredentials = false;
-                }
-            }
-        }
-    }
-    if (!clientHasLogCredentials) {
-        fprintf(stderr, "WARNING: "
-                "not in system context, bypassing end-to-end test\n");
-
-        log_time ts(CLOCK_MONOTONIC);
-
-        buffer.type = EVENT_TYPE_LONG;
-        buffer.data = *(static_cast<uint64_t *>((void *)&ts));
-
-        // expect failure!
-        ASSERT_GE(0, __android_log_security_bwrite(0, &buffer, sizeof(buffer)));
-
-        return;
-    }
-
-    setuid(AID_SYSTEM); // only one that can read security buffer
-
-    pid_t pid = getpid();
-
-    ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
-        LOG_ID_SECURITY, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK,
-        1000, pid)));
-
-    log_time ts(CLOCK_MONOTONIC);
-
-    buffer.type = EVENT_TYPE_LONG;
-    buffer.data = *(static_cast<uint64_t *>((void *)&ts));
-
-    ASSERT_LT(0, __android_log_security_bwrite(0, &buffer, sizeof(buffer)));
-    usleep(1000000);
-
-    int count = 0;
-
-    for (;;) {
-        log_msg log_msg;
-        if (android_logger_list_read(logger_list, &log_msg) <= 0) {
-            break;
-        }
-
-        ASSERT_EQ(log_msg.entry.pid, pid);
-
-        if ((log_msg.entry.len != (4 + 1 + 8))
-         || (log_msg.id() != LOG_ID_SECURITY)) {
-            continue;
-        }
-
-        char *eventData = log_msg.msg();
-
-        if (!eventData || (eventData[4] != EVENT_TYPE_LONG)) {
-            continue;
-        }
-
-        log_time tx(eventData + 4 + 1);
-        if (ts == tx) {
-            ++count;
-        }
-    }
-
-    if (set_persist) {
-        property_set(persist_key, persist);
-    }
-
-    android_logger_list_close(logger_list);
-
-    bool clientHasSecurityCredentials = (uid == AID_SYSTEM) || (gid == AID_SYSTEM);
-    if (!clientHasSecurityCredentials) {
-        fprintf(stderr, "WARNING: "
-                "not system, content submitted but can not check end-to-end\n");
-    }
-    EXPECT_EQ(clientHasSecurityCredentials ? 1 : 0, count);
-#else
-    GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
 #ifdef __ANDROID__
 static unsigned signaled;
 static log_time signal_time;
@@ -786,25 +606,27 @@
 
         ASSERT_EQ(log_msg.entry.pid, pid);
 
-        if ((log_msg.entry.len != (4 + 1 + 8))
+        if ((log_msg.entry.len != sizeof(android_log_event_long_t))
          || (log_msg.id() != LOG_ID_EVENTS)) {
             continue;
         }
 
-        char *eventData = log_msg.msg();
+        android_log_event_long_t* eventData;
+        eventData = reinterpret_cast<android_log_event_long_t*>(log_msg.msg());
 
-        if (!eventData || (eventData[4] != EVENT_TYPE_LONG)) {
+        if (!eventData || (eventData->payload.type != EVENT_TYPE_LONG)) {
             continue;
         }
 
-        unsigned long long l = eventData[4 + 1 + 0] & 0xFF;
-        l |= (unsigned long long) (eventData[4 + 1 + 1] & 0xFF) << 8;
-        l |= (unsigned long long) (eventData[4 + 1 + 2] & 0xFF) << 16;
-        l |= (unsigned long long) (eventData[4 + 1 + 3] & 0xFF) << 24;
-        l |= (unsigned long long) (eventData[4 + 1 + 4] & 0xFF) << 32;
-        l |= (unsigned long long) (eventData[4 + 1 + 5] & 0xFF) << 40;
-        l |= (unsigned long long) (eventData[4 + 1 + 6] & 0xFF) << 48;
-        l |= (unsigned long long) (eventData[4 + 1 + 7] & 0xFF) << 56;
+        char* cp = reinterpret_cast<char*>(&eventData->payload.data);
+        unsigned long long l = cp[0] & 0xFF;
+        l |= (unsigned long long) (cp[1] & 0xFF) << 8;
+        l |= (unsigned long long) (cp[2] & 0xFF) << 16;
+        l |= (unsigned long long) (cp[3] & 0xFF) << 24;
+        l |= (unsigned long long) (cp[4] & 0xFF) << 32;
+        l |= (unsigned long long) (cp[5] & 0xFF) << 40;
+        l |= (unsigned long long) (cp[6] & 0xFF) << 48;
+        l |= (unsigned long long) (cp[7] & 0xFF) << 56;
 
         if (l == v) {
             ++signals;
@@ -943,25 +765,27 @@
 
         ASSERT_EQ(log_msg.entry.pid, pid);
 
-        if ((log_msg.entry.len != (4 + 1 + 8))
+        if ((log_msg.entry.len != sizeof(android_log_event_long_t))
          || (log_msg.id() != LOG_ID_EVENTS)) {
             continue;
         }
 
-        char *eventData = log_msg.msg();
+        android_log_event_long_t* eventData;
+        eventData = reinterpret_cast<android_log_event_long_t*>(log_msg.msg());
 
-        if (!eventData || (eventData[4] != EVENT_TYPE_LONG)) {
+        if (!eventData || (eventData->payload.type != EVENT_TYPE_LONG)) {
             continue;
         }
 
-        unsigned long long l = eventData[4 + 1 + 0] & 0xFF;
-        l |= (unsigned long long) (eventData[4 + 1 + 1] & 0xFF) << 8;
-        l |= (unsigned long long) (eventData[4 + 1 + 2] & 0xFF) << 16;
-        l |= (unsigned long long) (eventData[4 + 1 + 3] & 0xFF) << 24;
-        l |= (unsigned long long) (eventData[4 + 1 + 4] & 0xFF) << 32;
-        l |= (unsigned long long) (eventData[4 + 1 + 5] & 0xFF) << 40;
-        l |= (unsigned long long) (eventData[4 + 1 + 6] & 0xFF) << 48;
-        l |= (unsigned long long) (eventData[4 + 1 + 7] & 0xFF) << 56;
+        char* cp = reinterpret_cast<char*>(&eventData->payload.data);
+        unsigned long long l = cp[0] & 0xFF;
+        l |= (unsigned long long) (cp[1] & 0xFF) << 8;
+        l |= (unsigned long long) (cp[2] & 0xFF) << 16;
+        l |= (unsigned long long) (cp[3] & 0xFF) << 24;
+        l |= (unsigned long long) (cp[4] & 0xFF) << 32;
+        l |= (unsigned long long) (cp[5] & 0xFF) << 40;
+        l |= (unsigned long long) (cp[6] & 0xFF) << 48;
+        l |= (unsigned long long) (cp[7] & 0xFF) << 56;
 
         if (l == v) {
             ++signals;
@@ -1367,6 +1191,9 @@
 
 TEST(liblog, android_logger_get_) {
 #ifdef __ANDROID__
+    // This test assumes the log buffers are filled with noise from
+    // normal operations. It will fail if done immediately after a
+    // logcat -c.
     struct logger_list * logger_list = android_logger_list_alloc(ANDROID_LOG_WRONLY, 0, 0);
 
     for(int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
@@ -1778,6 +1605,294 @@
 }
 
 #ifdef __ANDROID__
+// helper to liblog.enoent to count end-to-end matching logging messages.
+static int count_matching_ts(log_time ts) {
+    usleep(1000000);
+
+    pid_t pid = getpid();
+
+    struct logger_list* logger_list = android_logger_list_open(
+        LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid);
+
+    int count = 0;
+    if (logger_list == NULL) return count;
+
+    for (;;) {
+        log_msg log_msg;
+        if (android_logger_list_read(logger_list, &log_msg) <= 0) break;
+
+        if (log_msg.entry.len != sizeof(android_log_event_long_t)) continue;
+        if (log_msg.id() != LOG_ID_EVENTS) continue;
+
+        android_log_event_long_t* eventData;
+        eventData = reinterpret_cast<android_log_event_long_t*>(log_msg.msg());
+        if (!eventData) continue;
+        if (eventData->payload.type != EVENT_TYPE_LONG) continue;
+
+        log_time tx(reinterpret_cast<char*>(&eventData->payload.data));
+        if (ts != tx) continue;
+
+        // found event message with matching timestamp signature in payload
+        ++count;
+    }
+    android_logger_list_close(logger_list);
+
+    return count;
+}
+
+// meant to be handed to ASSERT_TRUE / EXPECT_TRUE only to expand the message
+static testing::AssertionResult IsOk(bool ok, std::string &message) {
+    return ok ?
+        testing::AssertionSuccess() :
+        (testing::AssertionFailure() << message);
+}
+#endif
+
+TEST(liblog, enoent) {
+#ifdef __ANDROID__
+    log_time ts(CLOCK_MONOTONIC);
+    EXPECT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
+    EXPECT_EQ(1, count_matching_ts(ts));
+
+    // This call will fail if we are setuid(AID_SYSTEM), beware of any
+    // test prior to this one playing with setuid and causing interference.
+    // We need to run before these tests so that they do not interfere with
+    // this test.
+    //
+    // Stopping the logger can affect some other test's expectations as they
+    // count on the log buffers filled with existing content, and this
+    // effectively does a logcat -c emptying it.  So we want this test to be
+    // as near as possible to the bottom of the file.  For example
+    // liblog.android_logger_get_ is one of those tests that has no recourse
+    // and that would be adversely affected by emptying the log if it was run
+    // right after this test.
+    system("stop logd");
+    usleep(1000000);
+
+    // A clean stop like we are testing returns -ENOENT, but in the _real_
+    // world we could get -ENOTCONN or -ECONNREFUSED depending on timing.
+    // Alas we can not test these other return values; accept that they
+    // are treated equally within the open-retry logic in liblog.
+    ts = log_time(CLOCK_MONOTONIC);
+    int ret = __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts));
+    std::string content = android::base::StringPrintf(
+        "__android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)) = %d %s\n",
+        ret, strerror(-ret));
+    EXPECT_TRUE(IsOk((ret == -ENOENT) ||
+                     (ret == -ENOTCONN) ||
+                     (ret == -ECONNREFUSED), content));
+    ret = __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts));
+    content = android::base::StringPrintf(
+        "__android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)) = %d %s\n",
+        ret, strerror(-ret));
+    EXPECT_TRUE(IsOk((ret == -ENOENT) ||
+                     (ret == -ENOTCONN) ||
+                     (ret == -ECONNREFUSED), content));
+    EXPECT_EQ(0, count_matching_ts(ts));
+
+    system("start logd");
+    usleep(1000000);
+
+    EXPECT_EQ(0, count_matching_ts(ts));
+
+    ts = log_time(CLOCK_MONOTONIC);
+    EXPECT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
+    EXPECT_EQ(1, count_matching_ts(ts));
+
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+}
+
+// Below this point we run risks of setuid(AID_SYSTEM) which may affect others.
+
+TEST(liblog, __security) {
+#ifdef __ANDROID__
+    static const char persist_key[] = "persist.logd.security";
+    static const char readonly_key[] = "ro.device_owner";
+    // A silly default value that can never be in readonly_key so
+    // that it can be determined the property is not set.
+    static const char nothing_val[] = "_NOTHING_TO_SEE_HERE_";
+    char persist[PROP_VALUE_MAX];
+    char readonly[PROP_VALUE_MAX];
+
+    property_get(persist_key, persist, "");
+    property_get(readonly_key, readonly, nothing_val);
+
+    if (!strcmp(readonly, nothing_val)) {
+        EXPECT_FALSE(__android_log_security());
+        fprintf(stderr, "Warning, setting ro.device_owner to a domain\n");
+        property_set(readonly_key, "com.google.android.SecOps.DeviceOwner");
+    } else if (!strcasecmp(readonly, "false") || !readonly[0]) {
+        EXPECT_FALSE(__android_log_security());
+        return;
+    }
+
+    if (!strcasecmp(persist, "true")) {
+        EXPECT_TRUE(__android_log_security());
+    } else {
+        EXPECT_FALSE(__android_log_security());
+    }
+    property_set(persist_key, "TRUE");
+    EXPECT_TRUE(__android_log_security());
+    property_set(persist_key, "FALSE");
+    EXPECT_FALSE(__android_log_security());
+    property_set(persist_key, "true");
+    EXPECT_TRUE(__android_log_security());
+    property_set(persist_key, "false");
+    EXPECT_FALSE(__android_log_security());
+    property_set(persist_key, "");
+    EXPECT_FALSE(__android_log_security());
+    property_set(persist_key, persist);
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+}
+
+TEST(liblog, __security_buffer) {
+#ifdef __ANDROID__
+    struct logger_list *logger_list;
+    android_event_long_t buffer;
+
+    static const char persist_key[] = "persist.logd.security";
+    char persist[PROP_VALUE_MAX];
+    bool set_persist = false;
+    bool allow_security = false;
+
+    if (__android_log_security()) {
+        allow_security = true;
+    } else {
+        property_get(persist_key, persist, "");
+        if (strcasecmp(persist, "true")) {
+            property_set(persist_key, "TRUE");
+            if (__android_log_security()) {
+                allow_security = true;
+                set_persist = true;
+            } else {
+                property_set(persist_key, persist);
+            }
+        }
+    }
+
+    if (!allow_security) {
+        fprintf(stderr, "WARNING: "
+                "security buffer disabled, bypassing end-to-end test\n");
+
+        log_time ts(CLOCK_MONOTONIC);
+
+        buffer.type = EVENT_TYPE_LONG;
+        buffer.data = *(static_cast<uint64_t *>((void *)&ts));
+
+        // expect failure!
+        ASSERT_GE(0, __android_log_security_bwrite(0, &buffer, sizeof(buffer)));
+
+        return;
+    }
+
+    /* Matches clientHasLogCredentials() in logd */
+    uid_t uid = getuid();
+    gid_t gid = getgid();
+    bool clientHasLogCredentials = true;
+    if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)
+     && (gid != AID_SYSTEM) && (gid != AID_ROOT) && (gid != AID_LOG)) {
+        uid_t euid = geteuid();
+        if ((euid != AID_SYSTEM) && (euid != AID_ROOT) && (euid != AID_LOG)) {
+            gid_t egid = getegid();
+            if ((egid != AID_SYSTEM) && (egid != AID_ROOT) && (egid != AID_LOG)) {
+                int num_groups = getgroups(0, NULL);
+                if (num_groups > 0) {
+                    gid_t groups[num_groups];
+                    num_groups = getgroups(num_groups, groups);
+                    while (num_groups > 0) {
+                        if (groups[num_groups - 1] == AID_LOG) {
+                            break;
+                        }
+                        --num_groups;
+                    }
+                }
+                if (num_groups <= 0) {
+                    clientHasLogCredentials = false;
+                }
+            }
+        }
+    }
+    if (!clientHasLogCredentials) {
+        fprintf(stderr, "WARNING: "
+                "not in system context, bypassing end-to-end test\n");
+
+        log_time ts(CLOCK_MONOTONIC);
+
+        buffer.type = EVENT_TYPE_LONG;
+        buffer.data = *(static_cast<uint64_t *>((void *)&ts));
+
+        // expect failure!
+        ASSERT_GE(0, __android_log_security_bwrite(0, &buffer, sizeof(buffer)));
+
+        return;
+    }
+
+    setuid(AID_SYSTEM); // only one that can read security buffer
+
+    pid_t pid = getpid();
+
+    ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+        LOG_ID_SECURITY, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK,
+        1000, pid)));
+
+    log_time ts(CLOCK_MONOTONIC);
+
+    buffer.type = EVENT_TYPE_LONG;
+    buffer.data = *(static_cast<uint64_t *>((void *)&ts));
+
+    ASSERT_LT(0, __android_log_security_bwrite(0, &buffer, sizeof(buffer)));
+    usleep(1000000);
+
+    int count = 0;
+
+    for (;;) {
+        log_msg log_msg;
+        if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+            break;
+        }
+
+        ASSERT_EQ(log_msg.entry.pid, pid);
+
+        if ((log_msg.entry.len != sizeof(android_log_event_long_t))
+         || (log_msg.id() != LOG_ID_SECURITY)) {
+            continue;
+        }
+
+        android_log_event_long_t* eventData;
+        eventData = reinterpret_cast<android_log_event_long_t*>(log_msg.msg());
+
+        if (!eventData || (eventData->payload.type != EVENT_TYPE_LONG)) {
+            continue;
+        }
+
+        log_time tx(reinterpret_cast<char*>(&eventData->payload.data));
+        if (ts == tx) {
+            ++count;
+        }
+    }
+
+    if (set_persist) {
+        property_set(persist_key, persist);
+    }
+
+    android_logger_list_close(logger_list);
+
+    bool clientHasSecurityCredentials = (uid == AID_SYSTEM) || (gid == AID_SYSTEM);
+    if (!clientHasSecurityCredentials) {
+        fprintf(stderr, "WARNING: "
+                "not system, content submitted but can not check end-to-end\n");
+    }
+    EXPECT_EQ(clientHasSecurityCredentials ? 1 : 0, count);
+#else
+    GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+}
+
+#ifdef __ANDROID__
 static void android_errorWriteWithInfoLog_helper(int TAG, const char* SUBTAG,
                                                  int UID, const char* payload,
                                                  int DATA_LEN, int& count) {
@@ -1842,7 +1957,7 @@
         int subtag_len = strlen(SUBTAG);
         if (subtag_len > 32) subtag_len = 32;
         ASSERT_EQ(subtag_len, get4LE(eventData));
-        eventData +=4;
+        eventData += 4;
 
         if (memcmp(SUBTAG, eventData, subtag_len)) {
             continue;
@@ -2795,13 +2910,6 @@
 }
 
 #ifdef __ANDROID__
-// meant to be handed to ASSERT_TRUE / EXPECT_TRUE only to expand the message
-static testing::AssertionResult IsOk(bool ok, std::string &message) {
-    return ok ?
-        testing::AssertionSuccess() :
-        (testing::AssertionFailure() << message);
-}
-
 // must be: '<needle:> 0 kB'
 static bool isZero(const std::string &content, std::string::size_type pos,
                    const char* needle) {
diff --git a/rootdir/init.zygote32.rc b/rootdir/init.zygote32.rc
index eedeba8..d836c4e 100644
--- a/rootdir/init.zygote32.rc
+++ b/rootdir/init.zygote32.rc
@@ -10,4 +10,5 @@
     onrestart restart cameraserver
     onrestart restart media
     onrestart restart netd
+    onrestart restart wificond
     writepid /dev/cpuset/foreground/tasks
diff --git a/rootdir/init.zygote32_64.rc b/rootdir/init.zygote32_64.rc
index 84a907f..ed11164 100644
--- a/rootdir/init.zygote32_64.rc
+++ b/rootdir/init.zygote32_64.rc
@@ -10,6 +10,7 @@
     onrestart restart cameraserver
     onrestart restart media
     onrestart restart netd
+    onrestart restart wificond
     writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
 
 service zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
diff --git a/rootdir/init.zygote64.rc b/rootdir/init.zygote64.rc
index 76e2b79..05ec16f 100644
--- a/rootdir/init.zygote64.rc
+++ b/rootdir/init.zygote64.rc
@@ -10,4 +10,5 @@
     onrestart restart cameraserver
     onrestart restart media
     onrestart restart netd
+    onrestart restart wificond
     writepid /dev/cpuset/foreground/tasks
diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc
index e918b67..66e7750 100644
--- a/rootdir/init.zygote64_32.rc
+++ b/rootdir/init.zygote64_32.rc
@@ -10,6 +10,7 @@
     onrestart restart cameraserver
     onrestart restart media
     onrestart restart netd
+    onrestart restart wificond
     writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
 
 service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary