System property for heapprofd at process startup.

Test: m
Test: flash sailfish
Test: setprop heapprofd.enable 1;
      setprop heapprofd.enable.ls 1;
      ls;

Bug: 117821125

Change-Id: I4a42e430e5e1e194a22f83683061751aa5dfe7ff
diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp
index 3a94084..8d8d420 100644
--- a/libc/bionic/malloc_common.cpp
+++ b/libc/bionic/malloc_common.cpp
@@ -271,6 +271,7 @@
 
 static const char* HEAPPROFD_SHARED_LIB = "heapprofd_client.so";
 static const char* HEAPPROFD_PREFIX = "heapprofd";
+static const char* HEAPPROFD_PROPERTY_ENABLE = "heapprofd.enable";
 static const int HEAPPROFD_SIGNAL = __SIGRTMIN + 4;
 
 enum FunctionEnum : uint8_t {
@@ -469,6 +470,39 @@
   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},
+  // if it is set and not 0, enable heap profiling for this process.
+  char property_value[PROP_VALUE_MAX];
+  if (__system_property_get(HEAPPROFD_PROPERTY_ENABLE, property_value) == 0) {
+    return false;
+  }
+  if (strcmp(property_value, "all") == 0) {
+    return true;
+  }
+
+  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");
+    }
+    return false;
+  }
+
+  if (__system_property_get(program_property, property_value) == 0) {
+    return false;
+  }
+
+  return program_property[0] != '\0';
+}
+
 static void ClearGlobalFunctions() {
   for (size_t i = 0; i < FUNC_LAST; i++) {
     g_functions[i] = nullptr;
@@ -572,6 +606,9 @@
   } else if (CheckLoadMallocHooks(&options)) {
     prefix = "hooks";
     shared_lib = HOOKS_SHARED_LIB;
+  } else if (CheckLoadHeapprofd()) {
+    prefix = "heapprofd";
+    shared_lib = HEAPPROFD_SHARED_LIB;
   } else {
     return;
   }