Merge "Remove unused primes.py python file."
diff --git a/adb/adb.h b/adb/adb.h
index 6a38f18..a30e297 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -34,6 +34,8 @@
constexpr size_t MAX_PAYLOAD_V2 = 256 * 1024;
constexpr size_t MAX_PAYLOAD = MAX_PAYLOAD_V2;
+constexpr size_t LINUX_MAX_SOCKET_SIZE = 4194304;
+
#define A_SYNC 0x434e5953
#define A_CNXN 0x4e584e43
#define A_OPEN 0x4e45504f
diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp
index a35c210..ac05d4c 100644
--- a/adb/daemon/usb.cpp
+++ b/adb/daemon/usb.cpp
@@ -49,16 +49,23 @@
#define MAX_PACKET_SIZE_HS 512
#define MAX_PACKET_SIZE_SS 1024
-// Writes larger than 16k fail on some devices (seed with 3.10.49-g209ea2f in particular).
-#define USB_FFS_MAX_WRITE 16384
-
-// The kernel allocates a contiguous buffer for reads, which can fail for large ones due to
-// fragmentation. 16k chosen arbitrarily to match the write limit.
-#define USB_FFS_MAX_READ 16384
+// Kernels before 3.3 have a 16KiB transfer limit That limit was replaced
+// with a 16MiB global limit in 3.3, but each URB submitted required a
+// contiguous kernel allocation, so you would get ENOMEM if you tried to
+// send something larger than the biggest available contiguous kernel
+// memory region. Large contiguous allocations could be unreliable
+// on a device kernel that has been running for a while fragmenting its
+// memory so we start with a larger allocation, and shrink the amount if
+// necessary.
+#define USB_FFS_BULK_SIZE 16384
#define cpu_to_le16(x) htole16(x)
#define cpu_to_le32(x) htole32(x)
+#define FUNCTIONFS_ENDPOINT_ALLOC _IOR('g', 231, __u32)
+
+static constexpr size_t ENDPOINT_ALLOC_RETRIES = 2;
+
static int dummy_fd = -1;
struct func_desc {
@@ -173,6 +180,7 @@
.source_comp = {
.bLength = sizeof(ss_descriptors.source_comp),
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ .bMaxBurst = 4,
},
.sink = {
.bLength = sizeof(ss_descriptors.sink),
@@ -184,6 +192,7 @@
.sink_comp = {
.bLength = sizeof(ss_descriptors.sink_comp),
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ .bMaxBurst = 4,
},
};
@@ -229,6 +238,7 @@
ssize_t ret;
struct desc_v1 v1_descriptor;
struct desc_v2 v2_descriptor;
+ size_t retries = 0;
v2_descriptor.header.magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2);
v2_descriptor.header.length = cpu_to_le32(sizeof(v2_descriptor));
@@ -287,6 +297,29 @@
goto err;
}
+ h->max_rw = MAX_PAYLOAD;
+ while (h->max_rw >= USB_FFS_BULK_SIZE && retries < ENDPOINT_ALLOC_RETRIES) {
+ int ret_in = ioctl(h->bulk_in, FUNCTIONFS_ENDPOINT_ALLOC, static_cast<__u32>(h->max_rw));
+ int errno_in = errno;
+ int ret_out = ioctl(h->bulk_out, FUNCTIONFS_ENDPOINT_ALLOC, static_cast<__u32>(h->max_rw));
+ int errno_out = errno;
+
+ if (ret_in || ret_out) {
+ if (errno_in == ENODEV || errno_out == ENODEV) {
+ std::this_thread::sleep_for(100ms);
+ retries += 1;
+ continue;
+ }
+ h->max_rw /= 2;
+ } else {
+ return true;
+ }
+ }
+
+ D("[ adb: cannot call endpoint alloc: errno=%d ]", errno);
+ // Kernel pre-allocation could have failed for recoverable reasons.
+ // Continue running with a safe max rw size.
+ h->max_rw *= 2;
return true;
err:
@@ -340,7 +373,7 @@
const char* buf = static_cast<const char*>(data);
while (len > 0) {
- int write_len = std::min(USB_FFS_MAX_WRITE, len);
+ int write_len = std::min(h->max_rw, len);
int n = adb_write(h->bulk_in, buf, write_len);
if (n < 0) {
D("ERROR: fd = %d, n = %d: %s", h->bulk_in, n, strerror(errno));
@@ -359,7 +392,7 @@
char* buf = static_cast<char*>(data);
while (len > 0) {
- int read_len = std::min(USB_FFS_MAX_READ, len);
+ int read_len = std::min(h->max_rw, len);
int n = adb_read(h->bulk_out, buf, read_len);
if (n < 0) {
D("ERROR: fd = %d, n = %d: %s", h->bulk_out, n, strerror(errno));
diff --git a/adb/daemon/usb.h b/adb/daemon/usb.h
index 1d85405..55b5995 100644
--- a/adb/daemon/usb.h
+++ b/adb/daemon/usb.h
@@ -20,13 +20,6 @@
#include <condition_variable>
#include <mutex>
-// Writes larger than 16k fail on some devices (seed with 3.10.49-g209ea2f in particular).
-#define USB_FFS_MAX_WRITE 16384
-
-// The kernel allocates a contiguous buffer for reads, which can fail for large ones due to
-// fragmentation. 16k chosen arbitrarily to match the write limit.
-#define USB_FFS_MAX_READ 16384
-
struct usb_handle {
usb_handle() : kicked(false) {
}
@@ -45,6 +38,8 @@
int control = -1;
int bulk_out = -1; /* "out" from the host's perspective => source for adbd */
int bulk_in = -1; /* "in" from the host's perspective => sink for adbd */
+
+ int max_rw;
};
bool init_functionfs(struct usb_handle* h);
diff --git a/adb/services.cpp b/adb/services.cpp
index df1b134..a48d855 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -242,6 +242,15 @@
}
D("socketpair: (%d,%d)", s[0], s[1]);
+#if !ADB_HOST
+ if (func == &file_sync_service) {
+ // Set file sync service socket to maximum size
+ int max_buf = LINUX_MAX_SOCKET_SIZE;
+ adb_setsockopt(s[0], SOL_SOCKET, SO_SNDBUF, &max_buf, sizeof(max_buf));
+ adb_setsockopt(s[1], SOL_SOCKET, SO_SNDBUF, &max_buf, sizeof(max_buf));
+ }
+#endif // !ADB_HOST
+
stinfo* sti = reinterpret_cast<stinfo*>(malloc(sizeof(stinfo)));
if (sti == nullptr) {
fatal("cannot allocate stinfo");
diff --git a/adf/libadf/adf.c b/adf/libadf/adf.c
index c4d6681..10f88b0 100644
--- a/adf/libadf/adf.c
+++ b/adf/libadf/adf.c
@@ -180,6 +180,37 @@
return (int)data.complete_fence;
}
+int adf_device_post_v2(struct adf_device *dev,
+ adf_id_t *interfaces, __u32 n_interfaces,
+ struct adf_buffer_config *bufs, __u32 n_bufs,
+ void *custom_data, __u64 custom_data_size,
+ enum adf_complete_fence_type complete_fence_type,
+ int *complete_fence)
+{
+ int err;
+ struct adf_post_config_v2 data;
+
+ memset(&data, 0, sizeof(data));
+ data.interfaces = (uintptr_t)interfaces;
+ data.n_interfaces = n_interfaces;
+ data.bufs = (uintptr_t)bufs;
+ data.n_bufs = n_bufs;
+ data.custom_data = (uintptr_t)custom_data;
+ data.custom_data_size = custom_data_size;
+ data.complete_fence_type = complete_fence_type;
+
+ err = ioctl(dev->fd, ADF_POST_CONFIG_V2, &data);
+ if (err < 0)
+ return -errno;
+
+ if (complete_fence)
+ *complete_fence = data.complete_fence;
+ else if (data.complete_fence >= 0)
+ close(data.complete_fence);
+
+ return 0;
+}
+
static int adf_device_attachment(struct adf_device *dev,
adf_id_t overlay_engine, adf_id_t interface, bool attach)
{
@@ -421,6 +452,21 @@
return (int)data.fd;
}
+static void adf_interface_simple_post_config_buf(struct adf_buffer_config *buf,
+ __u32 overlay_engine, __u32 w, __u32 h, __u32 format, int buf_fd,
+ __u32 offset, __u32 pitch, int acquire_fence)
+{
+ buf->overlay_engine = overlay_engine;
+ buf->w = w;
+ buf->h = h;
+ buf->format = format;
+ buf->fd[0] = buf_fd;
+ buf->offset[0] = offset;
+ buf->pitch[0] = pitch;
+ buf->n_planes = 1;
+ buf->acquire_fence = acquire_fence;
+}
+
int adf_interface_simple_post(int fd, __u32 overlay_engine,
__u32 w, __u32 h, __u32 format, int buf_fd, __u32 offset,
__u32 pitch, int acquire_fence)
@@ -429,16 +475,8 @@
struct adf_simple_post_config data;
memset(&data, 0, sizeof(data));
- data.buf.overlay_engine = overlay_engine;
- data.buf.w = w;
- data.buf.h = h;
- data.buf.format = format;
- data.buf.fd[0] = buf_fd;
- data.buf.offset[0] = offset;
- data.buf.pitch[0] = pitch;
- data.buf.n_planes = 1;
- data.buf.acquire_fence = acquire_fence;
-
+ adf_interface_simple_post_config_buf(&data.buf, overlay_engine, w, h, format,
+ buf_fd, offset, pitch, acquire_fence);
ret = ioctl(fd, ADF_SIMPLE_POST_CONFIG, &data);
if (ret < 0)
return -errno;
@@ -446,6 +484,32 @@
return (int)data.complete_fence;
}
+int adf_interface_simple_post_v2(int fd, adf_id_t overlay_engine,
+ __u32 w, __u32 h, __u32 format, int buf_fd, __u32 offset,
+ __u32 pitch, int acquire_fence,
+ enum adf_complete_fence_type complete_fence_type,
+ int *complete_fence)
+{
+ int ret;
+ struct adf_simple_post_config_v2 data;
+
+ memset(&data, 0, sizeof(data));
+ adf_interface_simple_post_config_buf(&data.buf, overlay_engine, w, h, format,
+ buf_fd, offset, pitch, acquire_fence);
+ data.complete_fence_type = complete_fence_type;
+
+ ret = ioctl(fd, ADF_SIMPLE_POST_CONFIG_V2, &data);
+ if (ret < 0)
+ return -errno;
+
+ if (complete_fence)
+ *complete_fence = data.complete_fence;
+ else if (data.complete_fence >= 0)
+ close(data.complete_fence);
+
+ return 0;
+}
+
ssize_t adf_overlay_engines(struct adf_device *dev, adf_id_t **overlay_engines)
{
char pattern[64];
diff --git a/adf/libadf/include/adf/adf.h b/adf/libadf/include/adf/adf.h
index b6bda34..e4c7b28 100644
--- a/adf/libadf/include/adf/adf.h
+++ b/adf/libadf/include/adf/adf.h
@@ -75,6 +75,29 @@
struct adf_buffer_config *bufs, size_t n_bufs,
void *custom_data, size_t custom_data_size);
/**
+ * Atomically posts a new display configuration to the specified interfaces.
+ *
+ * Compared to adf_device_post(), adf_device_post_v2():
+ *
+ * (*) allows the client to choose the kind of sync fence returned
+ * (through complete_fence_type)
+ *
+ * (*) stores the returned sync fence fd in a provided buffer, so the client
+ * can distinguish between a permission error (ret = -1) and a successful
+ * call that returns no fence (*complete_fence = -1)
+ *
+ * On error, returns -errno.
+ *
+ * On devices without the corresponding kernel support, returns -ENOTTY.
+ */
+int adf_device_post_v2(struct adf_device *dev,
+ adf_id_t *interfaces, __u32 n_interfaces,
+ struct adf_buffer_config *bufs, __u32 n_bufs,
+ void *custom_data, __u64 custom_data_size,
+ enum adf_complete_fence_type complete_fence_type,
+ int *complete_fence);
+
+/**
* Attaches the specified interface and overlay engine.
*/
int adf_device_attach(struct adf_device *dev, adf_id_t overlay_engine,
@@ -163,6 +186,28 @@
int adf_interface_simple_post(int fd, adf_id_t overlay_engine,
__u32 w, __u32 h, __u32 format, int buf_fd, __u32 offset,
__u32 pitch, int acquire_fence);
+/**
+ * Posts a single-plane RGB buffer to the display using the specified
+ * overlay engine.
+ *
+ * Compared to adf_interface_simple_post(), adf_interface_simple_post_v2():
+ *
+ * (*) allows the client to choose the kind of sync fence returned
+ * (through complete_fence_type)
+ *
+ * (*) stores the returned sync fence fd in a provided buffer, so the client
+ * can distinguish between a permission error (ret = -1) and a successful
+ * call that returns no fence (*complete_fence = -1)
+ *
+ * On error, returns -errno.
+ *
+ * On devices without the corresponding kernel support, returns -ENOTTY.
+ */
+int adf_interface_simple_post_v2(int fd, adf_id_t overlay_engine,
+ __u32 w, __u32 h, __u32 format, int buf_fd, __u32 offset,
+ __u32 pitch, int acquire_fence,
+ enum adf_complete_fence_type complete_fence_type,
+ int *complete_fence);
/**
* Enumerates all overlay engines belonging to an ADF device.
diff --git a/adf/libadf/include/video/adf.h b/adf/libadf/include/video/adf.h
index 77203a5..692a425 100644
--- a/adf/libadf/include/video/adf.h
+++ b/adf/libadf/include/video/adf.h
@@ -49,69 +49,94 @@
ADF_EVENT_DEVICE_CUSTOM = 128,
ADF_EVENT_TYPE_MAX = 255,
};
-struct adf_set_event {
+enum adf_complete_fence_type {
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ ADF_COMPLETE_FENCE_NONE = 0,
+ ADF_COMPLETE_FENCE_PRESENT = 1,
+ ADF_COMPLETE_FENCE_RELEASE = 2,
+};
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+struct adf_set_event {
__u8 type;
__u8 enabled;
};
-struct adf_event {
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+struct adf_event {
__u8 type;
__u32 length;
};
-struct adf_vsync_event {
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+struct adf_vsync_event {
struct adf_event base;
__aligned_u64 timestamp;
};
-struct adf_hotplug_event {
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+struct adf_hotplug_event {
struct adf_event base;
__u8 connected;
};
-#define ADF_MAX_PLANES 4
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define ADF_MAX_PLANES 4
struct adf_buffer_config {
__u32 overlay_engine;
__u32 w;
- __u32 h;
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ __u32 h;
__u32 format;
__s32 fd[ADF_MAX_PLANES];
__u32 offset[ADF_MAX_PLANES];
- __u32 pitch[ADF_MAX_PLANES];
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ __u32 pitch[ADF_MAX_PLANES];
__u8 n_planes;
__s32 acquire_fence;
};
-#define ADF_MAX_BUFFERS (4096 / sizeof(struct adf_buffer_config))
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define ADF_MAX_BUFFERS (4096 / sizeof(struct adf_buffer_config))
struct adf_post_config {
size_t n_interfaces;
__u32 __user * interfaces;
- size_t n_bufs;
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ size_t n_bufs;
struct adf_buffer_config __user * bufs;
size_t custom_data_size;
void __user * custom_data;
- __s32 complete_fence;
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ __s32 complete_fence;
};
+struct adf_post_config_v2 {
+ __u32 n_interfaces;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ __u64 interfaces;
+ __u32 n_bufs;
+ __u64 bufs;
+ __u64 custom_data_size;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ __u64 custom_data;
+ __s32 complete_fence;
+ __u8 complete_fence_type;
+};
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define ADF_MAX_INTERFACES (4096 / sizeof(__u32))
struct adf_simple_buffer_alloc {
__u16 w;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
__u16 h;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
__u32 format;
__s32 fd;
__u32 offset;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
__u32 pitch;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
};
struct adf_simple_post_config {
struct adf_buffer_config buf;
-/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
__s32 complete_fence;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+};
+struct adf_simple_post_config_v2 {
+ struct adf_buffer_config buf;
+ __s32 complete_fence;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+ __u8 complete_fence_type;
};
struct adf_attachment_config {
__u32 overlay_engine;
@@ -177,4 +202,8 @@
#define ADF_ATTACH _IOW(ADF_IOCTL_TYPE, 9, struct adf_attachment_config)
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define ADF_DETACH _IOW(ADF_IOCTL_TYPE, 10, struct adf_attachment_config)
+#define ADF_POST_CONFIG_V2 _IOW(ADF_IOCTL_TYPE, 11, struct adf_post_config_v2)
+#define ADF_SIMPLE_POST_CONFIG_V2 _IOW(ADF_IOCTL_TYPE, 12, struct adf_simple_post_config_v2)
#endif
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+
diff --git a/adf/libadf/original-kernel-headers/video/adf.h b/adf/libadf/original-kernel-headers/video/adf.h
index c5d2e62..8293c1d 100644
--- a/adf/libadf/original-kernel-headers/video/adf.h
+++ b/adf/libadf/original-kernel-headers/video/adf.h
@@ -46,6 +46,15 @@
ADF_EVENT_TYPE_MAX = 255,
};
+enum adf_complete_fence_type {
+ /* no fence */
+ ADF_COMPLETE_FENCE_NONE = 0,
+ /* fence fires when the configuration appears on the screen */
+ ADF_COMPLETE_FENCE_PRESENT = 1,
+ /* fence fires when the configuration leaves the screen */
+ ADF_COMPLETE_FENCE_RELEASE = 2,
+};
+
/**
* struct adf_set_event - start or stop subscribing to ADF events
*
@@ -131,6 +140,9 @@
/**
* struct adf_post_config - request to flip to a new set of buffers
*
+ * This request is equivalent to &struct adf_post_config_v2 with
+ * @complete_fence_type = %ADF_COMPLETE_FENCE_RELEASE.
+ *
* @n_interfaces: number of interfaces targeted by the flip (input)
* @interfaces: ids of interfaces targeted by the flip (input)
* @n_bufs: number of buffers displayed (input)
@@ -152,6 +164,34 @@
__s32 complete_fence;
};
+
+/**
+ * struct adf_post_config_v2 - request to flip to a new set of buffers
+ *
+ * @n_interfaces: number of interfaces targeted by the flip (input)
+ * @interfaces: ids of interfaces targeted by the flip (input)
+ * @n_bufs: number of buffers displayed (input)
+ * @bufs: description of buffers displayed (input)
+ * @custom_data_size: size of driver-private data (input)
+ * @custom_data: driver-private data (input)
+ * @complete_fence_type: one of &enum adf_complete_fence_type describing what
+ * fence to return (input)
+ * @complete_fence: sync_fence fd which will fire at the time
+ * requested by @complete_fence_type (output)
+ */
+struct adf_post_config_v2 {
+ __u32 n_interfaces;
+ __u64 interfaces; /* __u32 * packed into __u64 */
+
+ __u32 n_bufs;
+ __u64 bufs; /* struct adf_buffer_config * packed into __u64 */
+
+ __u64 custom_data_size;
+ __u64 custom_data; /* void * packed into __u64 */
+
+ __s32 complete_fence;
+ __u8 complete_fence_type;
+};
#define ADF_MAX_INTERFACES (4096 / sizeof(__u32))
/**
@@ -189,6 +229,9 @@
* struct adf_simple_post_config - request to flip to a single buffer without
* driver-private data
*
+ * This request is equivalent to &struct adf_simple_post_config_v2 with
+ * @complete_fence_type = %ADF_COMPLETE_FENCE_RELEASE.
+ *
* @buf: description of buffer displayed (input)
* @complete_fence: sync_fence fd which will clear when this buffer has left the
* screen (output)
@@ -199,6 +242,22 @@
};
/**
+ * struct adf_simple_post_config_v2 - request to flip to a single buffer without
+ * driver-private data
+ *
+ * @buf: description of buffer displayed (input)
+ * @complete_fence_type: one of &enum adf_complete_fence_type describing what
+ * fence to return (input)
+ * @complete_fence: sync_fence fd which will fire at the time
+ * requested by @complete_fence_type (output)
+ */
+struct adf_simple_post_config_v2 {
+ struct adf_buffer_config buf;
+ __s32 complete_fence;
+ __u8 complete_fence_type;
+};
+
+/**
* struct adf_attachment_config - description of attachment between an overlay
* engine and an interface
*
@@ -318,4 +377,10 @@
#define ADF_DETACH _IOW(ADF_IOCTL_TYPE, 10, \
struct adf_attachment_config)
+#define ADF_POST_CONFIG_V2 _IOW(ADF_IOCTL_TYPE, 11, \
+ struct adf_post_config_v2)
+#define ADF_SIMPLE_POST_CONFIG_V2 \
+ _IOW(ADF_IOCTL_TYPE, 12, \
+ struct adf_simple_post_config_v2)
+
#endif /* _UAPI_VIDEO_ADF_H_ */
diff --git a/adf/libadf/tests/Android.bp b/adf/libadf/tests/Android.bp
index 7b33300..9b3430e 100644
--- a/adf/libadf/tests/Android.bp
+++ b/adf/libadf/tests/Android.bp
@@ -17,6 +17,7 @@
cc_test {
name: "adf-unit-tests",
srcs: ["adf_test.cpp"],
+ shared_libs: ["libsync"],
static_libs: ["libadf"],
cflags: ["-Werror"],
}
diff --git a/adf/libadf/tests/adf_test.cpp b/adf/libadf/tests/adf_test.cpp
index eaa9342..4727c2b 100644
--- a/adf/libadf/tests/adf_test.cpp
+++ b/adf/libadf/tests/adf_test.cpp
@@ -20,6 +20,7 @@
#include <adf/adf.h>
#include <gtest/gtest.h>
#include <sys/mman.h>
+#include <sync/sync.h>
class AdfTest : public testing::Test {
public:
@@ -73,24 +74,6 @@
FAIL(); /* this should never happen */
}
- void drawCheckerboard(void *buf, uint32_t w, uint32_t h, uint32_t pitch) {
- uint8_t *buf8 = reinterpret_cast<uint8_t *>(buf);
- for (uint32_t y = 0; y < h / 2; y++) {
- uint32_t *scanline = reinterpret_cast<uint32_t *>(buf8 + y * pitch);
- for (uint32_t x = 0; x < w / 2; x++)
- scanline[x] = 0xFF0000FF;
- for (uint32_t x = w / 2; x < w; x++)
- scanline[x] = 0xFF00FFFF;
- }
- for (uint32_t y = h / 2; y < h; y++) {
- uint32_t *scanline = reinterpret_cast<uint32_t *>(buf8 + y * pitch);
- for (uint32_t x = 0; x < w / 2; x++)
- scanline[x] = 0xFFFF00FF;
- for (uint32_t x = w / 2; x < w; x++)
- scanline[x] = 0xFFFFFFFF;
- }
- }
-
/* various helpers to call ADF and die on failure */
void getInterfaceData(adf_interface_data &data) {
@@ -141,6 +124,42 @@
free(event);
}
+ void drawCheckerboard(uint32_t &w, uint32_t &h, uint32_t &format,
+ char format_str[ADF_FORMAT_STR_SIZE], int &buf_fd, uint32_t &offset,
+ uint32_t &pitch) {
+ ASSERT_NO_FATAL_FAILURE(getCurrentMode(w, h));
+ ASSERT_NO_FATAL_FAILURE(get8888Format(format, format_str));
+
+ buf_fd = adf_interface_simple_buffer_alloc(intf, w, h, format, &offset,
+ &pitch);
+ ASSERT_GE(buf_fd, 0) << "allocating " << w << "x" << h << " " <<
+ format_str << " buffer failed: " << strerror(-buf_fd);
+ EXPECT_GE(pitch, w * 4);
+
+ void *mapped = mmap(NULL, pitch * h, PROT_WRITE, MAP_SHARED, buf_fd,
+ offset);
+ ASSERT_NE(mapped, MAP_FAILED) << "mapping " << w << "x" << h << " " <<
+ format_str << " buffer failed: " << strerror(-errno);
+
+ uint8_t *buf8 = static_cast<uint8_t *>(mapped);
+ for (uint32_t y = 0; y < h / 2; y++) {
+ uint32_t *scanline = reinterpret_cast<uint32_t *>(buf8 + y * pitch);
+ for (uint32_t x = 0; x < w / 2; x++)
+ scanline[x] = 0xFF0000FF;
+ for (uint32_t x = w / 2; x < w; x++)
+ scanline[x] = 0xFF00FFFF;
+ }
+ for (uint32_t y = h / 2; y < h; y++) {
+ uint32_t *scanline = reinterpret_cast<uint32_t *>(buf8 + y * pitch);
+ for (uint32_t x = 0; x < w / 2; x++)
+ scanline[x] = 0xFFFF00FF;
+ for (uint32_t x = w / 2; x < w; x++)
+ scanline[x] = 0xFFFFFFFF;
+ }
+
+ munmap(mapped, pitch * h);
+ }
+
protected:
adf_device dev;
adf_id_t intf_id;
@@ -310,27 +329,11 @@
}
TEST_F(AdfTest, simple_buffer) {
- uint32_t w = 0, h = 0;
- ASSERT_NO_FATAL_FAILURE(getCurrentMode(w, h));
-
- uint32_t format = 0;
+ int buf_fd;
+ uint32_t w, h, format, offset, pitch;
char format_str[ADF_FORMAT_STR_SIZE];
- ASSERT_NO_FATAL_FAILURE(get8888Format(format, format_str));
-
- uint32_t offset;
- uint32_t pitch;
- int buf_fd = adf_interface_simple_buffer_alloc(intf, w, h, format, &offset,
- &pitch);
- ASSERT_GE(buf_fd, 0) << "allocating " << w << "x" << h << " " <<
- format_str << " buffer failed: " << strerror(-buf_fd);
- EXPECT_GE(pitch, w * 4);
-
- void *mapped = mmap(NULL, pitch * h, PROT_WRITE, MAP_SHARED, buf_fd,
- offset);
- ASSERT_NE(mapped, MAP_FAILED) << "mapping " << w << "x" << h << " " <<
- format_str << " buffer failed: " << strerror(-errno);
- drawCheckerboard(mapped, w, h, pitch);
- munmap(mapped, pitch * h);
+ ASSERT_NO_FATAL_FAILURE(drawCheckerboard(w, h, format, format_str,
+ buf_fd, offset, pitch));
ASSERT_NO_FATAL_FAILURE(attach());
ASSERT_NO_FATAL_FAILURE(blank(DRM_MODE_DPMS_ON));
@@ -342,3 +345,59 @@
format_str << " buffer failed: " << strerror(-release_fence);
close(release_fence);
}
+
+TEST_F(AdfTest, simple_buffer_v2) {
+ int buf_fd;
+ uint32_t w, h, format, offset, pitch;
+ char format_str[ADF_FORMAT_STR_SIZE];
+ ASSERT_NO_FATAL_FAILURE(drawCheckerboard(w, h, format, format_str,
+ buf_fd, offset, pitch));
+
+ ASSERT_NO_FATAL_FAILURE(attach());
+ ASSERT_NO_FATAL_FAILURE(blank(DRM_MODE_DPMS_ON));
+
+ int config_1_release;
+ int err = adf_interface_simple_post_v2(intf, eng_id, w, h,
+ format, buf_fd, offset, pitch, -1, ADF_COMPLETE_FENCE_RELEASE,
+ &config_1_release);
+ if (err == -ENOTTY) {
+ GTEST_LOG_(INFO) << "ADF_SIMPLE_POST_CONFIG_V2 not supported on this kernel";
+ return;
+ }
+ ASSERT_GE(err, 0) << "posting " << w << "x" << h << " " <<
+ format_str << " buffer failed: " << strerror(-err);
+
+ err = sync_wait(config_1_release, 1000);
+ ASSERT_EQ(-1, err) <<
+ "waiting for config 1's release fence should not have suceeded";
+ ASSERT_EQ(ETIME, errno) <<
+ "config 1's release fence should have timed out, but failed instead: " <<
+ strerror(errno);
+
+ int config_2_present;
+ err = adf_interface_simple_post_v2(intf, eng_id, w, h,
+ format, buf_fd, offset, pitch, -1, ADF_COMPLETE_FENCE_PRESENT,
+ &config_2_present);
+ ASSERT_GE(err, 0) << "posting " << w << "x" << h << " " <<
+ format_str << " buffer failed: " << strerror(-err);
+
+ err = sync_wait(config_2_present, 1000);
+ ASSERT_EQ(0, err) <<
+ "waiting for config 2's present fence failed: " << strerror(errno);
+ err = sync_wait(config_1_release, 0);
+ ASSERT_EQ(0, err) <<
+ "waiting for config 1's release fence failed: " << strerror(errno);
+ close(config_1_release);
+ close(config_2_present);
+
+ int config_3_no_fence;
+ err = adf_interface_simple_post_v2(intf, eng_id, w, h,
+ format, buf_fd, offset, pitch, -1, ADF_COMPLETE_FENCE_NONE,
+ &config_3_no_fence);
+ ASSERT_GE(err, 0) << "posting " << w << "x" << h << " " <<
+ format_str << " buffer failed: " << strerror(-err);
+ ASSERT_EQ(-1, config_3_no_fence) <<
+ "fence returned even though the fence type was ADF_COMPLETE_FENCE_NONE";
+
+ close(buf_fd);
+}
diff --git a/base/Android.bp b/base/Android.bp
index b9a6e0b..694e029 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -44,6 +44,9 @@
"properties.cpp",
],
cppflags: ["-Wexit-time-destructors"],
+ sanitize: {
+ misc_undefined: ["integer"],
+ },
},
darwin: {
srcs: ["errors_unix.cpp"],
@@ -89,6 +92,9 @@
target: {
android: {
srcs: ["properties_test.cpp"],
+ sanitize: {
+ misc_undefined: ["integer"],
+ },
},
windows: {
srcs: ["utf8_test.cpp"],
diff --git a/base/strings.cpp b/base/strings.cpp
index 46fe939..bfdaf12 100644
--- a/base/strings.cpp
+++ b/base/strings.cpp
@@ -36,11 +36,12 @@
size_t base = 0;
size_t found;
- do {
+ while (true) {
found = s.find_first_of(delimiters, base);
result.push_back(s.substr(base, found - base));
+ if (found == s.npos) break;
base = found + 1;
- } while (found != s.npos);
+ }
return result;
}
diff --git a/base/strings_test.cpp b/base/strings_test.cpp
index 7a65a00..7ed5b2b 100644
--- a/base/strings_test.cpp
+++ b/base/strings_test.cpp
@@ -251,3 +251,7 @@
ASSERT_FALSE(android::base::EqualsIgnoreCase("foo", "bar"));
ASSERT_FALSE(android::base::EqualsIgnoreCase("foo", "fool"));
}
+
+TEST(strings, ubsan_28729303) {
+ android::base::Split("/dev/null", ":");
+}
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index a7354a7..a4cc5f2 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -225,7 +225,12 @@
void RecordBootloaderTimings(BootEventRecordStore* boot_event_store) {
// |ro.boot.boottime| is of the form 'stage1:time1,...,stageN:timeN'.
std::string value = GetProperty("ro.boot.boottime");
+ if (value.empty()) {
+ // ro.boot.boottime is not reported on all devices.
+ return;
+ }
+ int32_t total_time = 0;
auto stages = android::base::Split(value, ",");
for (auto const &stageTiming : stages) {
// |stageTiming| is of the form 'stage:time'.
@@ -235,10 +240,13 @@
std::string stageName = stageTimingValues[0];
int32_t time_ms;
if (android::base::ParseInt(stageTimingValues[1], &time_ms)) {
+ total_time += time_ms;
boot_event_store->AddBootEventWithValue(
"boottime.bootloader." + stageName, time_ms);
}
}
+
+ boot_event_store->AddBootEventWithValue("boottime.bootloader.total", total_time);
}
// Records several metrics related to the time it takes to boot the device,
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index ca881aa..8d2ea68 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -12,14 +12,48 @@
}
cc_library_static {
- name: "libdebuggerd_handler",
+ name: "libdebuggerd_handler_core",
defaults: ["debuggerd_defaults"],
srcs: ["handler/debuggerd_handler.cpp"],
// libdebuggerd_handler gets async signal safe logging via libc_logging,
// which defines its interface in bionic private headers.
include_dirs: ["bionic/libc"],
- static_libs: ["libc_logging"],
+ whole_static_libs: [
+ "libc_logging",
+ "libdebuggerd",
+ ],
+
+ export_include_dirs: ["include"],
+}
+
+cc_library_static {
+ name: "libdebuggerd_handler",
+ defaults: ["debuggerd_defaults"],
+ srcs: ["handler/debuggerd_fallback_nop.cpp"],
+
+ whole_static_libs: [
+ "libdebuggerd_handler_core",
+ ],
+
+ export_include_dirs: ["include"],
+}
+
+cc_library_static {
+ name: "libdebuggerd_handler_fallback",
+ defaults: ["debuggerd_defaults"],
+ srcs: ["handler/debuggerd_fallback.cpp"],
+
+ // libdebuggerd_handler gets async signal safe logging via libc_logging,
+ // which defines its interface in bionic private headers.
+ include_dirs: ["bionic/libc"],
+ static_libs: [
+ "libdebuggerd",
+ "libbacktrace",
+ "libunwind",
+ "liblzma",
+ "libcutils",
+ ],
export_include_dirs: ["include"],
}
@@ -39,7 +73,7 @@
export_include_dirs: ["include"],
}
-cc_library {
+cc_library_static {
name: "libdebuggerd",
defaults: ["debuggerd_defaults"],
@@ -75,8 +109,10 @@
local_include_dirs: ["libdebuggerd/include"],
export_include_dirs: ["libdebuggerd/include"],
- shared_libs: [
+ static_libs: [
"libbacktrace",
+ "libunwind",
+ "liblzma",
"libbase",
"libcutils",
"liblog",
@@ -150,10 +186,14 @@
},
},
+ static_libs: [
+ "libdebuggerd",
+ "libcutils",
+ ],
+
shared_libs: [
"libbacktrace",
"libbase",
- "libdebuggerd",
"liblog",
"libprocinfo",
"libselinux",
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 2889356..08b0047 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -155,6 +155,14 @@
return false;
}
+ // Make the fd O_APPEND so that our output is guaranteed to be at the end of a file.
+ // (This also makes selinux rules consistent, because selinux distinguishes between writing to
+ // a regular fd, and writing to an fd with O_APPEND).
+ int flags = fcntl(tmp_output_fd.get(), F_GETFL);
+ if (fcntl(tmp_output_fd.get(), F_SETFL, flags | O_APPEND) != 0) {
+ PLOG(WARNING) << "failed to set output fd flags";
+ }
+
*tombstoned_socket = std::move(sockfd);
*output_fd = std::move(tmp_output_fd);
return true;
@@ -218,7 +226,7 @@
}
if (proc_info.pid != expected_pid) {
- LOG(FATAL) << "pid mismatch: expected " << expected_pid << ", actual " << proc_info.ppid;
+ LOG(FATAL) << "pid mismatch: expected " << expected_pid << ", actual " << proc_info.pid;
}
}
@@ -238,11 +246,12 @@
action.sa_handler = signal_handler;
debuggerd_register_handlers(&action);
- if (argc != 2) {
+ if (argc != 3) {
return 1;
}
pid_t main_tid;
+ pid_t pseudothread_tid;
if (target == 1) {
LOG(FATAL) << "target died before we could attach";
@@ -252,6 +261,10 @@
LOG(FATAL) << "invalid main tid: " << argv[1];
}
+ if (!android::base::ParseInt(argv[2], &pseudothread_tid, 1, std::numeric_limits<pid_t>::max())) {
+ LOG(FATAL) << "invalid pseudothread tid: " << argv[2];
+ }
+
android::procinfo::ProcessInfo target_info;
if (!android::procinfo::GetProcessInfo(main_tid, &target_info)) {
LOG(FATAL) << "failed to fetch process info for target " << main_tid;
@@ -284,16 +297,53 @@
check_process(target_proc_fd, target);
std::string attach_error;
+
+ // Seize the main thread.
if (!ptrace_seize_thread(target_proc_fd, main_tid, &attach_error)) {
LOG(FATAL) << attach_error;
}
+ // Seize the siblings.
+ std::set<pid_t> attached_siblings;
+ {
+ std::set<pid_t> siblings;
+ if (!android::procinfo::GetProcessTids(target, &siblings)) {
+ PLOG(FATAL) << "failed to get process siblings";
+ }
+
+ // but not the already attached main thread.
+ siblings.erase(main_tid);
+ // or the handler pseudothread.
+ siblings.erase(pseudothread_tid);
+
+ for (pid_t sibling_tid : siblings) {
+ if (!ptrace_seize_thread(target_proc_fd, sibling_tid, &attach_error)) {
+ LOG(WARNING) << attach_error;
+ } else {
+ attached_siblings.insert(sibling_tid);
+ }
+ }
+ }
+
+ // Collect the backtrace map and open files, while the process still has PR_GET_DUMPABLE=1
+ std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(main_tid));
+ if (!backtrace_map) {
+ LOG(FATAL) << "failed to create backtrace map";
+ }
+
+ // Collect the list of open files.
+ OpenFilesList open_files;
+ populate_open_files_list(target, &open_files);
+
+ // Drop our capabilities now that we've attached to the threads we care about.
+ drop_capabilities();
check_process(target_proc_fd, target);
LOG(INFO) << "obtaining output fd from tombstoned";
tombstoned_connected = tombstoned_connect(target, &tombstoned_socket, &output_fd);
// Write a '\1' to stdout to tell the crashing process to resume.
+ // It also restores the value of PR_SET_DUMPABLE at this point.
if (TEMP_FAILURE_RETRY(write(STDOUT_FILENO, "\1", 1)) == -1) {
PLOG(ERROR) << "failed to communicate to target process";
}
@@ -339,50 +389,14 @@
abort_address = reinterpret_cast<uintptr_t>(siginfo.si_value.sival_ptr);
}
- // Now that we have the signal that kicked things off, attach all of the
- // sibling threads, and then proceed.
- std::set<pid_t> attached_siblings;
- {
- std::set<pid_t> siblings;
- if (!android::procinfo::GetProcessTids(target, &siblings)) {
- PLOG(FATAL) << "failed to get process siblings";
- }
- siblings.erase(main_tid);
-
- for (pid_t sibling_tid : siblings) {
- if (!ptrace_seize_thread(target_proc_fd, sibling_tid, &attach_error)) {
- LOG(WARNING) << attach_error;
- } else {
- attached_siblings.insert(sibling_tid);
- }
- }
- }
-
- std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(main_tid));
- if (!backtrace_map) {
- LOG(FATAL) << "failed to create backtrace map";
- }
-
- // Collect the list of open files.
- OpenFilesList open_files;
- if (!backtrace) {
- populate_open_files_list(target, &open_files);
- }
-
- // Drop our capabilities now that we've attached to the threads we care about.
- drop_capabilities();
-
- check_process(target_proc_fd, target);
-
// TODO: Use seccomp to lock ourselves down.
std::string amfd_data;
-
if (backtrace) {
dump_backtrace(output_fd.get(), backtrace_map.get(), target, main_tid, attached_siblings, 0);
} else {
- engrave_tombstone(output_fd.get(), backtrace_map.get(), open_files, target, main_tid,
- attached_siblings, abort_address, fatal_signal ? &amfd_data : nullptr);
+ engrave_tombstone(output_fd.get(), backtrace_map.get(), &open_files, target, main_tid,
+ &attached_siblings, abort_address, fatal_signal ? &amfd_data : nullptr);
}
// We don't actually need to PTRACE_DETACH, as long as our tracees aren't in
diff --git a/debuggerd/crasher/crasher.cpp b/debuggerd/crasher/crasher.cpp
index 64a38dd..cd45bbb 100644
--- a/debuggerd/crasher/crasher.cpp
+++ b/debuggerd/crasher/crasher.cpp
@@ -26,6 +26,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
+#include <sys/prctl.h>
#include <unistd.h>
// We test both kinds of logging.
@@ -189,6 +190,8 @@
fprintf(stderr, " readdir-NULL pass a null pointer to readdir\n");
fprintf(stderr, " strlen-NULL pass a null pointer to strlen\n");
fprintf(stderr, "\n");
+ fprintf(stderr, " no_new_privs set PR_SET_NO_NEW_PRIVS and then abort\n");
+ fprintf(stderr, "\n");
fprintf(stderr, "prefix any of the above with 'thread-' to run on a new thread\n");
fprintf(stderr, "prefix any of the above with 'exhaustfd-' to exhaust\n");
fprintf(stderr, "all available file descriptors before crashing.\n");
@@ -276,6 +279,12 @@
} else if (!strcasecmp(arg, "kuser_cmpxchg64")) {
return __kuser_cmpxchg64(0, 0, 0);
#endif
+ } else if (!strcasecmp(arg, "no_new_privs")) {
+ if (prctl(PR_SET_NO_NEW_PRIVS, 1) != 0) {
+ fprintf(stderr, "prctl(PR_SET_NO_NEW_PRIVS, 1) failed: %s\n", strerror(errno));
+ return EXIT_SUCCESS;
+ }
+ abort();
} else {
return usage();
}
diff --git a/debuggerd/handler/debuggerd_fallback.cpp b/debuggerd/handler/debuggerd_fallback.cpp
new file mode 100644
index 0000000..77ad6ac
--- /dev/null
+++ b/debuggerd/handler/debuggerd_fallback.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stddef.h>
+#include <sys/ucontext.h>
+#include <unistd.h>
+
+#include "tombstone.h"
+
+extern "C" void __linker_use_fallback_allocator();
+
+extern "C" bool debuggerd_fallback(ucontext_t* ucontext, siginfo_t* siginfo, void* abort_message) {
+ // This is incredibly sketchy to do inside of a signal handler, especially when libbacktrace
+ // uses the C++ standard library throughout, but this code runs in the linker, so we'll be using
+ // the linker's malloc instead of the libc one. Switch it out for a replacement, just in case.
+ //
+ // This isn't the default method of dumping because it can fail in cases such as memory space
+ // exhaustion.
+ __linker_use_fallback_allocator();
+ engrave_tombstone_ucontext(-1, getpid(), gettid(), reinterpret_cast<uintptr_t>(abort_message),
+ siginfo, ucontext);
+ return true;
+}
diff --git a/debuggerd/handler/debuggerd_fallback_nop.cpp b/debuggerd/handler/debuggerd_fallback_nop.cpp
new file mode 100644
index 0000000..9b3053f
--- /dev/null
+++ b/debuggerd/handler/debuggerd_fallback_nop.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stddef.h>
+#include <sys/ucontext.h>
+#include <unistd.h>
+
+extern "C" bool debuggerd_fallback(ucontext_t*, siginfo_t*, void*) {
+ return false;
+}
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index 353f642..680ba4b 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -62,6 +62,8 @@
#define CRASH_DUMP_PATH "/system/bin/" CRASH_DUMP_NAME
+extern "C" bool debuggerd_fallback(ucontext_t*, siginfo_t*, void*);
+
static debuggerd_callbacks_t g_callbacks;
// Mutex to ensure only one crashing thread dumps itself.
@@ -81,7 +83,7 @@
va_start(args, fmt);
char buf[4096];
- vsnprintf(buf, sizeof(buf), fmt, args);
+ __libc_format_buffer_va_list(buf, sizeof(buf), fmt, args);
fatal("%s: %s", buf, strerror(err));
}
@@ -174,6 +176,41 @@
return (old_action.sa_flags & SA_SIGINFO) != 0;
}
+static void raise_caps() {
+ // Raise CapInh to match CapPrm, so that we can set the ambient bits.
+ __user_cap_header_struct capheader;
+ memset(&capheader, 0, sizeof(capheader));
+ capheader.version = _LINUX_CAPABILITY_VERSION_3;
+ capheader.pid = 0;
+
+ __user_cap_data_struct capdata[2];
+ if (capget(&capheader, &capdata[0]) == -1) {
+ fatal_errno("capget failed");
+ }
+
+ if (capdata[0].permitted != capdata[0].inheritable ||
+ capdata[1].permitted != capdata[1].inheritable) {
+ capdata[0].inheritable = capdata[0].permitted;
+ capdata[1].inheritable = capdata[1].permitted;
+
+ if (capset(&capheader, &capdata[0]) == -1) {
+ __libc_format_log(ANDROID_LOG_ERROR, "libc", "capset failed: %s", strerror(errno));
+ }
+ }
+
+ // Set the ambient capability bits so that crash_dump gets all of our caps and can ptrace us.
+ uint64_t capmask = capdata[0].inheritable;
+ capmask |= static_cast<uint64_t>(capdata[1].inheritable) << 32;
+ for (unsigned long i = 0; i < 64; ++i) {
+ if (capmask & (1 << i)) {
+ if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, i, 0, 0) != 0) {
+ __libc_format_log(ANDROID_LOG_ERROR, "libc", "failed to raise ambient capability %lu: %s",
+ i, strerror(errno));
+ }
+ }
+ }
+}
+
struct debugger_thread_info {
bool crash_dump_started;
pid_t crashing_tid;
@@ -217,14 +254,14 @@
close(pipefds[0]);
close(pipefds[1]);
- // Set all of the ambient capability bits we can, so that crash_dump can ptrace us.
- for (unsigned long i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) != -1; ++i) {
- prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, i, 0, 0);
- }
+ raise_caps();
- char buf[10];
- snprintf(buf, sizeof(buf), "%d", thread_info->crashing_tid);
- execl(CRASH_DUMP_PATH, CRASH_DUMP_NAME, buf, nullptr);
+ char main_tid[10];
+ char pseudothread_tid[10];
+ __libc_format_buffer(main_tid, sizeof(main_tid), "%d", thread_info->crashing_tid);
+ __libc_format_buffer(pseudothread_tid, sizeof(pseudothread_tid), "%d", thread_info->pseudothread_tid);
+
+ execl(CRASH_DUMP_PATH, CRASH_DUMP_NAME, main_tid, pseudothread_tid, nullptr);
fatal_errno("exec failed");
} else {
@@ -294,7 +331,7 @@
// Handler that does crash dumping by forking and doing the processing in the child.
// Do this by ptracing the relevant thread, and then execing debuggerd to do the actual dump.
-static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void*) {
+static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* context) {
int ret = pthread_mutex_lock(&crash_mutex);
if (ret != 0) {
__libc_format_log(ANDROID_LOG_INFO, "libc", "pthread_mutex_lock failed: %s", strerror(ret));
@@ -324,18 +361,22 @@
log_signal_summary(signal_number, info);
- if (prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0) == 1) {
- // The process has NO_NEW_PRIVS enabled, so we can't transition to the crash_dump context.
- __libc_format_log(ANDROID_LOG_INFO, "libc",
- "Suppressing debuggerd output because prctl(PR_GET_NO_NEW_PRIVS)==1");
- resend_signal(info, false);
- return;
- }
-
void* abort_message = nullptr;
if (g_callbacks.get_abort_message) {
abort_message = g_callbacks.get_abort_message();
}
+
+ if (prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0) == 1) {
+ ucontext_t* ucontext = static_cast<ucontext_t*>(context);
+ if (signal_number == DEBUGGER_SIGNAL || !debuggerd_fallback(ucontext, info, abort_message)) {
+ // The process has NO_NEW_PRIVS enabled, so we can't transition to the crash_dump context.
+ __libc_format_log(ANDROID_LOG_INFO, "libc",
+ "Suppressing debuggerd output because prctl(PR_GET_NO_NEW_PRIVS)==1");
+ }
+ resend_signal(info, false);
+ return;
+ }
+
// Populate si_value with the abort message address, if found.
if (abort_message) {
info->si_value.sival_ptr = abort_message;
@@ -349,6 +390,12 @@
.info = info
};
+ // Set PR_SET_DUMPABLE to 1, so that crash_dump can ptrace us.
+ int orig_dumpable = prctl(PR_GET_DUMPABLE);
+ if (prctl(PR_SET_DUMPABLE, 1) != 0) {
+ fatal_errno("failed to set dumpable");
+ }
+
// Essentially pthread_create without CLONE_FILES (see debuggerd_dispatch_pseudothread).
pid_t child_pid =
clone(debuggerd_dispatch_pseudothread, pseudothread_stack,
@@ -364,6 +411,11 @@
// and then wait for it to finish.
__futex_wait(&thread_info.pseudothread_tid, child_pid, nullptr);
+ // Restore PR_SET_DUMPABLE to its original value.
+ if (prctl(PR_SET_DUMPABLE, orig_dumpable) != 0) {
+ fatal_errno("failed to restore dumpable");
+ }
+
// Signals can either be fatal or nonfatal.
// For fatal signals, crash_dump will PTRACE_CONT us with the signal we
// crashed with, so that processes using waitpid on us will see that we
diff --git a/debuggerd/libdebuggerd/include/tombstone.h b/debuggerd/libdebuggerd/include/tombstone.h
index 4ff24af..aed71de 100644
--- a/debuggerd/libdebuggerd/include/tombstone.h
+++ b/debuggerd/libdebuggerd/include/tombstone.h
@@ -35,8 +35,11 @@
/* Creates a tombstone file and writes the crash dump to it. */
void engrave_tombstone(int tombstone_fd, BacktraceMap* map,
- const OpenFilesList& open_files, pid_t pid, pid_t tid,
- const std::set<pid_t>& siblings, uintptr_t abort_msg_address,
+ const OpenFilesList* open_files, pid_t pid, pid_t tid,
+ const std::set<pid_t>* siblings, uintptr_t abort_msg_address,
std::string* amfd_data);
+void engrave_tombstone_ucontext(int tombstone_fd, pid_t pid, pid_t tid, uintptr_t abort_msg_address,
+ siginfo_t* siginfo, ucontext_t* ucontext);
+
#endif // _DEBUGGERD_TOMBSTONE_H
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index ac2c0b6..3166bfc 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -220,14 +220,8 @@
if (!cause.empty()) _LOG(log, logtype::HEADER, "Cause: %s\n", cause.c_str());
}
-static void dump_signal_info(log_t* log, pid_t tid) {
- siginfo_t si;
- memset(&si, 0, sizeof(si));
- if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si) == -1) {
- ALOGE("cannot get siginfo: %s\n", strerror(errno));
- return;
- }
-
+static void dump_signal_info(log_t* log, const siginfo_t* siginfo) {
+ const siginfo_t& si = *siginfo;
char addr_desc[32]; // ", fault addr 0x1234"
if (signal_has_si_addr(si.si_signo, si.si_code)) {
snprintf(addr_desc, sizeof(addr_desc), "%p", si.si_addr);
@@ -241,6 +235,17 @@
dump_probable_cause(log, si);
}
+static void dump_signal_info(log_t* log, pid_t tid) {
+ siginfo_t si;
+ memset(&si, 0, sizeof(si));
+ if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si) == -1) {
+ ALOGE("cannot get siginfo: %s\n", strerror(errno));
+ return;
+ }
+
+ dump_signal_info(log, &si);
+}
+
static void dump_thread_info(log_t* log, pid_t pid, pid_t tid) {
char path[64];
char threadnamebuf[1024];
@@ -649,8 +654,8 @@
// Dumps all information about the specified pid to the tombstone.
static void dump_crash(log_t* log, BacktraceMap* map,
- const OpenFilesList& open_files, pid_t pid, pid_t tid,
- const std::set<pid_t>& siblings, uintptr_t abort_msg_address) {
+ const OpenFilesList* open_files, pid_t pid, pid_t tid,
+ const std::set<pid_t>* siblings, uintptr_t abort_msg_address) {
// don't copy log messages to tombstone unless this is a dev device
char value[PROPERTY_VALUE_MAX];
property_get("ro.debuggable", value, "0");
@@ -664,14 +669,16 @@
dump_logs(log, pid, 5);
}
- if (!siblings.empty()) {
- for (pid_t sibling : siblings) {
+ if (siblings && !siblings->empty()) {
+ for (pid_t sibling : *siblings) {
dump_thread(log, pid, sibling, map, 0, false);
}
}
- _LOG(log, logtype::OPEN_FILES, "\nopen files:\n");
- dump_open_files_list_to_log(open_files, log, " ");
+ if (open_files) {
+ _LOG(log, logtype::OPEN_FILES, "\nopen files:\n");
+ dump_open_files_list_to_log(*open_files, log, " ");
+ }
if (want_logs) {
dump_logs(log, pid, 0);
@@ -732,19 +739,34 @@
}
void engrave_tombstone(int tombstone_fd, BacktraceMap* map,
- const OpenFilesList& open_files, pid_t pid, pid_t tid,
- const std::set<pid_t>& siblings, uintptr_t abort_msg_address,
+ const OpenFilesList* open_files, pid_t pid, pid_t tid,
+ const std::set<pid_t>* siblings, uintptr_t abort_msg_address,
std::string* amfd_data) {
log_t log;
log.current_tid = tid;
log.crashed_tid = tid;
-
- if (tombstone_fd < 0) {
- ALOGE("debuggerd: skipping tombstone write, nothing to do.\n");
- return;
- }
-
log.tfd = tombstone_fd;
log.amfd_data = amfd_data;
dump_crash(&log, map, open_files, pid, tid, siblings, abort_msg_address);
}
+
+void engrave_tombstone_ucontext(int tombstone_fd, pid_t pid, pid_t tid, uintptr_t abort_msg_address,
+ siginfo_t* siginfo, ucontext_t* ucontext) {
+ log_t log;
+ log.current_tid = tid;
+ log.crashed_tid = tid;
+ log.tfd = tombstone_fd;
+ log.amfd_data = nullptr;
+
+ dump_thread_info(&log, pid, tid);
+ dump_signal_info(&log, siginfo);
+
+ std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid));
+ dump_abort_message(backtrace.get(), &log, abort_msg_address);
+ // TODO: Dump registers from the ucontext.
+ if (backtrace->Unwind(0, ucontext)) {
+ dump_backtrace_and_stack(backtrace.get(), &log);
+ } else {
+ ALOGE("Unwind failed: pid = %d, tid = %d", pid, tid);
+ }
+}
diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk
index 956c702..6939428 100644
--- a/fs_mgr/Android.mk
+++ b/fs_mgr/Android.mk
@@ -29,17 +29,11 @@
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/include \
system/vold \
- system/extras/ext4_utils \
- bootable/recovery
+ system/extras/ext4_utils
LOCAL_MODULE:= libfs_mgr
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.cpp b/fs_mgr/fs_mgr.cpp
index be84e8a..1768078 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -103,9 +103,7 @@
char tmpmnt_opts[64] = "errors=remount-ro";
const char *e2fsck_argv[] = {
E2FSCK_BIN,
-#ifndef TARGET_USES_MKE2FS // "-f" only for old ext4 generation tool
"-f",
-#endif
"-y",
blk_device
};
diff --git a/fs_mgr/fs_mgr_slotselect.cpp b/fs_mgr/fs_mgr_slotselect.cpp
index 94b43e4..b30417f 100644
--- a/fs_mgr/fs_mgr_slotselect.cpp
+++ b/fs_mgr/fs_mgr_slotselect.cpp
@@ -25,63 +25,61 @@
#include <stdlib.h>
#include <string.h>
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <cutils/properties.h>
#include "fs_mgr.h"
#include "fs_mgr_priv.h"
-#include "bootloader.h"
-
-// Copies slot_suffix from misc into |out_suffix|. Returns 0 on
-// success, -1 on error or if there is no non-empty slot_suffix.
-static int get_active_slot_suffix_from_misc(struct fstab *fstab,
- char *out_suffix,
- size_t suffix_len)
+// finds slot_suffix in androidboot.slot_suffix kernel command line argument
+// or in the device tree node at /firmware/android/slot_suffix property
+static int get_active_slot_suffix_from_kernel(char *out_suffix,
+ size_t suffix_len)
{
- int n;
- int misc_fd;
- ssize_t num_read;
- struct bootloader_message_ab msg;
-
- misc_fd = -1;
- for (n = 0; n < fstab->num_entries; n++) {
- if (strcmp(fstab->recs[n].mount_point, "/misc") == 0) {
- misc_fd = open(fstab->recs[n].blk_device, O_RDONLY);
- if (misc_fd == -1) {
- PERROR << "Error opening misc partition '"
- << fstab->recs[n].blk_device << "'";
- return -1;
- } else {
- break;
+ std::string cmdline;
+ if (android::base::ReadFileToString("/proc/cmdline", &cmdline)) {
+ for (const auto& entry : android::base::Split(android::base::Trim(cmdline), " ")) {
+ std::vector<std::string> pieces = android::base::Split(entry, "=");
+ if (pieces.size() == 2) {
+ if (pieces[0] == "androidboot.slot_suffix") {
+ strncpy(out_suffix, pieces[1].c_str(), suffix_len);
+ return 0;
+ }
}
}
}
- if (misc_fd == -1) {
- LERROR << "Error finding misc partition";
- return -1;
+ // if we can't find slot_suffix in cmdline, check the DT
+ static constexpr char android_dt_dir[] = "/proc/device-tree/firmware/android";
+ std::string file_name = android::base::StringPrintf("%s/compatible", android_dt_dir);
+ std::string dt_value;
+ if (android::base::ReadFileToString(file_name, &dt_value)) {
+ if (!dt_value.compare("android,firmware")) {
+ LERROR << "Error finding compatible android DT node";
+ return -1;
+ }
+
+ file_name = android::base::StringPrintf("%s/%s", android_dt_dir, "slot_suffix");
+ if (!android::base::ReadFileToString(file_name, &dt_value)) {
+ LERROR << "Error finding slot_suffix in device tree";
+ return -1;
+ }
+
+ // DT entries have a terminating '\0', so 'suffix_len' is safe.
+ strncpy(out_suffix, dt_value.c_str(), suffix_len);
+ return 0;
}
- num_read = TEMP_FAILURE_RETRY(read(misc_fd, &msg, sizeof(msg)));
- // Linux will never return partial reads when reading from block
- // devices so no need to worry about them.
- if (num_read != sizeof(msg)) {
- PERROR << "Error reading bootloader_message";
- close(misc_fd);
- return -1;
- }
- close(misc_fd);
- if (msg.slot_suffix[0] == '\0')
- return -1;
- strncpy(out_suffix, msg.slot_suffix, suffix_len);
- return 0;
+ // slot_suffix missing in kernel cmdline or device tree
+ return -1;
}
-// Gets slot_suffix from either the kernel cmdline / firmware or the
-// misc partition. Sets |out_suffix| on success and returns 0. Returns
-// -1 if slot_suffix could not be determined.
-static int get_active_slot_suffix(struct fstab *fstab, char *out_suffix,
- size_t suffix_len)
+// Gets slot_suffix from either the kernel cmdline / device tree. Sets
+// |out_suffix| on success and returns 0. Returns -1 if slot_suffix could not
+// be determined.
+static int get_active_slot_suffix(char *out_suffix, size_t suffix_len)
{
char propbuf[PROPERTY_VALUE_MAX];
@@ -94,10 +92,11 @@
return 0;
}
- // If we couldn't get the suffix from the kernel cmdline, try the
- // the misc partition.
- if (get_active_slot_suffix_from_misc(fstab, out_suffix, suffix_len) == 0) {
- LINFO << "Using slot suffix '" << out_suffix << "' from misc";
+ // if the property is not set, we are probably being invoked early during
+ // boot. Try to find the slotsuffix ourselves in the kernel command line
+ // or the device tree
+ if (get_active_slot_suffix_from_kernel(out_suffix, suffix_len) == 0) {
+ LINFO << "Using slot suffix '" << out_suffix << "' from kernel";
return 0;
}
@@ -119,8 +118,7 @@
if (!got_suffix) {
memset(suffix, '\0', sizeof(suffix));
- if (get_active_slot_suffix(fstab, suffix,
- sizeof(suffix) - 1) != 0) {
+ if (get_active_slot_suffix(suffix, sizeof(suffix) - 1) != 0) {
return -1;
}
got_suffix = 1;
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index d959798..a9deed9 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -123,6 +123,7 @@
int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab);
int fs_mgr_is_notrim(struct fstab_rec *fstab);
int fs_mgr_is_formattable(struct fstab_rec *fstab);
+int fs_mgr_is_slotselect(struct fstab_rec *fstab);
int fs_mgr_is_nofail(struct fstab_rec *fstab);
int fs_mgr_is_latemount(struct fstab_rec *fstab);
int fs_mgr_is_quota(struct fstab_rec *fstab);
diff --git a/init/devices.cpp b/init/devices.cpp
index 6af237c..b3b808b 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -62,19 +62,7 @@
extern struct selabel_handle *sehandle;
-static int device_fd = -1;
-
-struct uevent {
- const char *action;
- const char *path;
- const char *subsystem;
- const char *firmware;
- const char *partition_name;
- const char *device_name;
- int partition_num;
- int major;
- int minor;
-};
+static android::base::unique_fd device_fd;
struct perms_ {
char *name;
@@ -249,11 +237,13 @@
mode = get_device_perm(path, links, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
- if (selabel_lookup_best_match(sehandle, &secontext, path, links, mode)) {
- PLOG(ERROR) << "Device '" << path << "' not created; cannot find SELinux label";
- return;
+ if (sehandle) {
+ if (selabel_lookup_best_match(sehandle, &secontext, path, links, mode)) {
+ PLOG(ERROR) << "Device '" << path << "' not created; cannot find SELinux label";
+ return;
+ }
+ setfscreatecon(secontext);
}
- setfscreatecon(secontext);
dev = makedev(major, minor);
/* Temporarily change egid to avoid race condition setting the gid of the
@@ -264,7 +254,7 @@
setegid(gid);
/* If the node already exists update its SELinux label to handle cases when
* it was created with the wrong context during coldboot procedure. */
- if (mknod(path, mode, dev) && (errno == EEXIST)) {
+ if (mknod(path, mode, dev) && (errno == EEXIST) && secontext) {
char* fcon = nullptr;
int rc = lgetfilecon(path, &fcon);
@@ -285,8 +275,10 @@
chown(path, uid, -1);
setegid(AID_ROOT);
- freecon(secontext);
- setfscreatecon(NULL);
+ if (secontext) {
+ freecon(secontext);
+ setfscreatecon(NULL);
+ }
}
static void add_platform_device(const char *path)
@@ -349,6 +341,19 @@
}
}
+static void destroy_platform_devices() {
+ struct listnode* node;
+ struct listnode* n;
+ struct platform_node* bus;
+
+ list_for_each_safe(node, n, &platform_names) {
+ list_remove(node);
+ bus = node_to_item(node, struct platform_node, list);
+ free(bus->path);
+ free(bus);
+ }
+}
+
/* Given a path that may start with a PCI device, populate the supplied buffer
* with the PCI domain/bus number and the peripheral ID and return 0.
* If it doesn't start with a PCI device, or there is some error, return -1 */
@@ -515,7 +520,7 @@
return NULL;
memset(links, 0, sizeof(char *) * 4);
- LOG(INFO) << "found " << type << " device " << device;
+ LOG(VERBOSE) << "found " << type << " device " << device;
snprintf(link_path, sizeof(link_path), "/dev/block/%s/%s", type, device);
@@ -875,9 +880,15 @@
}
}
+static bool inline should_stop_coldboot(coldboot_action_t act)
+{
+ return (act == COLDBOOT_STOP || act == COLDBOOT_FINISH);
+}
+
#define UEVENT_MSG_LEN 2048
-static inline void handle_device_fd_with(void (handle_uevent)(struct uevent*))
+static inline coldboot_action_t handle_device_fd_with(
+ std::function<coldboot_action_t(uevent* uevent)> handle_uevent)
{
char msg[UEVENT_MSG_LEN+2];
int n;
@@ -890,14 +901,18 @@
struct uevent uevent;
parse_event(msg, &uevent);
- handle_uevent(&uevent);
+ coldboot_action_t act = handle_uevent(&uevent);
+ if (should_stop_coldboot(act))
+ return act;
}
+
+ return COLDBOOT_CONTINUE;
}
-void handle_device_fd()
+coldboot_action_t handle_device_fd(coldboot_callback fn)
{
- handle_device_fd_with(
- [](struct uevent *uevent) {
+ coldboot_action_t ret = handle_device_fd_with(
+ [&](uevent* uevent) -> coldboot_action_t {
if (selinux_status_updated() > 0) {
struct selabel_handle *sehandle2;
sehandle2 = selinux_android_file_context_handle();
@@ -907,9 +922,21 @@
}
}
- handle_device_event(uevent);
- handle_firmware_event(uevent);
+ // default is to always create the devices
+ coldboot_action_t act = COLDBOOT_CREATE;
+ if (fn) {
+ act = fn(uevent);
+ }
+
+ if (act == COLDBOOT_CREATE || act == COLDBOOT_STOP) {
+ handle_device_event(uevent);
+ handle_firmware_event(uevent);
+ }
+
+ return act;
});
+
+ return ret;
}
/* Coldboot walks parts of the /sys tree and pokes the uevent files
@@ -921,21 +948,24 @@
** socket's buffer.
*/
-static void do_coldboot(DIR *d)
+static coldboot_action_t do_coldboot(DIR *d, coldboot_callback fn)
{
struct dirent *de;
int dfd, fd;
+ coldboot_action_t act = COLDBOOT_CONTINUE;
dfd = dirfd(d);
fd = openat(dfd, "uevent", O_WRONLY);
- if(fd >= 0) {
+ if (fd >= 0) {
write(fd, "add\n", 4);
close(fd);
- handle_device_fd();
+ act = handle_device_fd(fn);
+ if (should_stop_coldboot(act))
+ return act;
}
- while((de = readdir(d))) {
+ while (!should_stop_coldboot(act) && (de = readdir(d))) {
DIR *d2;
if(de->d_type != DT_DIR || de->d_name[0] == '.')
@@ -949,85 +979,31 @@
if(d2 == 0)
close(fd);
else {
- do_coldboot(d2);
+ act = do_coldboot(d2, fn);
closedir(d2);
}
}
+
+ // default is always to continue looking for uevents
+ return act;
}
-static void coldboot(const char *path)
+static coldboot_action_t coldboot(const char *path, coldboot_callback fn)
{
std::unique_ptr<DIR, decltype(&closedir)> d(opendir(path), closedir);
- if(d) {
- do_coldboot(d.get());
- }
-}
-
-static void early_uevent_handler(struct uevent *uevent, const char *base, bool is_block)
-{
- const char *name;
- char devpath[DEVPATH_LEN];
-
- if (is_block && strncmp(uevent->subsystem, "block", 5))
- return;
-
- name = parse_device_name(uevent, MAX_DEV_NAME);
- if (!name) {
- LOG(ERROR) << "Failed to parse dev name from uevent: " << uevent->action
- << " " << uevent->partition_name << " " << uevent->partition_num
- << " " << uevent->major << ":" << uevent->minor;
- return;
+ if (d) {
+ return do_coldboot(d.get(), fn);
}
- snprintf(devpath, sizeof(devpath), "%s%s", base, name);
- make_dir(base, 0755);
-
- dev_t dev = makedev(uevent->major, uevent->minor);
- mode_t mode = 0600 | (is_block ? S_IFBLK : S_IFCHR);
- mknod(devpath, mode, dev);
+ return COLDBOOT_CONTINUE;
}
-void early_create_dev(const std::string& syspath, early_device_type dev_type)
-{
- android::base::unique_fd dfd(open(syspath.c_str(), O_RDONLY));
- if (dfd < 0) {
- LOG(ERROR) << "Failed to open " << syspath;
- return;
- }
-
- android::base::unique_fd fd(openat(dfd, "uevent", O_WRONLY));
- if (fd < 0) {
- LOG(ERROR) << "Failed to open " << syspath << "/uevent";
- return;
- }
-
- fcntl(device_fd, F_SETFL, O_NONBLOCK);
-
- write(fd, "add\n", 4);
- handle_device_fd_with(dev_type == EARLY_BLOCK_DEV ?
- [](struct uevent *uevent) {
- early_uevent_handler(uevent, "/dev/block/", true);
- } :
- [](struct uevent *uevent) {
- early_uevent_handler(uevent, "/dev/", false);
- });
-}
-
-int early_device_socket_open() {
- device_fd = uevent_open_socket(256*1024, true);
- return device_fd < 0;
-}
-
-void early_device_socket_close() {
- close(device_fd);
-}
-
-void device_init() {
+void device_init(const char* path, coldboot_callback fn) {
sehandle = selinux_android_file_context_handle();
selinux_status_open(true);
/* is 256K enough? udev uses 16MB! */
- device_fd = uevent_open_socket(256*1024, true);
+ device_fd.reset(uevent_open_socket(256*1024, true));
if (device_fd == -1) {
return;
}
@@ -1039,13 +1015,33 @@
}
Timer t;
- coldboot("/sys/class");
- coldboot("/sys/block");
- coldboot("/sys/devices");
- close(open(COLDBOOT_DONE, O_WRONLY|O_CREAT|O_CLOEXEC, 0000));
+ coldboot_action_t act;
+ if (!path) {
+ act = coldboot("/sys/class", fn);
+ if (!should_stop_coldboot(act)) {
+ act = coldboot("/sys/block", fn);
+ if (!should_stop_coldboot(act)) {
+ act = coldboot("/sys/devices", fn);
+ }
+ }
+ } else {
+ act = coldboot(path, fn);
+ }
+
+ // If we have a callback, then do as it says. If no, then the default is
+ // to always create COLDBOOT_DONE file.
+ if (!fn || (act == COLDBOOT_FINISH)) {
+ close(open(COLDBOOT_DONE, O_WRONLY|O_CREAT|O_CLOEXEC, 0000));
+ }
+
LOG(INFO) << "Coldboot took " << t;
}
+void device_close() {
+ destroy_platform_devices();
+ device_fd.reset();
+}
+
int get_device_fd() {
return device_fd;
}
diff --git a/init/devices.h b/init/devices.h
index 8e9ab7d..26a064b 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -17,16 +17,37 @@
#ifndef _INIT_DEVICES_H
#define _INIT_DEVICES_H
+#include <functional>
#include <sys/stat.h>
-extern void handle_device_fd();
-extern void device_init(void);
+enum coldboot_action_t {
+ // coldboot continues without creating the device for the uevent
+ COLDBOOT_CONTINUE = 0,
+ // coldboot continues after creating the device for the uevent
+ COLDBOOT_CREATE,
+ // coldboot stops after creating the device for uevent but doesn't
+ // create the COLDBOOT_DONE file
+ COLDBOOT_STOP,
+ // same as COLDBOOT_STOP, but creates the COLDBOOT_DONE file
+ COLDBOOT_FINISH
+};
-enum early_device_type { EARLY_BLOCK_DEV, EARLY_CHAR_DEV };
+struct uevent {
+ const char* action;
+ const char* path;
+ const char* subsystem;
+ const char* firmware;
+ const char* partition_name;
+ const char* device_name;
+ int partition_num;
+ int major;
+ int minor;
+};
-extern int early_device_socket_open();
-extern void early_device_socket_close();
-extern void early_create_dev(const std::string& syspath, early_device_type dev_type);
+typedef std::function<coldboot_action_t(struct uevent* uevent)> coldboot_callback;
+extern coldboot_action_t handle_device_fd(coldboot_callback fn = nullptr);
+extern void device_init(const char* path = nullptr, coldboot_callback fn = nullptr);
+extern void device_close();
extern int add_dev_perms(const char *name, const char *attr,
mode_t perm, unsigned int uid,
diff --git a/init/init.cpp b/init/init.cpp
index 43f601f..7f7eb2f 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -47,6 +47,7 @@
#include <cutils/iosched_policy.h>
#include <cutils/list.h>
#include <cutils/sockets.h>
+#include <libavb/libavb.h>
#include <private/android_filesystem_config.h>
#include <fstream>
@@ -495,28 +496,48 @@
}
}
-static void process_kernel_dt() {
- static const char android_dir[] = "/proc/device-tree/firmware/android";
+static constexpr char android_dt_dir[] = "/proc/device-tree/firmware/android";
- std::string file_name = StringPrintf("%s/compatible", android_dir);
+static bool is_dt_compatible() {
+ std::string dt_value;
+ std::string file_name = StringPrintf("%s/compatible", android_dt_dir);
- std::string dt_file;
- android::base::ReadFileToString(file_name, &dt_file);
- if (!dt_file.compare("android,firmware")) {
+ android::base::ReadFileToString(file_name, &dt_value);
+ if (!dt_value.compare("android,firmware")) {
LOG(ERROR) << "firmware/android is not compatible with 'android,firmware'";
- return;
+ return false;
}
- std::unique_ptr<DIR, int(*)(DIR*)>dir(opendir(android_dir), closedir);
+ return true;
+}
+
+static bool is_dt_fstab_compatible() {
+ std::string dt_value;
+ std::string file_name = StringPrintf("%s/%s/compatible", android_dt_dir, "fstab");
+
+ android::base::ReadFileToString(file_name, &dt_value);
+ if (!dt_value.compare("android,fstab")) {
+ LOG(ERROR) << "firmware/android/fstab is not compatible with 'android,fstab'";
+ return false;
+ }
+
+ return true;
+}
+
+static void process_kernel_dt() {
+ if (!is_dt_compatible()) return;
+
+ std::unique_ptr<DIR, int(*)(DIR*)>dir(opendir(android_dt_dir), closedir);
if (!dir) return;
+ std::string dt_file;
struct dirent *dp;
while ((dp = readdir(dir.get())) != NULL) {
if (dp->d_type != DT_REG || !strcmp(dp->d_name, "compatible") || !strcmp(dp->d_name, "name")) {
continue;
}
- file_name = StringPrintf("%s/%s", android_dir, dp->d_name);
+ std::string file_name = StringPrintf("%s/%s", android_dt_dir, dp->d_name);
android::base::ReadFileToString(file_name, &dt_file);
std::replace(dt_file.begin(), dt_file.end(), ',', '.');
@@ -643,102 +664,208 @@
}
}
-/* Returns a new path consisting of base_path and the file name in reference_path. */
-static std::string get_path(const std::string& base_path, const std::string& reference_path) {
- std::string::size_type pos = reference_path.rfind('/');
- if (pos == std::string::npos) {
- return base_path + '/' + reference_path;
- } else {
- return base_path + reference_path.substr(pos);
+static std::string import_dt_fstab() {
+ std::string fstab;
+ if (!is_dt_compatible() || !is_dt_fstab_compatible()) {
+ return fstab;
}
-}
-/* Imports the fstab info from cmdline. */
-static std::string import_cmdline_fstab() {
- std::string prefix, fstab, fstab_full;
+ std::string fstabdir_name = StringPrintf("%s/fstab", android_dt_dir);
+ std::unique_ptr<DIR, int (*)(DIR*)> fstabdir(opendir(fstabdir_name.c_str()), closedir);
+ if (!fstabdir) return fstab;
- import_kernel_cmdline(false,
- [&](const std::string& key, const std::string& value, bool in_qemu __attribute__((__unused__))) {
- if (key == "android.early.prefix") {
- prefix = value;
- } else if (key == "android.early.fstab") {
- fstab = value;
- }
- });
- if (!fstab.empty()) {
- // Convert "mmcblk0p09+/odm+ext4+ro+verify" to "mmcblk0p09 /odm ext4 ro verify"
- std::replace(fstab.begin(), fstab.end(), '+', ' ');
- for (const auto& entry : android::base::Split(fstab, "\n")) {
- fstab_full += prefix + entry + '\n';
+ dirent* dp;
+ while ((dp = readdir(fstabdir.get())) != NULL) {
+ // skip over name and compatible
+ if (dp->d_type != DT_DIR) {
+ continue;
}
+
+ // skip if its not 'vendor', 'odm' or 'system'
+ if (strcmp(dp->d_name, "odm") && strcmp(dp->d_name, "system") &&
+ strcmp(dp->d_name, "vendor")) {
+ continue;
+ }
+
+ // create <dev> <mnt_point> <type> <mnt_flags> <fsmgr_flags>\n
+ std::vector<std::string> fstab_entry;
+ std::string file_name;
+ std::string value;
+ file_name = StringPrintf("%s/%s/dev", fstabdir_name.c_str(), dp->d_name);
+ if (!android::base::ReadFileToString(file_name, &value)) {
+ LOG(ERROR) << "dt_fstab: Failed to find device for partition " << dp->d_name;
+ fstab.clear();
+ break;
+ }
+ // trim the terminating '\0' out
+ value.resize(value.size() - 1);
+ fstab_entry.push_back(value);
+ fstab_entry.push_back(StringPrintf("/%s", dp->d_name));
+
+ file_name = StringPrintf("%s/%s/type", fstabdir_name.c_str(), dp->d_name);
+ if (!android::base::ReadFileToString(file_name, &value)) {
+ LOG(ERROR) << "dt_fstab: Failed to find type for partition " << dp->d_name;
+ fstab.clear();
+ break;
+ }
+ value.resize(value.size() - 1);
+ fstab_entry.push_back(value);
+
+ file_name = StringPrintf("%s/%s/mnt_flags", fstabdir_name.c_str(), dp->d_name);
+ if (!android::base::ReadFileToString(file_name, &value)) {
+ LOG(ERROR) << "dt_fstab: Failed to find type for partition " << dp->d_name;
+ fstab.clear();
+ break;
+ }
+ value.resize(value.size() - 1);
+ fstab_entry.push_back(value);
+
+ file_name = StringPrintf("%s/%s/fsmgr_flags", fstabdir_name.c_str(), dp->d_name);
+ if (!android::base::ReadFileToString(file_name, &value)) {
+ LOG(ERROR) << "dt_fstab: Failed to find type for partition " << dp->d_name;
+ fstab.clear();
+ break;
+ }
+ value.resize(value.size() - 1);
+ fstab_entry.push_back(value);
+
+ fstab += android::base::Join(fstab_entry, " ");
+ fstab += '\n';
}
- return fstab_full;
+
+ return fstab;
}
-/* Early mount vendor and ODM partitions. The fstab info is read from kernel cmdline. */
-static void early_mount() {
- std::string fstab_string = import_cmdline_fstab();
- if (fstab_string.empty()) {
- LOG(INFO) << "Failed to load vendor fstab from kernel cmdline";
- return;
+/* Early mount vendor and ODM partitions. The fstab is read from device-tree. */
+static bool early_mount() {
+ std::string fstab = import_dt_fstab();
+ if (fstab.empty()) {
+ LOG(INFO) << "Early mount skipped (missing fstab in device tree)";
+ return true;
}
- FILE *fstab_file = fmemopen((void *)fstab_string.c_str(), fstab_string.length(), "r");
+
+ std::unique_ptr<FILE, decltype(&fclose)> fstab_file(
+ fmemopen(static_cast<void*>(const_cast<char*>(fstab.c_str())), fstab.length(), "r"), fclose);
if (!fstab_file) {
- PLOG(ERROR) << "Failed to open fstab string as FILE";
- return;
- }
- std::unique_ptr<struct fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_file(fstab_file), fs_mgr_free_fstab);
- fclose(fstab_file);
- if (!fstab) {
- LOG(ERROR) << "Failed to parse fstab string: " << fstab_string;
- return;
- }
- LOG(INFO) << "Loaded vendor fstab from cmdline";
-
- if (early_device_socket_open()) {
- LOG(ERROR) << "Failed to open device uevent socket";
- return;
+ PLOG(ERROR) << "Early mount failed to open fstab file in memory";
+ return false;
}
- /* Create /dev/device-mapper for dm-verity */
- early_create_dev("/sys/devices/virtual/misc/device-mapper", EARLY_CHAR_DEV);
+ std::unique_ptr<struct fstab, decltype(&fs_mgr_free_fstab)> tab(
+ fs_mgr_read_fstab_file(fstab_file.get()), fs_mgr_free_fstab);
+ if (!tab) {
+ LOG(ERROR) << "Early mount fsmgr failed to load fstab from kernel:" << std::endl << fstab;
+ return false;
+ }
- for (int i = 0; i < fstab->num_entries; ++i) {
- struct fstab_rec *rec = &fstab->recs[i];
- std::string mount_point = rec->mount_point;
- std::string syspath = rec->blk_device;
+ // find out fstab records for odm, system and vendor
+ fstab_rec* odm_rec = fs_mgr_get_entry_for_mount_point(tab.get(), "/odm");
+ fstab_rec* system_rec = fs_mgr_get_entry_for_mount_point(tab.get(), "/system");
+ fstab_rec* vendor_rec = fs_mgr_get_entry_for_mount_point(tab.get(), "/vendor");
+ if (!odm_rec && !system_rec && !vendor_rec) {
+ // nothing to early mount
+ return true;
+ }
- if (mount_point != "/vendor" && mount_point != "/odm")
- continue;
+ // assume A/B device if we find 'slotselect' in any fstab entry
+ bool is_ab = ((odm_rec && fs_mgr_is_slotselect(odm_rec)) ||
+ (system_rec && fs_mgr_is_slotselect(system_rec)) ||
+ (vendor_rec && fs_mgr_is_slotselect(vendor_rec)));
+ bool found_odm = !odm_rec;
+ bool found_system = !system_rec;
+ bool found_vendor = !vendor_rec;
+ int count_odm = 0, count_vendor = 0, count_system = 0;
- /* Create mount target under /dev/block/ from sysfs via uevent */
- LOG(INFO) << "Mounting " << mount_point << " from " << syspath << "...";
- char *devpath = strdup(get_path("/dev/block", syspath).c_str());
- if (!devpath) {
- PLOG(ERROR) << "Failed to strdup dev path in early mount " << syspath;
- continue;
- }
- rec->blk_device = devpath;
- early_create_dev(syspath, EARLY_BLOCK_DEV);
-
- int rc = fs_mgr_early_setup_verity(rec);
- if (rc == FS_MGR_EARLY_SETUP_VERITY_SUCCESS) {
- /* Mount target is changed to /dev/block/dm-<n>; initiate its creation from sysfs counterpart */
- early_create_dev(get_path("/sys/devices/virtual/block", rec->blk_device), EARLY_BLOCK_DEV);
- } else if (rc == FS_MGR_EARLY_SETUP_VERITY_FAIL) {
- LOG(ERROR) << "Failed to set up dm-verity on " << rec->blk_device;
- continue;
- } else { /* FS_MGR_EARLY_SETUP_VERITY_NO_VERITY */
- LOG(INFO) << "dm-verity disabled on debuggable device; mount directly on " << rec->blk_device;
+ // create the devices we need..
+ device_init(nullptr, [&](uevent* uevent) -> coldboot_action_t {
+ if (!strncmp(uevent->subsystem, "firmware", 8)) {
+ return COLDBOOT_CONTINUE;
}
- mkdir(mount_point.c_str(), 0755);
- rc = mount(rec->blk_device, mount_point.c_str(), rec->fs_type, rec->flags, rec->fs_options);
- if (rc) {
- PLOG(ERROR) << "Failed to mount on " << rec->blk_device;
+ // we need platform devices to create symlinks
+ if (!strncmp(uevent->subsystem, "platform", 8)) {
+ return COLDBOOT_CREATE;
}
+
+ // Ignore everything that is not a block device
+ if (strncmp(uevent->subsystem, "block", 5)) {
+ return COLDBOOT_CONTINUE;
+ }
+
+ coldboot_action_t ret;
+ bool create_this_node = false;
+ if (uevent->partition_name) {
+ // prefix match partition names so we create device nodes for
+ // A/B-ed partitions
+ if (!found_odm && !strncmp(uevent->partition_name, "odm", 3)) {
+ LOG(VERBOSE) << "early_mount: found (" << uevent->partition_name << ") partition";
+
+ // wait twice for A/B-ed partitions
+ count_odm++;
+ if (!is_ab) {
+ found_odm = true;
+ } else if (count_odm == 2) {
+ found_odm = true;
+ }
+
+ create_this_node = true;
+ } else if (!found_system && !strncmp(uevent->partition_name, "system", 6)) {
+ LOG(VERBOSE) << "early_mount: found (" << uevent->partition_name << ") partition";
+
+ count_system++;
+ if (!is_ab) {
+ found_system = true;
+ } else if (count_system == 2) {
+ found_system = true;
+ }
+
+ create_this_node = true;
+ } else if (!found_vendor && !strncmp(uevent->partition_name, "vendor", 6)) {
+ LOG(VERBOSE) << "early_mount: found (" << uevent->partition_name << ") partition";
+ count_vendor++;
+ if (!is_ab) {
+ found_vendor = true;
+ } else if (count_vendor == 2) {
+ found_vendor = true;
+ }
+
+ create_this_node = true;
+ }
+ }
+
+ // if we found all other partitions already, create this
+ // node and stop coldboot. If this is a prefix matched
+ // partition, create device node and continue. For everything
+ // else skip the device node
+ if (found_odm && found_system && found_vendor) {
+ ret = COLDBOOT_STOP;
+ } else if (create_this_node) {
+ ret = COLDBOOT_CREATE;
+ } else {
+ ret = COLDBOOT_CONTINUE;
+ }
+
+ return ret;
+ });
+
+ // TODO: add support to mount partitions w/ verity
+
+ int ret = 0;
+ if (odm_rec &&
+ (ret = fs_mgr_do_mount(tab.get(), odm_rec->mount_point, odm_rec->blk_device, NULL))) {
+ PLOG(ERROR) << "early_mount: fs_mgr_do_mount returned error for mounting odm";
+ return false;
}
- early_device_socket_close();
+
+ if (vendor_rec &&
+ (ret = fs_mgr_do_mount(tab.get(), vendor_rec->mount_point, vendor_rec->blk_device, NULL))) {
+ PLOG(ERROR) << "early_mount: fs_mgr_do_mount returned error for mounting vendor";
+ return false;
+ }
+
+ device_close();
+
+ return true;
}
int main(int argc, char** argv) {
@@ -787,8 +914,10 @@
LOG(INFO) << "init " << (is_first_stage ? "first" : "second") << " stage started!";
if (is_first_stage) {
- // Mount devices defined in android.early.* kernel commandline
- early_mount();
+ if (!early_mount()) {
+ LOG(ERROR) << "Failed to mount required partitions early ...";
+ panic();
+ }
// Set up SELinux, loading the SELinux policy.
selinux_initialize(true);
@@ -831,6 +960,9 @@
property_set("ro.boottime.init", getenv("INIT_STARTED_AT"));
property_set("ro.boottime.init.selinux", getenv("INIT_SELINUX_TOOK"));
+ // Set libavb version for Framework-only OTA match in Treble build.
+ property_set("ro.boot.init.avb_version", std::to_string(AVB_MAJOR_VERSION).c_str());
+
// Clean up our environment.
unsetenv("INIT_SECOND_STAGE");
unsetenv("INIT_STARTED_AT");
diff --git a/liblog/logd_reader.c b/liblog/logd_reader.c
index 9411f36..ccc7da8 100644
--- a/liblog/logd_reader.c
+++ b/liblog/logd_reader.c
@@ -91,7 +91,7 @@
static int logdAvailable(log_id_t logId)
{
- if (logId >= LOG_ID_MAX || logId == LOG_ID_KERNEL) {
+ if (logId > LOG_ID_KERNEL) {
return -EINVAL;
}
if (logId == LOG_ID_SECURITY) {
diff --git a/rootdir/init.zygote32_64.rc b/rootdir/init.zygote32_64.rc
index ed11164..80bb673 100644
--- a/rootdir/init.zygote32_64.rc
+++ b/rootdir/init.zygote32_64.rc
@@ -11,7 +11,7 @@
onrestart restart media
onrestart restart netd
onrestart restart wificond
- writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
+ writepid /dev/cpuset/foreground/tasks
service zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
class main
diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc
index 66e7750..36bb443 100644
--- a/rootdir/init.zygote64_32.rc
+++ b/rootdir/init.zygote64_32.rc
@@ -11,7 +11,7 @@
onrestart restart media
onrestart restart netd
onrestart restart wificond
- writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
+ writepid /dev/cpuset/foreground/tasks
service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
class main