Merge "[adb] Print fewer progress messages for push/pull" into rvc-dev
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index 14ccfbe..2199fd3 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -1423,13 +1423,13 @@
 #endif
 }
 
-static bool _is_valid_fd(int fd) {
+static bool _is_valid_os_fd(int fd) {
     // Disallow invalid FDs and stdin/out/err as well.
     if (fd < 3) {
         return false;
     }
 #ifdef _WIN32
-    HANDLE handle = adb_get_os_handle(fd);
+    auto handle = (HANDLE)fd;
     DWORD info = 0;
     if (GetHandleInformation(handle, &info) == 0) {
         return false;
@@ -2005,7 +2005,7 @@
 #endif
         }
         int connection_fd = atoi(argv[1]);
-        if (!_is_valid_fd(connection_fd)) {
+        if (!_is_valid_os_fd(connection_fd)) {
             error_exit("Invalid connection_fd number given: %d", connection_fd);
         }
 
@@ -2013,7 +2013,7 @@
         close_on_exec(connection_fd);
 
         int output_fd = atoi(argv[2]);
-        if (!_is_valid_fd(output_fd)) {
+        if (!_is_valid_os_fd(output_fd)) {
             error_exit("Invalid output_fd number given: %d", output_fd);
         }
         output_fd = adb_register_socket(output_fd);
diff --git a/adb/client/incremental.cpp b/adb/client/incremental.cpp
index fd608cc..a9e65dc 100644
--- a/adb/client/incremental.cpp
+++ b/adb/client/incremental.cpp
@@ -41,8 +41,7 @@
 
 static inline int32_t read_int32(borrowed_fd fd) {
     int32_t result;
-    ReadFully(fd, &result, sizeof(result));
-    return result;
+    return ReadFdExactly(fd, &result, sizeof(result)) ? result : -1;
 }
 
 static inline void append_int(borrowed_fd fd, std::vector<char>* bytes) {
@@ -54,11 +53,14 @@
 
 static inline void append_bytes_with_size(borrowed_fd fd, std::vector<char>* bytes) {
     int32_t le_size = read_int32(fd);
+    if (le_size < 0) {
+        return;
+    }
     int32_t size = int32_t(le32toh(le_size));
     auto old_size = bytes->size();
     bytes->resize(old_size + sizeof(le_size) + size);
     memcpy(bytes->data() + old_size, &le_size, sizeof(le_size));
-    ReadFully(fd, bytes->data() + old_size + sizeof(le_size), size);
+    ReadFdExactly(fd, bytes->data() + old_size + sizeof(le_size), size);
 }
 
 static inline std::pair<std::vector<char>, int32_t> read_id_sig_headers(borrowed_fd fd) {
@@ -200,7 +202,7 @@
         return {};
     }
     auto [pipe_read_fd, pipe_write_fd] = print_fds;
-    auto pipe_write_fd_param = std::to_string(pipe_write_fd);
+    auto pipe_write_fd_param = std::to_string(intptr_t(adb_get_os_handle(pipe_write_fd)));
     close_on_exec(pipe_read_fd);
 
     std::vector<std::string> args(std::move(files));
diff --git a/adb/client/incremental_server.cpp b/adb/client/incremental_server.cpp
index 1f47de8..737563c 100644
--- a/adb/client/incremental_server.cpp
+++ b/adb/client/incremental_server.cpp
@@ -228,7 +228,7 @@
     std::vector<char> pendingBlocks_;
 
     // True when client notifies that all the data has been received
-    bool servingComplete_;
+    bool servingComplete_ = false;
 };
 
 bool IncrementalServer::SkipToRequest(void* buffer, size_t* size, bool blocking) {
diff --git a/adb/client/incremental_utils.cpp b/adb/client/incremental_utils.cpp
index 316480c..caadb26 100644
--- a/adb/client/incremental_utils.cpp
+++ b/adb/client/incremental_utils.cpp
@@ -18,6 +18,7 @@
 
 #include "incremental_utils.h"
 
+#include <android-base/mapped_file.h>
 #include <android-base/strings.h>
 #include <ziparchive/zip_archive.h>
 #include <ziparchive/zip_writer.h>
@@ -26,6 +27,7 @@
 #include <numeric>
 #include <unordered_set>
 
+#include "adb_trace.h"
 #include "sysdeps.h"
 
 static constexpr int kBlockSize = 4096;
@@ -155,18 +157,81 @@
     return zipPriorityBlocks;
 }
 
-// TODO(b/151676293): avoid using OpenArchiveFd that reads local file headers
+[[maybe_unused]] static ZipArchiveHandle openZipArchiveFd(int fd) {
+    bool transferFdOwnership = false;
+#ifdef _WIN32
+    //
+    // Need to create a special CRT FD here as the current one is not compatible with
+    // normal read()/write() calls that libziparchive uses.
+    // To make this work we have to create a copy of the file handle, as CRT doesn't care
+    // and closes it together with the new descriptor.
+    //
+    // Note: don't move this into a helper function, it's better to be hard to reuse because
+    //       the code is ugly and won't work unless it's a last resort.
+    //
+    auto handle = adb_get_os_handle(fd);
+    HANDLE dupedHandle;
+    if (!::DuplicateHandle(::GetCurrentProcess(), handle, ::GetCurrentProcess(), &dupedHandle, 0,
+                           false, DUPLICATE_SAME_ACCESS)) {
+        D("%s failed at DuplicateHandle: %d", __func__, (int)::GetLastError());
+        return {};
+    }
+    fd = _open_osfhandle((intptr_t)dupedHandle, _O_RDONLY | _O_BINARY);
+    if (fd < 0) {
+        D("%s failed at _open_osfhandle: %d", __func__, errno);
+        ::CloseHandle(handle);
+        return {};
+    }
+    transferFdOwnership = true;
+#endif
+    ZipArchiveHandle zip;
+    if (OpenArchiveFd(fd, "apk_fd", &zip, transferFdOwnership) != 0) {
+        D("%s failed at OpenArchiveFd: %d", __func__, errno);
+#ifdef _WIN32
+        // "_close()" is a secret WinCRT name for the regular close() function.
+        _close(fd);
+#endif
+        return {};
+    }
+    return zip;
+}
+
+static std::pair<ZipArchiveHandle, std::unique_ptr<android::base::MappedFile>> openZipArchive(
+        int fd, int64_t fileSize) {
+#ifndef __LP64__
+    if (fileSize >= INT_MAX) {
+        return {openZipArchiveFd(fd), nullptr};
+    }
+#endif
+    auto mapping =
+            android::base::MappedFile::FromOsHandle(adb_get_os_handle(fd), 0, fileSize, PROT_READ);
+    if (!mapping) {
+        D("%s failed at FromOsHandle: %d", __func__, errno);
+        return {};
+    }
+    ZipArchiveHandle zip;
+    if (OpenArchiveFromMemory(mapping->data(), mapping->size(), "apk_mapping", &zip) != 0) {
+        D("%s failed at OpenArchiveFromMemory: %d", __func__, errno);
+        return {};
+    }
+    return {zip, std::move(mapping)};
+}
+
+// TODO(b/151676293): avoid using libziparchive as it reads local file headers
 // which causes additional performance cost. Instead, only read from central directory.
 static std::vector<int32_t> InstallationPriorityBlocks(int fd, int64_t fileSize) {
-    std::vector<int32_t> installationPriorityBlocks;
-    ZipArchiveHandle zip;
-    if (OpenArchiveFd(fd, "", &zip, false) != 0) {
+    auto [zip, _] = openZipArchive(fd, fileSize);
+    if (!zip) {
         return {};
     }
+
     void* cookie = nullptr;
     if (StartIteration(zip, &cookie) != 0) {
+        D("%s failed at StartIteration: %d", __func__, errno);
         return {};
     }
+
+    std::vector<int32_t> installationPriorityBlocks;
     ZipEntry entry;
     std::string_view entryName;
     while (Next(cookie, &entry, &entryName) == 0) {
@@ -183,6 +248,7 @@
             int32_t endBlockIndex = offsetToBlockIndex(entryEndOffset);
             int32_t numNewBlocks = endBlockIndex - startBlockIndex + 1;
             appendBlocks(startBlockIndex, numNewBlocks, &installationPriorityBlocks);
+            D("\tadding to priority blocks: '%.*s'", (int)entryName.size(), entryName.data());
         } else if (entryName == "classes.dex") {
             // Only the head is needed for installation
             int32_t startBlockIndex = offsetToBlockIndex(entry.offset);
@@ -213,4 +279,4 @@
     unduplicate(priorityBlocks);
     return priorityBlocks;
 }
-}  // namespace incremental
\ No newline at end of file
+}  // namespace incremental
diff --git a/adb/fdevent/fdevent.cpp b/adb/fdevent/fdevent.cpp
index 562f587..fd55020 100644
--- a/adb/fdevent/fdevent.cpp
+++ b/adb/fdevent/fdevent.cpp
@@ -63,7 +63,10 @@
 
     int fd_num = fd.get();
 
-    fdevent* fde = new fdevent();
+    auto [it, inserted] = this->installed_fdevents_.emplace(fd_num, fdevent{});
+    CHECK(inserted);
+
+    fdevent* fde = &it->second;
     fde->id = fdevent_id_++;
     fde->state = 0;
     fde->fd = std::move(fd);
@@ -76,10 +79,6 @@
         LOG(ERROR) << "failed to set non-blocking mode for fd " << fde->fd.get();
     }
 
-    auto [it, inserted] = this->installed_fdevents_.emplace(fd_num, fde);
-    CHECK(inserted);
-    UNUSED(it);
-
     this->Register(fde);
     return fde;
 }
@@ -92,12 +91,12 @@
 
     this->Unregister(fde);
 
-    auto erased = this->installed_fdevents_.erase(fde->fd.get());
+    unique_fd fd = std::move(fde->fd);
+
+    auto erased = this->installed_fdevents_.erase(fd.get());
     CHECK_EQ(1UL, erased);
 
-    unique_fd result = std::move(fde->fd);
-    delete fde;
-    return result;
+    return fd;
 }
 
 void fdevent_context::Add(fdevent* fde, unsigned events) {
@@ -123,9 +122,9 @@
 
     for (const auto& [fd, fde] : this->installed_fdevents_) {
         UNUSED(fd);
-        auto timeout_opt = fde->timeout;
+        auto timeout_opt = fde.timeout;
         if (timeout_opt) {
-            auto deadline = fde->last_active + *timeout_opt;
+            auto deadline = fde.last_active + *timeout_opt;
             auto time_left = duration_cast<std::chrono::milliseconds>(deadline - now);
             if (time_left < 0ms) {
                 time_left = 0ms;
@@ -194,11 +193,13 @@
 #endif
 }
 
-static auto& g_ambient_fdevent_context =
-        *new std::unique_ptr<fdevent_context>(fdevent_create_context());
+static auto& g_ambient_fdevent_context() {
+    static auto context = fdevent_create_context().release();
+    return context;
+}
 
 static fdevent_context* fdevent_get_ambient() {
-    return g_ambient_fdevent_context.get();
+    return g_ambient_fdevent_context();
 }
 
 fdevent* fdevent_create(int fd, fd_func func, void* arg) {
@@ -256,5 +257,6 @@
 }
 
 void fdevent_reset() {
-    g_ambient_fdevent_context = fdevent_create_context();
+    auto old = std::exchange(g_ambient_fdevent_context(), fdevent_create_context().release());
+    delete old;
 }
diff --git a/adb/fdevent/fdevent.h b/adb/fdevent/fdevent.h
index 86814d7..9fc3b2c 100644
--- a/adb/fdevent/fdevent.h
+++ b/adb/fdevent/fdevent.h
@@ -52,6 +52,20 @@
     unsigned events;
 };
 
+struct fdevent final {
+    uint64_t id;
+
+    unique_fd fd;
+    int force_eof = 0;
+
+    uint16_t state = 0;
+    std::optional<std::chrono::milliseconds> timeout;
+    std::chrono::steady_clock::time_point last_active;
+
+    std::variant<fd_func, fd_func2> func;
+    void* arg = nullptr;
+};
+
 struct fdevent_context {
   public:
     virtual ~fdevent_context() = default;
@@ -113,7 +127,7 @@
     std::atomic<bool> terminate_loop_ = false;
 
   protected:
-    std::unordered_map<int, fdevent*> installed_fdevents_;
+    std::unordered_map<int, fdevent> installed_fdevents_;
 
   private:
     uint64_t fdevent_id_ = 0;
@@ -121,20 +135,6 @@
     std::deque<std::function<void()>> run_queue_ GUARDED_BY(run_queue_mutex_);
 };
 
-struct fdevent {
-    uint64_t id;
-
-    unique_fd fd;
-    int force_eof = 0;
-
-    uint16_t state = 0;
-    std::optional<std::chrono::milliseconds> timeout;
-    std::chrono::steady_clock::time_point last_active;
-
-    std::variant<fd_func, fd_func2> func;
-    void* arg = nullptr;
-};
-
 // Backwards compatibility shims that forward to the global fdevent_context.
 fdevent* fdevent_create(int fd, fd_func func, void* arg);
 fdevent* fdevent_create(int fd, fd_func2 func, void* arg);
diff --git a/adb/fdevent/fdevent_epoll.cpp b/adb/fdevent/fdevent_epoll.cpp
index e3d1674..4ef41d1 100644
--- a/adb/fdevent/fdevent_epoll.cpp
+++ b/adb/fdevent/fdevent_epoll.cpp
@@ -155,15 +155,15 @@
             event_map[fde] = events;
         }
 
-        for (const auto& [fd, fde] : installed_fdevents_) {
+        for (auto& [fd, fde] : installed_fdevents_) {
             unsigned events = 0;
-            if (auto it = event_map.find(fde); it != event_map.end()) {
+            if (auto it = event_map.find(&fde); it != event_map.end()) {
                 events = it->second;
             }
 
             if (events == 0) {
-                if (fde->timeout) {
-                    auto deadline = fde->last_active + *fde->timeout;
+                if (fde.timeout) {
+                    auto deadline = fde.last_active + *fde.timeout;
                     if (deadline < post_poll) {
                         events |= FDE_TIMEOUT;
                     }
@@ -171,13 +171,13 @@
             }
 
             if (events != 0) {
-                LOG(DEBUG) << dump_fde(fde) << " got events " << std::hex << std::showbase
+                LOG(DEBUG) << dump_fde(&fde) << " got events " << std::hex << std::showbase
                            << events;
-                fde_events.push_back({fde, events});
-                fde->last_active = post_poll;
+                fde_events.push_back({&fde, events});
+                fde.last_active = post_poll;
             }
         }
-        this->HandleEvents(std::move(fde_events));
+        this->HandleEvents(fde_events);
         fde_events.clear();
     }
 
diff --git a/adb/fdevent/fdevent_epoll.h b/adb/fdevent/fdevent_epoll.h
index 684fa32..6214d2e 100644
--- a/adb/fdevent/fdevent_epoll.h
+++ b/adb/fdevent/fdevent_epoll.h
@@ -47,12 +47,7 @@
   protected:
     virtual void Interrupt() final;
 
-  public:
-    // All operations to fdevent should happen only in the main thread.
-    // That's why we don't need a lock for fdevent.
-    std::unordered_map<int, fdevent*> epoll_node_map_;
-    std::list<fdevent*> pending_list_;
-
+  private:
     unique_fd epoll_fd_;
     unique_fd interrupt_fd_;
     fdevent* interrupt_fde_ = nullptr;
diff --git a/adb/fdevent/fdevent_poll.cpp b/adb/fdevent/fdevent_poll.cpp
index cc4a7a1..ac86c08 100644
--- a/adb/fdevent/fdevent_poll.cpp
+++ b/adb/fdevent/fdevent_poll.cpp
@@ -103,24 +103,27 @@
 void fdevent_context_poll::Loop() {
     main_thread_id_ = android::base::GetThreadId();
 
+    std::vector<adb_pollfd> pollfds;
+    std::vector<fdevent_event> poll_events;
+
     while (true) {
         if (terminate_loop_) {
             break;
         }
 
         D("--- --- waiting for events");
-        std::vector<adb_pollfd> pollfds;
+        pollfds.clear();
         for (const auto& [fd, fde] : this->installed_fdevents_) {
             adb_pollfd pfd;
             pfd.fd = fd;
             pfd.events = 0;
-            if (fde->state & FDE_READ) {
+            if (fde.state & FDE_READ) {
                 pfd.events |= POLLIN;
             }
-            if (fde->state & FDE_WRITE) {
+            if (fde.state & FDE_WRITE) {
                 pfd.events |= POLLOUT;
             }
-            if (fde->state & FDE_ERROR) {
+            if (fde.state & FDE_ERROR) {
                 pfd.events |= POLLERR;
             }
 #if defined(__linux__)
@@ -147,7 +150,6 @@
         }
 
         auto post_poll = std::chrono::steady_clock::now();
-        std::vector<fdevent_event> poll_events;
 
         for (const auto& pollfd : pollfds) {
             unsigned events = 0;
@@ -170,7 +172,7 @@
 
             auto it = this->installed_fdevents_.find(pollfd.fd);
             CHECK(it != this->installed_fdevents_.end());
-            fdevent* fde = it->second;
+            fdevent* fde = &it->second;
 
             if (events == 0) {
                 if (fde->timeout) {
@@ -187,7 +189,8 @@
                 fde->last_active = post_poll;
             }
         }
-        this->HandleEvents(std::move(poll_events));
+        this->HandleEvents(poll_events);
+        poll_events.clear();
     }
 
     main_thread_id_.reset();
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 4efbc02..3e781b8 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -276,6 +276,7 @@
 class Process {
   public:
     constexpr explicit Process(HANDLE h = nullptr) : h_(h) {}
+    constexpr Process(Process&& other) : h_(std::exchange(other.h_, nullptr)) {}
     ~Process() { close(); }
     constexpr explicit operator bool() const { return h_ != nullptr; }
 
@@ -292,6 +293,8 @@
     }
 
   private:
+    DISALLOW_COPY_AND_ASSIGN(Process);
+
     void close() {
         if (*this) {
             ::CloseHandle(h_);
@@ -666,6 +669,8 @@
 class Process {
   public:
     constexpr explicit Process(pid_t pid) : pid_(pid) {}
+    constexpr Process(Process&& other) : pid_(std::exchange(other.pid_, -1)) {}
+
     constexpr explicit operator bool() const { return pid_ >= 0; }
 
     void wait() {
@@ -682,6 +687,8 @@
     }
 
   private:
+    DISALLOW_COPY_AND_ASSIGN(Process);
+
     pid_t pid_;
 };
 
diff --git a/fastboot/bootimg_utils.cpp b/fastboot/bootimg_utils.cpp
index 46d4bd3..2c0989e 100644
--- a/fastboot/bootimg_utils.cpp
+++ b/fastboot/bootimg_utils.cpp
@@ -34,14 +34,54 @@
 #include <stdlib.h>
 #include <string.h>
 
-void bootimg_set_cmdline(boot_img_hdr_v2* h, const std::string& cmdline) {
+static void bootimg_set_cmdline_v3(boot_img_hdr_v3* h, const std::string& cmdline) {
     if (cmdline.size() >= sizeof(h->cmdline)) die("command line too large: %zu", cmdline.size());
     strcpy(reinterpret_cast<char*>(h->cmdline), cmdline.c_str());
 }
 
+void bootimg_set_cmdline(boot_img_hdr_v2* h, const std::string& cmdline) {
+    if (h->header_version == 3) {
+        return bootimg_set_cmdline_v3(reinterpret_cast<boot_img_hdr_v3*>(h), cmdline);
+    }
+    if (cmdline.size() >= sizeof(h->cmdline)) die("command line too large: %zu", cmdline.size());
+    strcpy(reinterpret_cast<char*>(h->cmdline), cmdline.c_str());
+}
+
+static boot_img_hdr_v3* mkbootimg_v3(const std::vector<char>& kernel,
+                                     const std::vector<char>& ramdisk, const boot_img_hdr_v2& src,
+                                     std::vector<char>* out) {
+#define V3_PAGE_SIZE 4096
+    const size_t page_mask = V3_PAGE_SIZE - 1;
+    int64_t kernel_actual = (kernel.size() + page_mask) & (~page_mask);
+    int64_t ramdisk_actual = (ramdisk.size() + page_mask) & (~page_mask);
+
+    int64_t bootimg_size = V3_PAGE_SIZE + kernel_actual + ramdisk_actual;
+    out->resize(bootimg_size);
+
+    boot_img_hdr_v3* hdr = reinterpret_cast<boot_img_hdr_v3*>(out->data());
+
+    memcpy(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE);
+    hdr->kernel_size = kernel.size();
+    hdr->ramdisk_size = ramdisk.size();
+    hdr->os_version = src.os_version;
+    hdr->header_size = sizeof(boot_img_hdr_v3);
+    hdr->header_version = 3;
+
+    memcpy(hdr->magic + V3_PAGE_SIZE, kernel.data(), kernel.size());
+    memcpy(hdr->magic + V3_PAGE_SIZE + kernel_actual, ramdisk.data(), ramdisk.size());
+
+    return hdr;
+}
+
 boot_img_hdr_v2* mkbootimg(const std::vector<char>& kernel, const std::vector<char>& ramdisk,
                            const std::vector<char>& second, const std::vector<char>& dtb,
                            size_t base, const boot_img_hdr_v2& src, std::vector<char>* out) {
+    if (src.header_version == 3) {
+        if (!second.empty() || !dtb.empty()) {
+            die("Second stage bootloader and dtb not supported in v3 boot image\n");
+        }
+        return reinterpret_cast<boot_img_hdr_v2*>(mkbootimg_v3(kernel, ramdisk, src, out));
+    }
     const size_t page_mask = src.page_size - 1;
 
     int64_t header_actual = (sizeof(boot_img_hdr_v1) + page_mask) & (~page_mask);
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 7fdc28b..7f6e723 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -464,7 +464,7 @@
     }
 
     // Is this actually a boot image?
-    if (kernel_data.size() < sizeof(boot_img_hdr_v2)) {
+    if (kernel_data.size() < sizeof(boot_img_hdr_v3)) {
         die("cannot load '%s': too short", kernel.c_str());
     }
     if (!memcmp(kernel_data.data(), BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
@@ -493,7 +493,7 @@
 
     std::vector<char> dtb_data;
     if (!g_dtb_path.empty()) {
-        if (g_boot_img_hdr.header_version < 2) {
+        if (g_boot_img_hdr.header_version != 2) {
                     die("Argument dtb not supported for boot image header version %d\n",
                         g_boot_img_hdr.header_version);
         }
diff --git a/init/init.cpp b/init/init.cpp
index b29dfa3..4289dcf 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -713,8 +713,15 @@
     InitKernelLogging(argv);
     LOG(INFO) << "init second stage started!";
 
-    // Will handle EPIPE at the time of write by checking the errno
-    signal(SIGPIPE, SIG_IGN);
+    // Init should not crash because of a dependence on any other process, therefore we ignore
+    // SIGPIPE and handle EPIPE at the call site directly.  Note that setting a signal to SIG_IGN
+    // is inherited across exec, but custom signal handlers are not.  Since we do not want to
+    // ignore SIGPIPE for child processes, we set a no-op function for the signal handler instead.
+    {
+        struct sigaction action = {.sa_flags = SA_RESTART};
+        action.sa_handler = [](int) {};
+        sigaction(SIGPIPE, &action, nullptr);
+    }
 
     // Set init and its forked children's oom_adj.
     if (auto result =
diff --git a/libstats/pull/include/stats_pull_atom_callback.h b/libstats/pull/include/stats_pull_atom_callback.h
index ad9b04e..0b0df2b 100644
--- a/libstats/pull/include/stats_pull_atom_callback.h
+++ b/libstats/pull/include/stats_pull_atom_callback.h
@@ -112,6 +112,8 @@
  * invoke the callback when the stats service determines that this atom needs to be
  * pulled.
  *
+ * Requires the REGISTER_STATS_PULL_ATOM permission.
+ *
  * \param atom_tag          The tag of the atom for this pull atom callback.
  * \param metadata          Optional metadata specifying the timeout, cool down time, and
  *                          additive fields for mapping isolated to host uids.
@@ -128,6 +130,8 @@
  * Unregisters a callback for an atom when that atom is to be pulled. Note that any ongoing
  * pulls will still occur.
  *
+ * Requires the REGISTER_STATS_PULL_ATOM permission.
+ *
  * \param atomTag           The tag of the atom of which to unregister
  */
 void AStatsManager_unregisterPullAtomCallback(int32_t atom_tag);
diff --git a/storaged/main.cpp b/storaged/main.cpp
index a7bda14..bbed210 100644
--- a/storaged/main.cpp
+++ b/storaged/main.cpp
@@ -71,6 +71,7 @@
     bool flag_dump_perf = false;
     int opt;
 
+    signal(SIGPIPE, SIG_IGN);
     android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));
 
     for (;;) {