Merge changes from topic "logwrapper-api-update"

* changes:
  Update init/fs_mgr for new logwrapper function
  logwrap: convert to C++, rename function logwrap_fork_execvp().
diff --git a/debuggerd/tombstoned/tombstoned.cpp b/debuggerd/tombstoned/tombstoned.cpp
index bbeb181..d09b8e8 100644
--- a/debuggerd/tombstoned/tombstoned.cpp
+++ b/debuggerd/tombstoned/tombstoned.cpp
@@ -100,7 +100,7 @@
 
   static CrashQueue* for_tombstones() {
     static CrashQueue queue("/data/tombstones", "tombstone_" /* file_name_prefix */,
-                            GetIntProperty("tombstoned.max_tombstone_count", 10),
+                            GetIntProperty("tombstoned.max_tombstone_count", 32),
                             1 /* max_concurrent_dumps */);
     return &queue;
   }
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 0dd275a..0d6aa2c 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -406,6 +406,20 @@
     //   |needs_merge| is set to true.
     bool TryCancelUpdate(bool* needs_merge);
 
+    // Helper for CreateUpdateSnapshots.
+    // Creates all underlying images, COW partitions and snapshot files. Does not initialize them.
+    bool CreateUpdateSnapshotsInternal(LockedFile* lock, const DeltaArchiveManifest& manifest,
+                                       PartitionCowCreator* cow_creator,
+                                       AutoDeviceList* created_devices,
+                                       std::map<std::string, SnapshotStatus>* all_snapshot_status);
+
+    // Initialize snapshots so that they can be mapped later.
+    // Map the COW partition and zero-initialize the header.
+    bool InitializeUpdateSnapshots(
+            LockedFile* lock, MetadataBuilder* target_metadata,
+            const LpMetadata* exported_target_metadata, const std::string& target_suffix,
+            const std::map<std::string, SnapshotStatus>& all_snapshot_status);
+
     std::string gsid_dir_;
     std::string metadata_dir_;
     std::unique_ptr<IDeviceInfo> device_;
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 2e689bd..0200077 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -1761,6 +1761,15 @@
     auto lock = LockExclusive();
     if (!lock) return false;
 
+    // TODO(b/134949511): remove this check. Right now, with overlayfs mounted, the scratch
+    // partition takes up a big chunk of space in super, causing COW images to be created on
+    // retrofit Virtual A/B devices.
+    if (device_->IsOverlayfsSetup()) {
+        LOG(ERROR) << "Cannot create update snapshots with overlayfs setup. Run `adb enable-verity`"
+                   << ", reboot, then try again.";
+        return false;
+    }
+
     const auto& opener = device_->GetPartitionOpener();
     auto current_suffix = device_->GetSlotSuffix();
     uint32_t current_slot = SlotNumberForSlotSuffix(current_suffix);
@@ -1778,32 +1787,6 @@
         return false;
     }
 
-    if (!target_metadata->AddGroup(kCowGroupName, 0)) {
-        LOG(ERROR) << "Cannot add group " << kCowGroupName;
-        return false;
-    }
-
-    std::map<std::string, const RepeatedPtrField<InstallOperation>*> install_operation_map;
-    for (const auto& partition_update : manifest.partitions()) {
-        auto suffixed_name = partition_update.partition_name() + target_suffix;
-        auto&& [it, inserted] = install_operation_map.emplace(std::move(suffixed_name),
-                                                              &partition_update.operations());
-        if (!inserted) {
-            LOG(ERROR) << "Duplicated partition " << partition_update.partition_name()
-                       << " in update manifest.";
-            return false;
-        }
-    }
-
-    // TODO(b/134949511): remove this check. Right now, with overlayfs mounted, the scratch
-    // partition takes up a big chunk of space in super, causing COW images to be created on
-    // retrofit Virtual A/B devices.
-    if (device_->IsOverlayfsSetup()) {
-        LOG(ERROR) << "Cannot create update snapshots with overlayfs setup. Run `adb enable-verity`"
-                   << ", reboot, then try again.";
-        return false;
-    }
-
     // Delete previous COW partitions in current_metadata so that PartitionCowCreator marks those as
     // free regions.
     UnmapAndDeleteCowPartition(current_metadata.get());
@@ -1823,17 +1806,78 @@
     // these devices.
     AutoDeviceList created_devices;
 
-    for (auto* target_partition : ListPartitionsWithSuffix(target_metadata.get(), target_suffix)) {
-        const RepeatedPtrField<InstallOperation>* operations = nullptr;
+    PartitionCowCreator cow_creator{.target_metadata = target_metadata.get(),
+                                    .target_suffix = target_suffix,
+                                    .target_partition = nullptr,
+                                    .current_metadata = current_metadata.get(),
+                                    .current_suffix = current_suffix,
+                                    .operations = nullptr};
+
+    if (!CreateUpdateSnapshotsInternal(lock.get(), manifest, &cow_creator, &created_devices,
+                                       &all_snapshot_status)) {
+        return false;
+    }
+
+    auto exported_target_metadata = target_metadata->Export();
+    if (exported_target_metadata == nullptr) {
+        LOG(ERROR) << "Cannot export target metadata";
+        return false;
+    }
+
+    if (!InitializeUpdateSnapshots(lock.get(), target_metadata.get(),
+                                   exported_target_metadata.get(), target_suffix,
+                                   all_snapshot_status)) {
+        return false;
+    }
+
+    if (!UpdatePartitionTable(opener, device_->GetSuperDevice(target_slot),
+                              *exported_target_metadata, target_slot)) {
+        LOG(ERROR) << "Cannot write target metadata";
+        return false;
+    }
+
+    created_devices.Release();
+    LOG(INFO) << "Successfully created all snapshots for target slot " << target_suffix;
+
+    return true;
+}
+
+bool SnapshotManager::CreateUpdateSnapshotsInternal(
+        LockedFile* lock, const DeltaArchiveManifest& manifest, PartitionCowCreator* cow_creator,
+        AutoDeviceList* created_devices,
+        std::map<std::string, SnapshotStatus>* all_snapshot_status) {
+    CHECK(lock);
+
+    auto* target_metadata = cow_creator->target_metadata;
+    const auto& target_suffix = cow_creator->target_suffix;
+
+    if (!target_metadata->AddGroup(kCowGroupName, 0)) {
+        LOG(ERROR) << "Cannot add group " << kCowGroupName;
+        return false;
+    }
+
+    std::map<std::string, const RepeatedPtrField<InstallOperation>*> install_operation_map;
+    for (const auto& partition_update : manifest.partitions()) {
+        auto suffixed_name = partition_update.partition_name() + target_suffix;
+        auto&& [it, inserted] = install_operation_map.emplace(std::move(suffixed_name),
+                                                              &partition_update.operations());
+        if (!inserted) {
+            LOG(ERROR) << "Duplicated partition " << partition_update.partition_name()
+                       << " in update manifest.";
+            return false;
+        }
+    }
+
+    for (auto* target_partition : ListPartitionsWithSuffix(target_metadata, target_suffix)) {
+        cow_creator->target_partition = target_partition;
+        cow_creator->operations = nullptr;
         auto operations_it = install_operation_map.find(target_partition->name());
         if (operations_it != install_operation_map.end()) {
-            operations = operations_it->second;
+            cow_creator->operations = operations_it->second;
         }
 
         // Compute the device sizes for the partition.
-        PartitionCowCreator cow_creator{target_metadata.get(),  target_suffix,  target_partition,
-                                        current_metadata.get(), current_suffix, operations};
-        auto cow_creator_ret = cow_creator.Run();
+        auto cow_creator_ret = cow_creator->Run();
         if (!cow_creator_ret.has_value()) {
             return false;
         }
@@ -1846,7 +1890,7 @@
                   << ", cow file size = " << cow_creator_ret->snapshot_status.cow_file_size;
 
         // Delete any existing snapshot before re-creating one.
-        if (!DeleteSnapshot(lock.get(), target_partition->name())) {
+        if (!DeleteSnapshot(lock, target_partition->name())) {
             LOG(ERROR) << "Cannot delete existing snapshot before creating a new one for partition "
                        << target_partition->name();
             return false;
@@ -1866,11 +1910,10 @@
         }
 
         // Store these device sizes to snapshot status file.
-        if (!CreateSnapshot(lock.get(), target_partition->name(),
-                            cow_creator_ret->snapshot_status)) {
+        if (!CreateSnapshot(lock, target_partition->name(), cow_creator_ret->snapshot_status)) {
             return false;
         }
-        created_devices.EmplaceBack<AutoDeleteSnapshot>(this, lock.get(), target_partition->name());
+        created_devices->EmplaceBack<AutoDeleteSnapshot>(this, lock, target_partition->name());
 
         // Create the COW partition. That is, use any remaining free space in super partition before
         // creating the COW images.
@@ -1898,32 +1941,36 @@
 
         // Create the backing COW image if necessary.
         if (cow_creator_ret->snapshot_status.cow_file_size > 0) {
-            if (!CreateCowImage(lock.get(), target_partition->name())) {
+            if (!CreateCowImage(lock, target_partition->name())) {
                 return false;
             }
         }
 
-        all_snapshot_status[target_partition->name()] = std::move(cow_creator_ret->snapshot_status);
+        all_snapshot_status->emplace(target_partition->name(),
+                                     std::move(cow_creator_ret->snapshot_status));
 
         LOG(INFO) << "Successfully created snapshot for " << target_partition->name();
     }
+    return true;
+}
+
+bool SnapshotManager::InitializeUpdateSnapshots(
+        LockedFile* lock, MetadataBuilder* target_metadata,
+        const LpMetadata* exported_target_metadata, const std::string& target_suffix,
+        const std::map<std::string, SnapshotStatus>& all_snapshot_status) {
+    CHECK(lock);
 
     auto& dm = DeviceMapper::Instance();
-    auto exported_target_metadata = target_metadata->Export();
-    if (exported_target_metadata == nullptr) {
-        LOG(ERROR) << "Cannot export target metadata";
-        return false;
-    }
     CreateLogicalPartitionParams cow_params{
             .block_device = LP_METADATA_DEFAULT_PARTITION_NAME,
-            .metadata = exported_target_metadata.get(),
+            .metadata = exported_target_metadata,
             .timeout_ms = std::chrono::milliseconds::max(),
             .partition_opener = &device_->GetPartitionOpener(),
     };
-    for (auto* target_partition : ListPartitionsWithSuffix(target_metadata.get(), target_suffix)) {
+    for (auto* target_partition : ListPartitionsWithSuffix(target_metadata, target_suffix)) {
         AutoDeviceList created_devices_for_cow;
 
-        if (!UnmapPartitionWithSnapshot(lock.get(), target_partition->name())) {
+        if (!UnmapPartitionWithSnapshot(lock, target_partition->name())) {
             LOG(ERROR) << "Cannot unmap existing COW devices before re-mapping them for zero-fill: "
                        << target_partition->name();
             return false;
@@ -1933,8 +1980,7 @@
         CHECK(it != all_snapshot_status.end()) << target_partition->name();
         cow_params.partition_name = target_partition->name();
         std::string cow_name;
-        if (!MapCowDevices(lock.get(), cow_params, it->second, &created_devices_for_cow,
-                           &cow_name)) {
+        if (!MapCowDevices(lock, cow_params, it->second, &created_devices_for_cow, &cow_name)) {
             return false;
         }
 
@@ -1951,16 +1997,6 @@
         }
         // Let destructor of created_devices_for_cow to unmap the COW devices.
     };
-
-    if (!UpdatePartitionTable(opener, device_->GetSuperDevice(target_slot),
-                              *exported_target_metadata, target_slot)) {
-        LOG(ERROR) << "Cannot write target metadata";
-        return false;
-    }
-
-    created_devices.Release();
-    LOG(INFO) << "Successfully created all snapshots for target slot " << target_suffix;
-
     return true;
 }
 
diff --git a/init/devices.cpp b/init/devices.cpp
index f6e453a..9fbec64 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -441,6 +441,23 @@
     }
 }
 
+void DeviceHandler::HandleAshmemUevent(const Uevent& uevent) {
+    if (uevent.device_name == "ashmem") {
+        static const std::string boot_id_path = "/proc/sys/kernel/random/boot_id";
+        std::string boot_id;
+        if (!ReadFileToString(boot_id_path, &boot_id)) {
+            PLOG(ERROR) << "Cannot duplicate ashmem device node. Failed to read " << boot_id_path;
+            return;
+        };
+        boot_id = Trim(boot_id);
+
+        Uevent dup_ashmem_uevent = uevent;
+        dup_ashmem_uevent.device_name += boot_id;
+        dup_ashmem_uevent.path += boot_id;
+        HandleUevent(dup_ashmem_uevent);
+    }
+}
+
 void DeviceHandler::HandleUevent(const Uevent& uevent) {
     if (uevent.action == "add" || uevent.action == "change" || uevent.action == "online") {
         FixupSysPermissions(uevent.path, uevent.subsystem);
@@ -485,6 +502,10 @@
     mkdir_recursive(Dirname(devpath), 0755);
 
     HandleDevice(uevent.action, devpath, block, uevent.major, uevent.minor, links);
+
+    // Duplicate /dev/ashmem device and name it /dev/ashmem<boot_id>.
+    // TODO(b/111903542): remove once all users of /dev/ashmem are migrated to libcutils API.
+    HandleAshmemUevent(uevent);
 }
 
 void DeviceHandler::ColdbootDone() {
diff --git a/init/devices.h b/init/devices.h
index 442c53f..05d64da 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -130,6 +130,7 @@
     void HandleDevice(const std::string& action, const std::string& devpath, bool block, int major,
                       int minor, const std::vector<std::string>& links) const;
     void FixupSysPermissions(const std::string& upath, const std::string& subsystem) const;
+    void HandleAshmemUevent(const Uevent& uevent);
 
     std::vector<Permissions> dev_permissions_;
     std::vector<SysfsPermissions> sysfs_permissions_;
diff --git a/libcutils/ashmem-dev.cpp b/libcutils/ashmem-dev.cpp
index e67b458..340572c 100644
--- a/libcutils/ashmem-dev.cpp
+++ b/libcutils/ashmem-dev.cpp
@@ -23,9 +23,6 @@
  */
 #define LOG_TAG "ashmem"
 
-#ifndef __ANDROID_VNDK__
-#include <dlfcn.h>
-#endif
 #include <errno.h>
 #include <fcntl.h>
 #include <linux/ashmem.h>
@@ -42,11 +39,11 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <android-base/file.h>
 #include <android-base/properties.h>
+#include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 
-#define ASHMEM_DEVICE "/dev/ashmem"
-
 /* Will be added to UAPI once upstream change is merged */
 #define F_SEAL_FUTURE_WRITE 0x0010
 
@@ -66,32 +63,6 @@
 static pthread_mutex_t __ashmem_lock = PTHREAD_MUTEX_INITIALIZER;
 
 /*
- * We use ashmemd to enforce that apps don't open /dev/ashmem directly. Vendor
- * code can't access system aidl services per Treble requirements. So we limit
- * ashmemd access to the system variant of libcutils.
- */
-#ifndef __ANDROID_VNDK__
-using openFdType = int (*)();
-
-static openFdType openFd;
-
-openFdType initOpenAshmemFd() {
-    openFdType openFd = nullptr;
-    void* handle = dlopen("libashmemd_client.so", RTLD_NOW);
-    if (!handle) {
-        ALOGE("Failed to dlopen() libashmemd_client.so: %s", dlerror());
-        return openFd;
-    }
-
-    openFd = reinterpret_cast<openFdType>(dlsym(handle, "openAshmemdFd"));
-    if (!openFd) {
-        ALOGE("Failed to dlsym() openAshmemdFd() function: %s", dlerror());
-    }
-    return openFd;
-}
-#endif
-
-/*
  * has_memfd_support() determines if the device can use memfd. memfd support
  * has been there for long time, but certain things in it may be missing.  We
  * check for needed support in it. Also we check if the VNDK version of
@@ -215,25 +186,31 @@
     return memfd_supported;
 }
 
+static std::string get_ashmem_device_path() {
+    static const std::string boot_id_path = "/proc/sys/kernel/random/boot_id";
+    std::string boot_id;
+    if (!android::base::ReadFileToString(boot_id_path, &boot_id)) {
+        ALOGE("Failed to read %s: %s.\n", boot_id_path.c_str(), strerror(errno));
+        return "";
+    };
+    boot_id = android::base::Trim(boot_id);
+
+    return "/dev/ashmem" + boot_id;
+}
+
 /* logistics of getting file descriptor for ashmem */
 static int __ashmem_open_locked()
 {
+    static const std::string ashmem_device_path = get_ashmem_device_path();
+
     int ret;
     struct stat st;
 
-    int fd = -1;
-#ifndef __ANDROID_VNDK__
-    if (!openFd) {
-        openFd = initOpenAshmemFd();
+    if (ashmem_device_path.empty()) {
+        return -1;
     }
 
-    if (openFd) {
-        fd = openFd();
-    }
-#endif
-    if (fd < 0) {
-        fd = TEMP_FAILURE_RETRY(open(ASHMEM_DEVICE, O_RDWR | O_CLOEXEC));
-    }
+    int fd = TEMP_FAILURE_RETRY(open(ashmem_device_path.c_str(), O_RDWR | O_CLOEXEC));
     if (fd < 0) {
         return fd;
     }
@@ -485,11 +462,3 @@
 
     return __ashmem_check_failure(fd, TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_GET_SIZE, NULL)));
 }
-
-void ashmem_init() {
-#ifndef __ANDROID_VNDK__
-    pthread_mutex_lock(&__ashmem_lock);
-    openFd = initOpenAshmemFd();
-    pthread_mutex_unlock(&__ashmem_lock);
-#endif  //__ANDROID_VNDK__
-}
diff --git a/libcutils/ashmem-host.cpp b/libcutils/ashmem-host.cpp
index 6c7655a..2ba1eb0 100644
--- a/libcutils/ashmem-host.cpp
+++ b/libcutils/ashmem-host.cpp
@@ -94,5 +94,3 @@
 
     return buf.st_size;
 }
-
-void ashmem_init() {}
diff --git a/libcutils/include/cutils/ashmem.h b/libcutils/include/cutils/ashmem.h
index abc5068..d80caa6 100644
--- a/libcutils/include/cutils/ashmem.h
+++ b/libcutils/include/cutils/ashmem.h
@@ -26,7 +26,6 @@
 int ashmem_pin_region(int fd, size_t offset, size_t len);
 int ashmem_unpin_region(int fd, size_t offset, size_t len);
 int ashmem_get_size_region(int fd);
-void ashmem_init();
 
 #ifdef __cplusplus
 }
diff --git a/libmeminfo/vts/Android.bp b/libmeminfo/vts/Android.bp
index 5a3a23b..a92f669 100644
--- a/libmeminfo/vts/Android.bp
+++ b/libmeminfo/vts/Android.bp
@@ -12,9 +12,22 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-cc_test {
-    name: "vts_meminfo_test",
+cc_defaults {
+    name: "vts_meminfo_defaults",
     defaults: ["libmeminfo_defaults"],
     srcs: ["vts_meminfo_test.cpp"],
     static_libs: ["libmeminfo"],
 }
+
+cc_test {
+    name: "vts_meminfo_test",
+    defaults: ["vts_meminfo_defaults"],
+}
+
+cc_test {
+    name: "vts_core_meminfo_test",
+    defaults: ["vts_meminfo_defaults"],
+    test_suites: ["vts-core"],
+    auto_gen_config: true,
+    test_min_api_level: 29,
+}
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index d17da12..f06717d 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -362,6 +362,9 @@
 /* PAGE_SIZE / 1024 */
 static long page_k;
 
+static char* proc_get_name(int pid);
+static void poll_kernel();
+
 static bool parse_int64(const char* str, int64_t* ret) {
     char* endptr;
     long long val = strtoll(str, &endptr, 10);
@@ -634,6 +637,9 @@
     }
 
     if (use_inkernel_interface) {
+#ifdef LMKD_LOG_STATS
+        stats_store_taskname(params.pid, proc_get_name(params.pid));
+#endif
         return;
     }
 
@@ -704,6 +710,16 @@
     struct lmk_procremove params;
 
     if (use_inkernel_interface) {
+#ifdef LMKD_LOG_STATS
+        /* Perform an extra check before the pid is removed, after which it
+         * will be impossible for poll_kernel to get the taskname. poll_kernel()
+         * is potentially a long-running blocking function; however this method
+         * handles AMS requests but does not block AMS.*/
+        if (enable_stats_log) {
+            poll_kernel();
+        }
+        stats_remove_taskname(params.pid);
+#endif
         return;
     }
 
@@ -721,6 +737,9 @@
     struct proc *next;
 
     if (use_inkernel_interface) {
+#ifdef LMKD_LOG_STATS
+        stats_purge_tasknames();
+#endif
         return;
     }
 
@@ -1925,7 +1944,6 @@
 
 #ifdef LMKD_LOG_STATS
 static int kernel_poll_fd = -1;
-
 static void poll_kernel() {
     if (kernel_poll_fd == -1) {
         // not waiting
@@ -1958,9 +1976,9 @@
         /* only the death of the group leader process is logged */
         if (fields_read == 10 && group_leader_pid == pid) {
             int64_t process_start_time_ns = starttime * (NS_PER_SEC / sysconf(_SC_CLK_TCK));
-            stats_write_lmk_kill_occurred(log_ctx, LMK_KILL_OCCURRED, uid, taskname, oom_score_adj,
-                                          min_flt, maj_flt, rss_in_pages * PAGE_SIZE, 0, 0,
-                                          process_start_time_ns, min_score_adj);
+            stats_write_lmk_kill_occurred_pid(log_ctx, LMK_KILL_OCCURRED, uid, pid, oom_score_adj,
+                                              min_flt, maj_flt, rss_in_pages * PAGE_SIZE, 0, 0,
+                                              process_start_time_ns, min_score_adj);
         }
 
         free(taskname);
diff --git a/lmkd/statslog.c b/lmkd/statslog.c
index 0c230ae..f3a6e55 100644
--- a/lmkd/statslog.c
+++ b/lmkd/statslog.c
@@ -18,8 +18,22 @@
 #include <errno.h>
 #include <log/log_id.h>
 #include <stats_event_list.h>
+#include <stdlib.h>
+#include <string.h>
 #include <time.h>
 
+#define LINE_MAX 128
+
+struct proc {
+    int pid;
+    char taskname[LINE_MAX];
+    struct proc* pidhash_next;
+};
+
+#define PIDHASH_SZ 1024
+static struct proc** pidhash = NULL;
+#define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1))
+
 static int64_t getElapsedRealTimeNs() {
     struct timespec t;
     t.tv_sec = t.tv_nsec = 0;
@@ -57,6 +71,17 @@
     return write_to_logger(ctx, LOG_ID_STATS);
 }
 
+static struct proc* pid_lookup(int pid) {
+    struct proc* procp;
+
+    if (!pidhash) return NULL;
+
+    for (procp = pidhash[pid_hashfn(pid)]; procp && procp->pid != pid; procp = procp->pidhash_next)
+        ;
+
+    return procp;
+}
+
 /**
  * Logs the event when LMKD kills a process to reduce memory pressure.
  * Code: LMK_KILL_OCCURRED = 51
@@ -124,3 +149,74 @@
 
     return write_to_logger(ctx, LOG_ID_STATS);
 }
+
+int stats_write_lmk_kill_occurred_pid(android_log_context ctx, int32_t code, int32_t uid, int pid,
+                                      int32_t oom_score, int64_t pgfault, int64_t pgmajfault,
+                                      int64_t rss_in_bytes, int64_t cache_in_bytes,
+                                      int64_t swap_in_bytes, int64_t process_start_time_ns,
+                                      int32_t min_oom_score) {
+    struct proc* proc = pid_lookup(pid);
+    if (!proc) return -EINVAL;
+
+    return stats_write_lmk_kill_occurred(ctx, code, uid, proc->taskname, oom_score, pgfault,
+                                         pgmajfault, rss_in_bytes, cache_in_bytes, swap_in_bytes,
+                                         process_start_time_ns, min_oom_score);
+}
+
+static void proc_insert(struct proc* procp) {
+    if (!pidhash)
+        pidhash = calloc(PIDHASH_SZ, sizeof(struct proc));
+    int hval = pid_hashfn(procp->pid);
+    procp->pidhash_next = pidhash[hval];
+    pidhash[hval] = procp;
+}
+
+void stats_remove_taskname(int pid) {
+    if (!pidhash) return;
+
+    int hval = pid_hashfn(pid);
+    struct proc* procp;
+    struct proc* prevp;
+
+    for (procp = pidhash[hval], prevp = NULL; procp && procp->pid != pid;
+         procp = procp->pidhash_next)
+        prevp = procp;
+
+    if (!procp)
+        return;
+
+    if (!prevp)
+        pidhash[hval] = procp->pidhash_next;
+    else
+        prevp->pidhash_next = procp->pidhash_next;
+
+    free(procp);
+}
+
+void stats_store_taskname(int pid, const char* taskname) {
+    struct proc* procp = pid_lookup(pid);
+    if (procp != NULL && strcmp(procp->taskname, taskname) == 0)
+        return;
+    procp = malloc(sizeof(struct proc));
+    stats_remove_taskname(pid);
+    procp->pid = pid;
+    strncpy(procp->taskname, taskname, LINE_MAX - 1);
+    procp->taskname[LINE_MAX - 1] = '\0';
+    proc_insert(procp);
+}
+
+void stats_purge_tasknames() {
+    if (!pidhash) return;
+    struct proc* procp;
+    struct proc* next;
+    int i;
+    for (i = 0; i < PIDHASH_SZ; i++) {
+        procp = pidhash[i];
+        while (procp) {
+            next = procp->pidhash_next;
+            free(procp);
+            procp = next;
+        }
+    }
+    memset(pidhash, 0, PIDHASH_SZ * sizeof(struct proc));
+}
diff --git a/lmkd/statslog.h b/lmkd/statslog.h
index 2edba7a..50d69f7 100644
--- a/lmkd/statslog.h
+++ b/lmkd/statslog.h
@@ -85,12 +85,41 @@
  * Code: LMK_KILL_OCCURRED = 51
  */
 int
+stats_write_lmk_kill_occurred_pid(android_log_context ctx, int32_t code, int32_t uid, int pid,
+                                  int32_t oom_score, int64_t pgfault, int64_t pgmajfault,
+                                  int64_t rss_in_bytes, int64_t cache_in_bytes,
+                                  int64_t swap_in_bytes, int64_t process_start_time_ns,
+                                  int32_t min_oom_score);
+
+/**
+ * Logs the event when LMKD kills a process to reduce memory pressure.
+ * Code: LMK_KILL_OCCURRED = 51
+ */
+int
 stats_write_lmk_kill_occurred(android_log_context ctx, int32_t code, int32_t uid,
                               char const* process_name, int32_t oom_score, int64_t pgfault,
                               int64_t pgmajfault, int64_t rss_in_bytes, int64_t cache_in_bytes,
                               int64_t swap_in_bytes, int64_t process_start_time_ns,
                               int32_t min_oom_score);
 
+/**
+ * Registers a process taskname by pid, while it is still alive.
+ */
+void
+stats_store_taskname(int pid, const char* taskname);
+
+/**
+ * Unregister all process tasknames.
+ */
+void
+stats_purge_tasknames();
+
+/**
+ * Unregister a process taskname, e.g. after it has been killed.
+ */
+void
+stats_remove_taskname(int pid);
+
 __END_DECLS
 
 #endif /* _STATSLOG_H_ */
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index 451f5ad..9c2cdf2 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -33,7 +33,7 @@
 /dev/urandom              0666   root       root
 # Make HW RNG readable by group system to let EntropyMixer read it.
 /dev/hw_random            0440   root       system
-/dev/ashmem               0666   root       root
+/dev/ashmem*              0666   root       root
 /dev/binder               0666   root       root
 /dev/hwbinder             0666   root       root
 /dev/vndbinder            0666   root       root