Merge "Allow firmware loading from ODM partition"
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index d9185d9..40ebde0 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -242,6 +242,10 @@
     {"watchdog_nonsec", 102},
     {"watchdog_apps_bark", 103},
     {"reboot_dmverity_corrupted", 104},
+    {"reboot_smpl", 105},
+    {"watchdog_sdi_apps_reset", 106},
+    {"smpl", 107},
+    {"oem_modem_failed_to_powerup", 108},
 };
 
 // Converts a string value representing the reason the system booted to an
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 725c42c..a0ba81b 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -417,7 +417,7 @@
        "memory map (%zu entr%s):",
        map->size(), map->size() == 1 ? "y" : "ies");
   if (print_fault_address_marker) {
-    if (map->begin() != map->end() && addr < map->begin()->start) {
+    if (map->begin() != map->end() && addr < (*map->begin())->start) {
       _LOG(log, logtype::MAPS, "\n--->Fault address falls at %s before any mapped regions\n",
            get_addr_string(addr).c_str());
       print_fault_address_marker = false;
@@ -429,49 +429,50 @@
   }
 
   std::string line;
-  for (BacktraceMap::const_iterator it = map->begin(); it != map->end(); ++it) {
+  for (auto it = map->begin(); it != map->end(); ++it) {
+    const backtrace_map_t* entry = *it;
     line = "    ";
     if (print_fault_address_marker) {
-      if (addr < it->start) {
+      if (addr < entry->start) {
         _LOG(log, logtype::MAPS, "--->Fault address falls at %s between mapped regions\n",
              get_addr_string(addr).c_str());
         print_fault_address_marker = false;
-      } else if (addr >= it->start && addr < it->end) {
+      } else if (addr >= entry->start && addr < entry->end) {
         line = "--->";
         print_fault_address_marker = false;
       }
     }
-    line += get_addr_string(it->start) + '-' + get_addr_string(it->end - 1) + ' ';
-    if (it->flags & PROT_READ) {
+    line += get_addr_string(entry->start) + '-' + get_addr_string(entry->end - 1) + ' ';
+    if (entry->flags & PROT_READ) {
       line += 'r';
     } else {
       line += '-';
     }
-    if (it->flags & PROT_WRITE) {
+    if (entry->flags & PROT_WRITE) {
       line += 'w';
     } else {
       line += '-';
     }
-    if (it->flags & PROT_EXEC) {
+    if (entry->flags & PROT_EXEC) {
       line += 'x';
     } else {
       line += '-';
     }
-    line += StringPrintf("  %8" PRIxPTR "  %8" PRIxPTR, it->offset, it->end - it->start);
+    line += StringPrintf("  %8" PRIxPTR "  %8" PRIxPTR, entry->offset, entry->end - entry->start);
     bool space_needed = true;
-    if (it->name.length() > 0) {
+    if (entry->name.length() > 0) {
       space_needed = false;
-      line += "  " + it->name;
+      line += "  " + entry->name;
       std::string build_id;
-      if ((it->flags & PROT_READ) && elf_get_build_id(backtrace, it->start, &build_id)) {
+      if ((entry->flags & PROT_READ) && elf_get_build_id(backtrace, entry->start, &build_id)) {
         line += " (BuildId: " + build_id + ")";
       }
     }
-    if (it->load_bias != 0) {
+    if (entry->load_bias != 0) {
       if (space_needed) {
         line += ' ';
       }
-      line += StringPrintf(" (load bias 0x%" PRIxPTR ")", it->load_bias);
+      line += StringPrintf(" (load bias 0x%" PRIxPTR ")", entry->load_bias);
     }
     _LOG(log, logtype::MAPS, "%s\n", line.c_str());
   }
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index b0b2337..e0f702d 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -39,7 +39,7 @@
 LOCAL_MODULE_TAGS := debug
 LOCAL_MODULE_HOST_OS := darwin linux windows
 LOCAL_CFLAGS += -Wall -Wextra -Werror -Wunreachable-code
-LOCAL_REQUIRED_MODULES := mke2fs e2fsdroid make_f2fs
+LOCAL_REQUIRED_MODULES := mke2fs e2fsdroid mke2fs.conf make_f2fs
 
 LOCAL_SRC_FILES_linux := usb_linux.cpp
 LOCAL_STATIC_LIBRARIES_linux := libselinux
diff --git a/fastboot/fs.cpp b/fastboot/fs.cpp
index 4bf7af8..fe5cbc3 100644
--- a/fastboot/fs.cpp
+++ b/fastboot/fs.cpp
@@ -23,11 +23,12 @@
 #include <android-base/stringprintf.h>
 #include <android-base/unique_fd.h>
 
+using android::base::GetExecutableDirectory;
 using android::base::StringPrintf;
 using android::base::unique_fd;
 
 #ifdef WIN32
-static int exec_e2fs_cmd(const char* /*path*/, char* const argv[]) {
+static int exec_e2fs_cmd(const char* /*path*/, const char** argv, const char** envp) {
     std::string cmd;
     int i = 0;
     while (argv[i] != nullptr) {
@@ -44,7 +45,13 @@
     si.cb = sizeof(si);
     ZeroMemory(&pi, sizeof(pi));
 
-    SetEnvironmentVariableA("MKE2FS_CONFIG", "");
+    std::string env_str;
+    if (envp != nullptr) {
+        while (*envp != nullptr) {
+            env_str += std::string(*envp) + std::string("\0", 1);
+            envp++;
+        }
+    }
 
     if (!CreateProcessA(nullptr,                         // No module name (use command line)
                         const_cast<char*>(cmd.c_str()),  // Command line
@@ -52,10 +59,10 @@
                         nullptr,                         // Thread handle not inheritable
                         FALSE,                           // Set handle inheritance to FALSE
                         0,                               // No creation flags
-                        nullptr,                         // Use parent's environment block
-                        nullptr,                         // Use parent's starting directory
-                        &si,                             // Pointer to STARTUPINFO structure
-                        &pi)                             // Pointer to PROCESS_INFORMATION structure
+                        env_str.empty() ? nullptr : LPSTR(env_str.c_str()),
+                        nullptr,  // Use parent's starting directory
+                        &si,      // Pointer to STARTUPINFO structure
+                        &pi)      // Pointer to PROCESS_INFORMATION structure
     ) {
         fprintf(stderr, "CreateProcess failed: %s\n",
                 android::base::SystemErrorCodeToString(GetLastError()).c_str());
@@ -72,12 +79,11 @@
     return exit_code != 0;
 }
 #else
-static int exec_e2fs_cmd(const char* path, char* const argv[]) {
+static int exec_e2fs_cmd(const char* path, const char** argv, const char** envp) {
     int status;
     pid_t child;
     if ((child = fork()) == 0) {
-        setenv("MKE2FS_CONFIG", "", 1);
-        execvp(path, argv);
+        execvpe(path, const_cast<char**>(argv), const_cast<char**>(envp));
         _exit(EXIT_FAILURE);
     }
     if (child < 0) {
@@ -131,7 +137,10 @@
     mke2fs_args.push_back(size_str.c_str());
     mke2fs_args.push_back(nullptr);
 
-    int ret = exec_e2fs_cmd(mke2fs_args[0], const_cast<char**>(mke2fs_args.data()));
+    const std::string mke2fs_env = "MKE2FS_CONFIG=" + GetExecutableDirectory() + "/mke2fs.conf";
+    std::vector<const char*> mke2fs_envp = {mke2fs_env.c_str(), nullptr};
+
+    int ret = exec_e2fs_cmd(mke2fs_args[0], mke2fs_args.data(), mke2fs_envp.data());
     if (ret != 0) {
         fprintf(stderr, "mke2fs failed: %d\n", ret);
         return -1;
@@ -145,7 +154,7 @@
     std::vector<const char*> e2fsdroid_args = {e2fsdroid_path.c_str(), "-f", initial_dir.c_str(),
                                                fileName, nullptr};
 
-    ret = exec_e2fs_cmd(e2fsdroid_args[0], const_cast<char**>(e2fsdroid_args.data()));
+    ret = exec_e2fs_cmd(e2fsdroid_args[0], e2fsdroid_args.data(), nullptr);
     if (ret != 0) {
         fprintf(stderr, "e2fsdroid failed: %d\n", ret);
         return -1;
@@ -173,7 +182,7 @@
     mkf2fs_args.push_back(fileName);
     mkf2fs_args.push_back(nullptr);
 
-    int ret = exec_e2fs_cmd(mkf2fs_args[0], const_cast<char**>(mkf2fs_args.data()));
+    int ret = exec_e2fs_cmd(mkf2fs_args[0], mkf2fs_args.data(), nullptr);
     if (ret != 0) {
         fprintf(stderr, "mkf2fs failed: %d\n", ret);
         return -1;
diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp
index 0e31495..0f1ae11 100644
--- a/libbacktrace/BacktraceMap.cpp
+++ b/libbacktrace/BacktraceMap.cpp
@@ -40,9 +40,10 @@
 
 void BacktraceMap::FillIn(uintptr_t addr, backtrace_map_t* map) {
   ScopedBacktraceMapIteratorLock lock(this);
-  for (BacktraceMap::const_iterator it = begin(); it != end(); ++it) {
-    if (addr >= it->start && addr < it->end) {
-      *map = *it;
+  for (auto it = begin(); it != end(); ++it) {
+    const backtrace_map_t* entry = *it;
+    if (addr >= entry->start && addr < entry->end) {
+      *map = *entry;
       return;
     }
   }
diff --git a/libbacktrace/UnwindStackMap.cpp b/libbacktrace/UnwindStackMap.cpp
index 9ac0a0b..836a774 100644
--- a/libbacktrace/UnwindStackMap.cpp
+++ b/libbacktrace/UnwindStackMap.cpp
@@ -71,8 +71,19 @@
   if (map_info == nullptr) {
     return;
   }
-  unwindstack::Elf* elf = map_info->GetElf(process_memory_, true);
-  map->load_bias = elf->GetLoadBias();
+  map->load_bias = map_info->GetLoadBias(process_memory_);
+}
+
+uint64_t UnwindStackMap::GetLoadBias(size_t index) {
+  if (index >= stack_maps_->Total()) {
+    return 0;
+  }
+
+  unwindstack::MapInfo* map_info = stack_maps_->Get(index);
+  if (map_info == nullptr) {
+    return 0;
+  }
+  return map_info->GetLoadBias(process_memory_);
 }
 
 std::string UnwindStackMap::GetFunctionName(uintptr_t pc, uintptr_t* offset) {
diff --git a/libbacktrace/UnwindStackMap.h b/libbacktrace/UnwindStackMap.h
index bc432e7..2f63655 100644
--- a/libbacktrace/UnwindStackMap.h
+++ b/libbacktrace/UnwindStackMap.h
@@ -42,6 +42,8 @@
   const std::shared_ptr<unwindstack::Memory>& process_memory() { return process_memory_; }
 
  protected:
+  uint64_t GetLoadBias(size_t index) override;
+
   std::unique_ptr<unwindstack::Maps> stack_maps_;
   std::shared_ptr<unwindstack::Memory> process_memory_;
 };
diff --git a/libbacktrace/backtrace_offline_test.cpp b/libbacktrace/backtrace_offline_test.cpp
index 0a1f33d..0935660 100644
--- a/libbacktrace/backtrace_offline_test.cpp
+++ b/libbacktrace/backtrace_offline_test.cpp
@@ -171,10 +171,12 @@
   testdata += android::base::StringPrintf("pid: %d tid: %d\n", getpid(), arg.tid);
   // 2. Dump maps
   for (auto it = map->begin(); it != map->end(); ++it) {
-    testdata += android::base::StringPrintf(
-        "map: start: %" PRIxPTR " end: %" PRIxPTR " offset: %" PRIxPTR " load_bias: %" PRIxPTR
-        " flags: %d name: %s\n",
-        it->start, it->end, it->offset, it->load_bias, it->flags, it->name.c_str());
+    const backtrace_map_t* entry = *it;
+    testdata +=
+        android::base::StringPrintf("map: start: %" PRIxPTR " end: %" PRIxPTR " offset: %" PRIxPTR
+                                    " load_bias: %" PRIxPTR " flags: %d name: %s\n",
+                                    entry->start, entry->end, entry->offset, entry->load_bias,
+                                    entry->flags, entry->name.c_str());
   }
   // 3. Dump registers
   testdata += android::base::StringPrintf("registers: %zu ", sizeof(arg.unw_context));
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index 9911e74..890ab3f 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -857,6 +857,34 @@
 
 static bool map_sort(map_test_t i, map_test_t j) { return i.start < j.start; }
 
+static std::string GetTestMapsAsString(const std::vector<map_test_t>& maps) {
+  if (maps.size() == 0) {
+    return "No test map entries\n";
+  }
+  std::string map_txt;
+  for (auto map : maps) {
+    map_txt += android::base::StringPrintf("%" PRIxPTR "-%" PRIxPTR "\n", map.start, map.end);
+  }
+  return map_txt;
+}
+
+static std::string GetMapsAsString(BacktraceMap* maps) {
+  if (maps->size() == 0) {
+    return "No map entries\n";
+  }
+  std::string map_txt;
+  for (const backtrace_map_t* map : *maps) {
+    map_txt += android::base::StringPrintf(
+        "%" PRIxPTR "-%" PRIxPTR " flags: 0x%x offset: 0x%" PRIxPTR " load_bias: 0x%" PRIxPTR,
+        map->start, map->end, map->flags, map->offset, map->load_bias);
+    if (!map->name.empty()) {
+      map_txt += ' ' + map->name;
+    }
+    map_txt += '\n';
+  }
+  return map_txt;
+}
+
 static void VerifyMap(pid_t pid) {
   char buffer[4096];
   snprintf(buffer, sizeof(buffer), "/proc/%d/maps", pid);
@@ -875,12 +903,20 @@
   std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(pid));
 
   // Basic test that verifies that the map is in the expected order.
-  ScopedBacktraceMapIteratorLock lock(map.get());
-  std::vector<map_test_t>::const_iterator test_it = test_maps.begin();
-  for (BacktraceMap::const_iterator it = map->begin(); it != map->end(); ++it) {
-    ASSERT_TRUE(test_it != test_maps.end());
-    ASSERT_EQ(test_it->start, it->start);
-    ASSERT_EQ(test_it->end, it->end);
+  auto test_it = test_maps.begin();
+  for (auto it = map->begin(); it != map->end(); ++it) {
+    ASSERT_TRUE(test_it != test_maps.end()) << "Mismatch in number of maps, expected test maps:\n"
+                                            << GetTestMapsAsString(test_maps) << "Actual maps:\n"
+                                            << GetMapsAsString(map.get());
+    ASSERT_EQ(test_it->start, (*it)->start) << "Mismatch in map data, expected test maps:\n"
+                                            << GetTestMapsAsString(test_maps) << "Actual maps:\n"
+                                            << GetMapsAsString(map.get());
+    ASSERT_EQ(test_it->end, (*it)->end) << "Mismatch maps in map data, expected test maps:\n"
+                                        << GetTestMapsAsString(test_maps) << "Actual maps:\n"
+                                        << GetMapsAsString(map.get());
+    // Make sure the load bias get set to a value.
+    ASSERT_NE(static_cast<uint64_t>(-1), (*it)->load_bias) << "Found uninitialized load_bias\n"
+                                                           << GetMapsAsString(map.get());
     ++test_it;
   }
   ASSERT_TRUE(test_it == test_maps.end());
diff --git a/libbacktrace/include/backtrace/BacktraceMap.h b/libbacktrace/include/backtrace/BacktraceMap.h
index d078392..4ae68dd 100644
--- a/libbacktrace/include/backtrace/BacktraceMap.h
+++ b/libbacktrace/include/backtrace/BacktraceMap.h
@@ -30,6 +30,7 @@
 #endif
 
 #include <deque>
+#include <iterator>
 #include <string>
 #include <vector>
 
@@ -61,6 +62,49 @@
 
   virtual ~BacktraceMap();
 
+  class iterator : public std::iterator<std::bidirectional_iterator_tag, backtrace_map_t*> {
+   public:
+    iterator(BacktraceMap* map, size_t index) : map_(map), index_(index) {}
+
+    iterator& operator++() {
+      index_++;
+      return *this;
+    }
+    iterator& operator++(int increment) {
+      index_ += increment;
+      return *this;
+    }
+    iterator& operator--() {
+      index_--;
+      return *this;
+    }
+    iterator& operator--(int decrement) {
+      index_ -= decrement;
+      return *this;
+    }
+
+    bool operator==(const iterator& rhs) { return this->index_ == rhs.index_; }
+    bool operator!=(const iterator& rhs) { return this->index_ != rhs.index_; }
+
+    const backtrace_map_t* operator*() {
+      if (index_ >= map_->size()) {
+        return nullptr;
+      }
+      backtrace_map_t* map = &map_->maps_[index_];
+      if (map->load_bias == static_cast<uintptr_t>(-1)) {
+        map->load_bias = map_->GetLoadBias(index_);
+      }
+      return map;
+    }
+
+   private:
+    BacktraceMap* map_ = nullptr;
+    size_t index_ = 0;
+  };
+
+  iterator begin() { return iterator(this, 0); }
+  iterator end() { return iterator(this, maps_.size()); }
+
   // Fill in the map data structure for the given address.
   virtual void FillIn(uintptr_t addr, backtrace_map_t* map);
 
@@ -89,14 +133,6 @@
   virtual void LockIterator() {}
   virtual void UnlockIterator() {}
 
-  typedef std::deque<backtrace_map_t>::iterator iterator;
-  iterator begin() { return maps_.begin(); }
-  iterator end() { return maps_.end(); }
-
-  typedef std::deque<backtrace_map_t>::const_iterator const_iterator;
-  const_iterator begin() const { return maps_.begin(); }
-  const_iterator end() const { return maps_.end(); }
-
   size_t size() const { return maps_.size(); }
 
   virtual bool Build();
@@ -114,6 +150,8 @@
  protected:
   BacktraceMap(pid_t pid);
 
+  virtual uint64_t GetLoadBias(size_t /* index */) { return 0; }
+
   virtual bool ParseLine(const char* line, backtrace_map_t* map);
 
   pid_t pid_;
diff --git a/liblog/logger_write.c b/liblog/logger_write.c
index 589ce84..d03a2b6 100644
--- a/liblog/logger_write.c
+++ b/liblog/logger_write.c
@@ -270,7 +270,7 @@
       /* If only we could reset downstream logd counter */
       return -EPERM;
     }
-  } else if (log_id == LOG_ID_EVENTS) {
+  } else if (log_id == LOG_ID_EVENTS || log_id == LOG_ID_STATS) {
     const char* tag;
     size_t len;
     EventTagMap *m, *f;
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 75aa427..74930d6 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -118,6 +118,7 @@
         "tests/ElfTestUtils.cpp",
         "tests/LogFake.cpp",
         "tests/MapInfoGetElfTest.cpp",
+        "tests/MapInfoGetLoadBiasTest.cpp",
         "tests/MapsTest.cpp",
         "tests/MemoryBufferTest.cpp",
         "tests/MemoryFake.cpp",
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp
index 97ade56..5f307ed 100644
--- a/libunwindstack/Elf.cpp
+++ b/libunwindstack/Elf.cpp
@@ -215,4 +215,22 @@
   return interface.release();
 }
 
+uint64_t Elf::GetLoadBias(Memory* memory) {
+  if (!IsValidElf(memory)) {
+    return 0;
+  }
+
+  uint8_t class_type;
+  if (!memory->Read(EI_CLASS, &class_type, 1)) {
+    return 0;
+  }
+
+  if (class_type == ELFCLASS32) {
+    return ElfInterface::GetLoadBias<Elf32_Ehdr, Elf32_Phdr>(memory);
+  } else if (class_type == ELFCLASS64) {
+    return ElfInterface::GetLoadBias<Elf64_Ehdr, Elf64_Phdr>(memory);
+  }
+  return 0;
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index 9bdb094..334cf76 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -148,6 +148,26 @@
 }
 
 template <typename EhdrType, typename PhdrType>
+uint64_t ElfInterface::GetLoadBias(Memory* memory) {
+  EhdrType ehdr;
+  if (!memory->Read(0, &ehdr, sizeof(ehdr))) {
+    return false;
+  }
+
+  uint64_t offset = ehdr.e_phoff;
+  for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
+    PhdrType phdr;
+    if (!memory->Read(offset, &phdr, sizeof(phdr))) {
+      return 0;
+    }
+    if (phdr.p_type == PT_LOAD && phdr.p_offset == 0) {
+      return phdr.p_vaddr;
+    }
+  }
+  return 0;
+}
+
+template <typename EhdrType, typename PhdrType>
 bool ElfInterface::ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias) {
   uint64_t offset = ehdr.e_phoff;
   for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
@@ -421,4 +441,7 @@
 template void ElfInterface::GetMaxSizeWithTemplate<Elf32_Ehdr>(Memory*, uint64_t*);
 template void ElfInterface::GetMaxSizeWithTemplate<Elf64_Ehdr>(Memory*, uint64_t*);
 
+template uint64_t ElfInterface::GetLoadBias<Elf32_Ehdr, Elf32_Phdr>(Memory*);
+template uint64_t ElfInterface::GetLoadBias<Elf64_Ehdr, Elf64_Phdr>(Memory*);
+
 }  // namespace unwindstack
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index 8a7ad9c..51bce8e 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -121,4 +121,23 @@
   return elf;
 }
 
+uint64_t MapInfo::GetLoadBias(const std::shared_ptr<Memory>& process_memory) {
+  {
+    // Make sure no other thread is trying to add the elf to this map.
+    std::lock_guard<std::mutex> guard(mutex_);
+    if (elf != nullptr) {
+      if (elf->valid()) {
+        return elf->GetLoadBias();
+      } else {
+        return 0;
+      }
+    }
+  }
+
+  // Call lightweight static function that will only read enough of the
+  // elf data to get the load bias.
+  std::unique_ptr<Memory> memory(CreateMemory(process_memory));
+  return Elf::GetLoadBias(memory.get());
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/Memory.cpp b/libunwindstack/Memory.cpp
index 2479655..b1b39a0 100644
--- a/libunwindstack/Memory.cpp
+++ b/libunwindstack/Memory.cpp
@@ -198,8 +198,68 @@
   return actual_len;
 }
 
+static bool PtraceReadLong(pid_t pid, uint64_t addr, long* value) {
+  // ptrace() returns -1 and sets errno when the operation fails.
+  // To disambiguate -1 from a valid result, we clear errno beforehand.
+  errno = 0;
+  *value = ptrace(PTRACE_PEEKTEXT, pid, reinterpret_cast<void*>(addr), nullptr);
+  if (*value == -1 && errno) {
+    return false;
+  }
+  return true;
+}
+
+static size_t ReadWithPtrace(pid_t pid, uint64_t addr, void* dst, size_t bytes) {
+  // Make sure that there is no overflow.
+  uint64_t max_size;
+  if (__builtin_add_overflow(addr, bytes, &max_size)) {
+    return 0;
+  }
+
+  size_t bytes_read = 0;
+  long data;
+  size_t align_bytes = addr & (sizeof(long) - 1);
+  if (align_bytes != 0) {
+    if (!PtraceReadLong(pid, addr & ~(sizeof(long) - 1), &data)) {
+      return 0;
+    }
+    size_t copy_bytes = std::min(sizeof(long) - align_bytes, bytes);
+    memcpy(dst, reinterpret_cast<uint8_t*>(&data) + align_bytes, copy_bytes);
+    addr += copy_bytes;
+    dst = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(dst) + copy_bytes);
+    bytes -= copy_bytes;
+    bytes_read += copy_bytes;
+  }
+
+  for (size_t i = 0; i < bytes / sizeof(long); i++) {
+    if (!PtraceReadLong(pid, addr, &data)) {
+      return bytes_read;
+    }
+    memcpy(dst, &data, sizeof(long));
+    dst = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(dst) + sizeof(long));
+    addr += sizeof(long);
+    bytes_read += sizeof(long);
+  }
+
+  size_t left_over = bytes & (sizeof(long) - 1);
+  if (left_over) {
+    if (!PtraceReadLong(pid, addr, &data)) {
+      return bytes_read;
+    }
+    memcpy(dst, &data, left_over);
+    bytes_read += left_over;
+  }
+  return bytes_read;
+}
+
 size_t MemoryRemote::Read(uint64_t addr, void* dst, size_t size) {
-  return ProcessVmRead(pid_, dst, addr, size);
+#if !defined(__LP64__)
+  // Cannot read an address greater than 32 bits.
+  if (addr > UINT32_MAX) {
+    return 0;
+  }
+#endif
+  return ReadWithPtrace(pid_, addr, dst, size);
 }
 
 size_t MemoryLocal::Read(uint64_t addr, void* dst, size_t size) {
diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h
index da2ddc0..d9ea9c4 100644
--- a/libunwindstack/include/unwindstack/Elf.h
+++ b/libunwindstack/include/unwindstack/Elf.h
@@ -74,6 +74,8 @@
 
   static void GetInfo(Memory* memory, bool* valid, uint64_t* size);
 
+  static uint64_t GetLoadBias(Memory* memory);
+
  protected:
   bool valid_ = false;
   uint64_t load_bias_ = 0;
diff --git a/libunwindstack/include/unwindstack/ElfInterface.h b/libunwindstack/include/unwindstack/ElfInterface.h
index 86e51b3..5cfe74d 100644
--- a/libunwindstack/include/unwindstack/ElfInterface.h
+++ b/libunwindstack/include/unwindstack/ElfInterface.h
@@ -82,6 +82,9 @@
   DwarfSection* eh_frame() { return eh_frame_.get(); }
   DwarfSection* debug_frame() { return debug_frame_.get(); }
 
+  template <typename EhdrType, typename PhdrType>
+  static uint64_t GetLoadBias(Memory* memory);
+
  protected:
   template <typename AddressType>
   void InitHeadersWithTemplate();
diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h
index e54b348..6f8ceca 100644
--- a/libunwindstack/include/unwindstack/MapInfo.h
+++ b/libunwindstack/include/unwindstack/MapInfo.h
@@ -51,6 +51,8 @@
   // This function guarantees it will never return nullptr.
   Elf* GetElf(const std::shared_ptr<Memory>& process_memory, bool init_gnu_debugdata = false);
 
+  uint64_t GetLoadBias(const std::shared_ptr<Memory>& process_memory);
+
  private:
   MapInfo(const MapInfo&) = delete;
   void operator=(const MapInfo&) = delete;
diff --git a/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp b/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp
new file mode 100644
index 0000000..44a73a8
--- /dev/null
+++ b/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <elf.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <atomic>
+#include <memory>
+#include <thread>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/test_utils.h>
+#include <gtest/gtest.h>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
+
+#include "ElfFake.h"
+#include "ElfTestUtils.h"
+#include "MemoryFake.h"
+
+namespace unwindstack {
+
+class MapInfoGetLoadBiasTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    memory_ = new MemoryFake;
+    process_memory_.reset(memory_);
+    elf_ = new ElfFake(new MemoryFake);
+    elf_container_.reset(elf_);
+    map_info_.reset(new MapInfo(0x1000, 0x20000, 0, PROT_READ | PROT_WRITE, ""));
+  }
+
+  void MultipleThreadTest(uint64_t expected_load_bias);
+
+  std::shared_ptr<Memory> process_memory_;
+  MemoryFake* memory_;
+  ElfFake* elf_;
+  std::unique_ptr<ElfFake> elf_container_;
+  std::unique_ptr<MapInfo> map_info_;
+};
+
+TEST_F(MapInfoGetLoadBiasTest, no_elf_and_no_valid_elf_in_memory) {
+  MapInfo info(0x1000, 0x2000, 0, PROT_READ, "");
+
+  EXPECT_EQ(0U, info.GetLoadBias(process_memory_));
+}
+
+TEST_F(MapInfoGetLoadBiasTest, elf_exists) {
+  map_info_->elf = elf_container_.release();
+
+  elf_->FakeSetLoadBias(0);
+  EXPECT_EQ(0U, map_info_->GetLoadBias(process_memory_));
+
+  elf_->FakeSetLoadBias(0x1000);
+  EXPECT_EQ(0x1000U, map_info_->GetLoadBias(process_memory_));
+}
+
+void MapInfoGetLoadBiasTest::MultipleThreadTest(uint64_t expected_load_bias) {
+  static constexpr size_t kNumConcurrentThreads = 100;
+
+  uint64_t load_bias_values[kNumConcurrentThreads];
+  std::vector<std::thread*> threads;
+
+  std::atomic_bool wait;
+  wait = true;
+  // Create all of the threads and have them do the GetLoadBias at the same time
+  // to make it likely that a race will occur.
+  for (size_t i = 0; i < kNumConcurrentThreads; i++) {
+    std::thread* thread = new std::thread([i, this, &wait, &load_bias_values]() {
+      while (wait)
+        ;
+      load_bias_values[i] = map_info_->GetLoadBias(process_memory_);
+    });
+    threads.push_back(thread);
+  }
+
+  // Set them all going and wait for the threads to finish.
+  wait = false;
+  for (auto thread : threads) {
+    thread->join();
+    delete thread;
+  }
+
+  // Now verify that all of the elf files are exactly the same and valid.
+  for (size_t i = 0; i < kNumConcurrentThreads; i++) {
+    EXPECT_EQ(expected_load_bias, load_bias_values[i]) << "Thread " << i << " mismatched.";
+  }
+}
+
+TEST_F(MapInfoGetLoadBiasTest, multiple_thread_elf_exists) {
+  map_info_->elf = elf_container_.release();
+  elf_->FakeSetLoadBias(0x1000);
+
+  MultipleThreadTest(0x1000);
+}
+
+static void InitElfData(MemoryFake* memory, uint64_t offset) {
+  Elf32_Ehdr ehdr;
+  TestInitEhdr(&ehdr, ELFCLASS32, EM_ARM);
+  ehdr.e_phoff = 0x5000;
+  ehdr.e_phnum = 2;
+  ehdr.e_phentsize = sizeof(Elf32_Phdr);
+  memory->SetMemory(offset, &ehdr, sizeof(ehdr));
+
+  Elf32_Phdr phdr;
+  memset(&phdr, 0, sizeof(phdr));
+  phdr.p_type = PT_NULL;
+  memory->SetMemory(offset + 0x5000, &phdr, sizeof(phdr));
+  phdr.p_type = PT_LOAD;
+  phdr.p_offset = 0;
+  phdr.p_vaddr = 0xe000;
+  memory->SetMemory(offset + 0x5000 + sizeof(phdr), &phdr, sizeof(phdr));
+}
+
+TEST_F(MapInfoGetLoadBiasTest, elf_exists_in_memory) {
+  InitElfData(memory_, map_info_->start);
+
+  EXPECT_EQ(0xe000U, map_info_->GetLoadBias(process_memory_));
+}
+
+TEST_F(MapInfoGetLoadBiasTest, multiple_thread_elf_exists_in_memory) {
+  InitElfData(memory_, map_info_->start);
+
+  MultipleThreadTest(0xe000);
+}
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/MemoryRemoteTest.cpp b/libunwindstack/tests/MemoryRemoteTest.cpp
index 8aa4c3f..8aa8605 100644
--- a/libunwindstack/tests/MemoryRemoteTest.cpp
+++ b/libunwindstack/tests/MemoryRemoteTest.cpp
@@ -79,14 +79,13 @@
   ASSERT_TRUE(Detach(pid));
 }
 
-TEST_F(MemoryRemoteTest, Read) {
+TEST_F(MemoryRemoteTest, read_partial) {
   char* mapping = static_cast<char*>(
-      mmap(nullptr, 2 * getpagesize(), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
-
+      mmap(nullptr, 4 * getpagesize(), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
   ASSERT_NE(MAP_FAILED, mapping);
-
-  mprotect(mapping + getpagesize(), getpagesize(), PROT_NONE);
-  memset(mapping + getpagesize() - 1024, 0x4c, 1024);
+  memset(mapping, 0x4c, 4 * getpagesize());
+  ASSERT_EQ(0, mprotect(mapping + getpagesize(), getpagesize(), PROT_NONE));
+  ASSERT_EQ(0, munmap(mapping + 3 * getpagesize(), getpagesize()));
 
   pid_t pid;
   if ((pid = fork()) == 0) {
@@ -97,19 +96,31 @@
   ASSERT_LT(0, pid);
   TestScopedPidReaper reap(pid);
 
+  // Unmap from our process.
+  ASSERT_EQ(0, munmap(mapping, 3 * getpagesize()));
+
   ASSERT_TRUE(Attach(pid));
 
   MemoryRemote remote(pid);
 
   std::vector<uint8_t> dst(4096);
-  ASSERT_EQ(1024U, remote.Read(reinterpret_cast<uint64_t>(mapping + getpagesize() - 1024),
-                               dst.data(), 4096));
-  for (size_t i = 0; i < 1024; i++) {
+  size_t bytes =
+      remote.Read(reinterpret_cast<uint64_t>(mapping + getpagesize() - 1024), dst.data(), 4096);
+  // Some read methods can read PROT_NONE maps, allow that.
+  ASSERT_LE(1024U, bytes);
+  for (size_t i = 0; i < bytes; i++) {
+    ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i;
+  }
+
+  // Now verify that reading stops at the end of a map.
+  bytes =
+      remote.Read(reinterpret_cast<uint64_t>(mapping + 3 * getpagesize() - 1024), dst.data(), 4096);
+  ASSERT_EQ(1024U, bytes);
+  for (size_t i = 0; i < bytes; i++) {
     ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i;
   }
 
   ASSERT_TRUE(Detach(pid));
-  ASSERT_EQ(0, munmap(mapping, 2 * getpagesize()));
 }
 
 TEST_F(MemoryRemoteTest, read_fail) {
@@ -192,12 +203,13 @@
   ASSERT_TRUE(Detach(pid));
 }
 
-TEST_F(MemoryRemoteTest, read_hole) {
+TEST_F(MemoryRemoteTest, read_mprotect_hole) {
+  size_t page_size = getpagesize();
   void* mapping =
-      mmap(nullptr, 3 * 4096, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+      mmap(nullptr, 3 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
   ASSERT_NE(MAP_FAILED, mapping);
-  memset(mapping, 0xFF, 3 * 4096);
-  mprotect(static_cast<char*>(mapping) + 4096, 4096, PROT_NONE);
+  memset(mapping, 0xFF, 3 * page_size);
+  ASSERT_EQ(0, mprotect(static_cast<char*>(mapping) + page_size, page_size, PROT_NONE));
 
   pid_t pid;
   if ((pid = fork()) == 0) {
@@ -207,15 +219,53 @@
   ASSERT_LT(0, pid);
   TestScopedPidReaper reap(pid);
 
+  ASSERT_EQ(0, munmap(mapping, 3 * page_size));
+
   ASSERT_TRUE(Attach(pid));
 
   MemoryRemote remote(pid);
-  std::vector<uint8_t> dst(4096 * 3, 0xCC);
-  ASSERT_EQ(4096U, remote.Read(reinterpret_cast<uintptr_t>(mapping), dst.data(), 4096 * 3));
-  for (size_t i = 0; i < 4096; ++i) {
+  std::vector<uint8_t> dst(getpagesize() * 4, 0xCC);
+  size_t read_size = remote.Read(reinterpret_cast<uintptr_t>(mapping), dst.data(), page_size * 3);
+  // Some read methods can read PROT_NONE maps, allow that.
+  ASSERT_LE(page_size, read_size);
+  for (size_t i = 0; i < read_size; ++i) {
     ASSERT_EQ(0xFF, dst[i]);
   }
-  for (size_t i = 4096; i < 4096 * 3; ++i) {
+  for (size_t i = read_size; i < dst.size(); ++i) {
+    ASSERT_EQ(0xCC, dst[i]);
+  }
+}
+
+TEST_F(MemoryRemoteTest, read_munmap_hole) {
+  size_t page_size = getpagesize();
+  void* mapping =
+      mmap(nullptr, 3 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+  ASSERT_NE(MAP_FAILED, mapping);
+  memset(mapping, 0xFF, 3 * page_size);
+  ASSERT_EQ(0, munmap(static_cast<char*>(mapping) + page_size, page_size));
+
+  pid_t pid;
+  if ((pid = fork()) == 0) {
+    while (true)
+      ;
+    exit(1);
+  }
+  ASSERT_LT(0, pid);
+  TestScopedPidReaper reap(pid);
+
+  ASSERT_EQ(0, munmap(mapping, page_size));
+  ASSERT_EQ(0, munmap(static_cast<char*>(mapping) + 2 * page_size, page_size));
+
+  ASSERT_TRUE(Attach(pid));
+
+  MemoryRemote remote(pid);
+  std::vector<uint8_t> dst(getpagesize() * 4, 0xCC);
+  size_t read_size = remote.Read(reinterpret_cast<uintptr_t>(mapping), dst.data(), page_size * 3);
+  ASSERT_EQ(page_size, read_size);
+  for (size_t i = 0; i < read_size; ++i) {
+    ASSERT_EQ(0xFF, dst[i]);
+  }
+  for (size_t i = read_size; i < dst.size(); ++i) {
     ASSERT_EQ(0xCC, dst[i]);
   }
 }
diff --git a/logd/FlushCommand.cpp b/logd/FlushCommand.cpp
old mode 100644
new mode 100755
index a9edc3e..70ecbe0
--- a/logd/FlushCommand.cpp
+++ b/logd/FlushCommand.cpp
@@ -26,18 +26,6 @@
 #include "LogTimes.h"
 #include "LogUtils.h"
 
-FlushCommand::FlushCommand(LogReader& reader, bool nonBlock, unsigned long tail,
-                           unsigned int logMask, pid_t pid, log_time start,
-                           uint64_t timeout)
-    : mReader(reader),
-      mNonBlock(nonBlock),
-      mTail(tail),
-      mLogMask(logMask),
-      mPid(pid),
-      mStart(start),
-      mTimeout((start != log_time::EPOCH) ? timeout : 0) {
-}
-
 // runSocketCommand is called once for every open client on the
 // log reader socket. Here we manage and associated the reader
 // client tracking and log region locks LastLogTimes list of
@@ -56,6 +44,10 @@
     while (it != times.end()) {
         entry = (*it);
         if (entry->mClient == client) {
+            if (!entry->isWatchingMultiple(mLogMask)) {
+                LogTimeEntry::unlock();
+                return;
+            }
             if (entry->mTimeout.tv_sec || entry->mTimeout.tv_nsec) {
                 if (mReader.logbuf().isMonotonic()) {
                     LogTimeEntry::unlock();
diff --git a/logd/FlushCommand.h b/logd/FlushCommand.h
old mode 100644
new mode 100755
index 7cdd03f..543dfc3
--- a/logd/FlushCommand.h
+++ b/logd/FlushCommand.h
@@ -29,16 +29,36 @@
     LogReader& mReader;
     bool mNonBlock;
     unsigned long mTail;
-    unsigned int mLogMask;
+    log_mask_t mLogMask;
     pid_t mPid;
     log_time mStart;
     uint64_t mTimeout;
 
    public:
-    explicit FlushCommand(LogReader& mReader, bool nonBlock = false,
-                          unsigned long tail = -1, unsigned int logMask = -1,
-                          pid_t pid = 0, log_time start = log_time::EPOCH,
-                          uint64_t timeout = 0);
+    // for opening a reader
+    explicit FlushCommand(LogReader& reader, bool nonBlock, unsigned long tail,
+                          log_mask_t logMask, pid_t pid, log_time start,
+                          uint64_t timeout)
+        : mReader(reader),
+          mNonBlock(nonBlock),
+          mTail(tail),
+          mLogMask(logMask),
+          mPid(pid),
+          mStart(start),
+          mTimeout((start != log_time::EPOCH) ? timeout : 0) {
+    }
+
+    // for notification of an update
+    explicit FlushCommand(LogReader& reader, log_mask_t logMask)
+        : mReader(reader),
+          mNonBlock(false),
+          mTail(-1),
+          mLogMask(logMask),
+          mPid(0),
+          mStart(log_time::EPOCH),
+          mTimeout(0) {
+    }
+
     virtual void runSocketCommand(SocketClient* client);
 
     static bool hasReadLogs(SocketClient* client);
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
old mode 100644
new mode 100755
index cfcbaa5..1d0cc33
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -365,7 +365,7 @@
                   : LOGGER_ENTRY_MAX_PAYLOAD;
     size_t message_len = str_len + sizeof(android_log_event_string_t);
 
-    bool notify = false;
+    log_mask_t notify = 0;
 
     if (events) {  // begin scope for event buffer
         uint32_t buffer[(message_len + sizeof(uint32_t) - 1) / sizeof(uint32_t)];
@@ -384,7 +384,7 @@
             (message_len <= USHRT_MAX) ? (unsigned short)message_len
                                        : USHRT_MAX);
         if (rc >= 0) {
-            notify = true;
+            notify |= 1 << LOG_ID_EVENTS;
         }
         // end scope for event buffer
     }
@@ -440,7 +440,7 @@
                                                     : USHRT_MAX);
 
         if (rc >= 0) {
-            notify = true;
+            notify |= 1 << LOG_ID_MAIN;
         }
         // end scope for main buffer
     }
@@ -449,7 +449,7 @@
     free(str);
 
     if (notify) {
-        reader->notifyNewLog();
+        reader->notifyNewLog(notify);
         if (rc < 0) {
             rc = message_len;
         }
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 43362fb..560f490 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -213,7 +213,7 @@
         int prio = ANDROID_LOG_INFO;
         const char* tag = nullptr;
         size_t tag_len = 0;
-        if (log_id == LOG_ID_EVENTS) {
+        if (log_id == LOG_ID_EVENTS || log_id == LOG_ID_STATS) {
             tag = tagToName(elem->getTag());
             if (tag) {
                 tag_len = strlen(tag);
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
old mode 100644
new mode 100755
index a7e7208..7a7ac7d
--- a/logd/LogKlog.cpp
+++ b/logd/LogKlog.cpp
@@ -826,7 +826,7 @@
 
     // notify readers
     if (!rc) {
-        reader->notifyNewLog();
+        reader->notifyNewLog(static_cast<log_mask_t>(1 << LOG_ID_KERNEL));
     }
 
     return rc;
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
old mode 100644
new mode 100755
index fcf2cd8..fc51dcf
--- a/logd/LogListener.cpp
+++ b/logd/LogListener.cpp
@@ -94,12 +94,13 @@
 
     android_log_header_t* header =
         reinterpret_cast<android_log_header_t*>(buffer);
-    if (/* header->id < LOG_ID_MIN || */ header->id >= LOG_ID_MAX ||
-        header->id == LOG_ID_KERNEL) {
+    log_id_t logId = static_cast<log_id_t>(header->id);
+    if (/* logId < LOG_ID_MIN || */ logId >= LOG_ID_MAX ||
+        logId == LOG_ID_KERNEL) {
         return false;
     }
 
-    if ((header->id == LOG_ID_SECURITY) &&
+    if ((logId == LOG_ID_SECURITY) &&
         (!__android_log_security() ||
          !clientHasLogCredentials(cred->uid, cred->gid, cred->pid))) {
         return false;
@@ -134,11 +135,10 @@
 
     if (logbuf != nullptr) {
         int res = logbuf->log(
-            (log_id_t)header->id, header->realtime, cred->uid, cred->pid,
-            header->tid, msg,
+            logId, header->realtime, cred->uid, cred->pid, header->tid, msg,
             ((size_t)n <= USHRT_MAX) ? (unsigned short)n : USHRT_MAX);
         if (res > 0 && reader != nullptr) {
-            reader->notifyNewLog();
+            reader->notifyNewLog(static_cast<log_mask_t>(1 << logId));
         }
     }
 
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
old mode 100644
new mode 100755
index 6d69316..2b6556d
--- a/logd/LogReader.cpp
+++ b/logd/LogReader.cpp
@@ -35,9 +35,9 @@
 }
 
 // When we are notified a new log entry is available, inform
-// all of our listening sockets.
-void LogReader::notifyNewLog() {
-    FlushCommand command(*this);
+// listening sockets who are watching this entry's log id.
+void LogReader::notifyNewLog(log_mask_t logMask) {
+    FlushCommand command(*this, logMask);
     runOnEachSocket(&command);
 }
 
diff --git a/logd/LogReader.h b/logd/LogReader.h
old mode 100644
new mode 100755
index 271e08c..b5312b6
--- a/logd/LogReader.h
+++ b/logd/LogReader.h
@@ -19,6 +19,8 @@
 
 #include <sysutils/SocketListener.h>
 
+#include "LogTimes.h"
+
 #define LOGD_SNDTIMEO 32
 
 class LogBuffer;
@@ -28,7 +30,7 @@
 
    public:
     explicit LogReader(LogBuffer* logbuf);
-    void notifyNewLog();
+    void notifyNewLog(log_mask_t logMask);
 
     LogBuffer& logbuf(void) const {
         return mLogbuf;
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp
old mode 100644
new mode 100755
index 25c2ad2..7a6f84b
--- a/logd/LogTimes.cpp
+++ b/logd/LogTimes.cpp
@@ -28,9 +28,8 @@
 pthread_mutex_t LogTimeEntry::timesLock = PTHREAD_MUTEX_INITIALIZER;
 
 LogTimeEntry::LogTimeEntry(LogReader& reader, SocketClient* client,
-                           bool nonBlock, unsigned long tail,
-                           unsigned int logMask, pid_t pid, log_time start,
-                           uint64_t timeout)
+                           bool nonBlock, unsigned long tail, log_mask_t logMask,
+                           pid_t pid, log_time start, uint64_t timeout)
     : mRefCount(1),
       mRelease(false),
       mError(false),
diff --git a/logd/LogTimes.h b/logd/LogTimes.h
old mode 100644
new mode 100755
index 9ca2aea..76d016c
--- a/logd/LogTimes.h
+++ b/logd/LogTimes.h
@@ -26,6 +26,8 @@
 #include <log/log.h>
 #include <sysutils/SocketClient.h>
 
+typedef unsigned int log_mask_t;
+
 class LogReader;
 class LogBufferElement;
 
@@ -41,7 +43,7 @@
     LogReader& mReader;
     static void* threadStart(void* me);
     static void threadStop(void* me);
-    const unsigned int mLogMask;
+    const log_mask_t mLogMask;
     const pid_t mPid;
     unsigned int skipAhead[LOG_ID_MAX];
     pid_t mLastTid[LOG_ID_MAX];
@@ -51,7 +53,7 @@
 
    public:
     LogTimeEntry(LogReader& reader, SocketClient* client, bool nonBlock,
-                 unsigned long tail, unsigned int logMask, pid_t pid,
+                 unsigned long tail, log_mask_t logMask, pid_t pid,
                  log_time start, uint64_t timeout);
 
     SocketClient* mClient;
@@ -133,8 +135,11 @@
         // No one else is holding a reference to this
         delete this;
     }
-    bool isWatching(log_id_t id) {
-        return (mLogMask & (1 << id)) != 0;
+    bool isWatching(log_id_t id) const {
+        return mLogMask & (1 << id);
+    }
+    bool isWatchingMultiple(log_mask_t logMask) const {
+        return mLogMask & logMask;
     }
     // flushTo filter callbacks
     static int FilterFirstPass(const LogBufferElement* element, void* me);
diff --git a/shell_and_utilities/Android.bp b/shell_and_utilities/Android.bp
index 9620d63..4203db4 100644
--- a/shell_and_utilities/Android.bp
+++ b/shell_and_utilities/Android.bp
@@ -1,6 +1,8 @@
 phony {
     name: "shell_and_utilities",
     required: [
+        "awk",
+        "awk_vendor",
         "bzip2",
         "grep",
         "grep_vendor",
diff --git a/shell_and_utilities/README.md b/shell_and_utilities/README.md
index c4e8aac..206204b 100644
--- a/shell_and_utilities/README.md
+++ b/shell_and_utilities/README.md
@@ -21,7 +21,8 @@
 Not everything is provided by toybox, though. We currently still use
 the BSD dd and grep (because the toybox versions are still unfinished),
 and for the bzip2 command-line tools we use the ones that are part of
-the bzip2 distribution.
+the bzip2 distribution. The awk added in Android P is Brian Kernighan's
+"one true" awk.
 
 The lists below show what tools were provided and where they came from in
 each release starting with Gingerbread. This doesn't tell the full story,
@@ -164,3 +165,29 @@
 sysctl tac tail tar taskset tee time timeout top touch tr true truncate
 tty ulimit umount uname uniq unix2dos uptime usleep uudecode uuencode
 vmstat wc which whoami xargs xxd yes zcat
+
+Android P
+---------
+
+BSD: dd grep
+
+bzip2: bzcat bzip2 bunzip2
+
+one-true-awk: awk
+
+toolbox: getevent newfs\_msdos
+
+toybox: acpi base64 basename blockdev cal cat chcon chgrp chmod chown
+chroot chrt cksum clear cmp comm cp cpio cut date df diff dirname dmesg
+dos2unix du echo env expand expr fallocate false file find flock free
+getenforce getprop groups gunzip gzip head hostname hwclock id ifconfig
+inotifyd insmod ionice iorenice kill killall ln load\_policy log logname
+losetup ls lsmod lsof lspci lsusb md5sum microcom mkdir mkfifo mknod
+mkswap mktemp modinfo modprobe more mount mountpoint mv netstat nice
+nl nohup od paste patch pgrep pidof pkill pmap printenv printf ps pwd
+readlink realpath renice restorecon rm rmdir rmmod runcon sed sendevent
+seq setenforce setprop setsid sha1sum sha224sum sha256sum sha384sum
+sha512sum sleep sort split start stat stop strings swapoff swapon sync
+sysctl tac tail tar taskset tee time timeout top touch tr true truncate
+tty ulimit umount uname uniq unix2dos uptime usleep uudecode uuencode
+vmstat wc which whoami xargs xxd yes zcat