Use cmdline instead for enabling heapprofd.

Because we also want to profile Java applications, which have longer
names, the character limit of comm is a problem. To avoid complexity, it
is preferable to apply the same logic for finding running processes
(which includes Java apps), and determining whether to profile a process
from startup.

Test: m
Test: flash sailfish
Test: setprop heapprofd.enable 1
      setprop heapprofd.enable.ls 1
      ls
      /system/bin/ls
      /system/bin/ls /

Bug: 120175590

Change-Id: Id0859d4a333efcb05883e611ea6a31a51468f82c
diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp
index 8d8d420..031b0aa 100644
--- a/libc/bionic/malloc_common.cpp
+++ b/libc/bionic/malloc_common.cpp
@@ -252,8 +252,10 @@
 #if !defined(LIBC_STATIC)
 
 #include <dlfcn.h>
+#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <unistd.h>
 
 #include <async_safe/log.h>
 #include <sys/system_properties.h>
@@ -470,6 +472,64 @@
   return true;
 }
 
+static bool GetHeapprofdProgramProperty(char* data, size_t size) {
+  constexpr char prefix[] = "heapprofd.enable.";
+  // - 1 to skip nullbyte, which we will write later.
+  constexpr size_t prefix_size = sizeof(prefix) - 1;
+  if (size < prefix_size) {
+    error_log("%s: Overflow constructing heapprofd property", getprogname());
+    return false;
+  }
+  memcpy(data, prefix, prefix_size);
+
+  int fd = open("/proc/self/cmdline", O_RDONLY | O_CLOEXEC);
+  if (fd == -1) {
+    error_log("%s: Failed to open /proc/self/cmdline", getprogname());
+    return false;
+  }
+  char cmdline[128];
+  ssize_t rd = read(fd, cmdline, sizeof(cmdline) - 1);
+  close(fd);
+  if (rd == -1) {
+    error_log("%s: Failed to read /proc/self/cmdline", getprogname());
+    return false;
+  }
+  cmdline[rd] = '\0';
+  char* first_arg = static_cast<char*>(memchr(cmdline, '\0', rd));
+  if (first_arg == nullptr || first_arg == cmdline + size - 1) {
+    error_log("%s: Overflow reading cmdline", getprogname());
+    return false;
+  }
+  // For consistency with what we do with Java app cmdlines, trim everything
+  // after the @ sign of the first arg.
+  char* first_at = static_cast<char*>(memchr(cmdline, '@', rd));
+  if (first_at != nullptr && first_at < first_arg) {
+    *first_at = '\0';
+    first_arg = first_at;
+  }
+
+  char* start = static_cast<char*>(memrchr(cmdline, '/', first_arg - cmdline));
+  if (start == first_arg) {
+    // The first argument ended in a slash.
+    error_log("%s: cmdline ends in /", getprogname());
+    return false;
+  } else if (start == nullptr) {
+    start = cmdline;
+  } else {
+    // Skip the /.
+    start++;
+  }
+
+  size_t name_size = static_cast<size_t>(first_arg - start);
+  if (name_size >= size - prefix_size) {
+    error_log("%s: overflow constructing heapprofd property.", getprogname());
+    return false;
+  }
+  // + 1 to also copy the trailing null byte.
+  memcpy(data + prefix_size, start, name_size + 1);
+  return true;
+}
+
 static bool CheckLoadHeapprofd() {
   // First check for heapprofd.enable. If it is set to "all", enable
   // heapprofd for all processes. Otherwise, check heapprofd.enable.${prog},
@@ -483,23 +543,13 @@
   }
 
   char program_property[128];
-  int ret = snprintf(program_property, sizeof(program_property), "%s.%s",
-                     HEAPPROFD_PROPERTY_ENABLE, getprogname());
-
-  if (ret < 0 || static_cast<size_t>(ret) >= sizeof(program_property)) {
-    if (ret < 0) {
-      error_log("Failed to concatenate heapprofd property %s.%s: %s",
-                HEAPPROFD_PROPERTY_ENABLE, getprogname(), strerror(errno));
-    } else {
-      error_log("Overflow in concatenating heapprofd property");
-    }
+  if (!GetHeapprofdProgramProperty(program_property,
+                                   sizeof(program_property))) {
     return false;
   }
-
   if (__system_property_get(program_property, property_value) == 0) {
     return false;
   }
-
   return program_property[0] != '\0';
 }