[standalone, mac] Set the process title based on the main script.

This makes it easier to identify the responsible program when a Dart process has high CPU or memory usage.

TEST=look at Activity Monitor
Change-Id: Ibcdcc1becf72a25dab5b010accdd8dcd199a0ba1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/214137
Reviewed-by: Siva Annamalai <asiva@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
diff --git a/runtime/bin/platform_macos.cc b/runtime/bin/platform_macos.cc
index 0c22675..b78112e 100644
--- a/runtime/bin/platform_macos.cc
+++ b/runtime/bin/platform_macos.cc
@@ -13,6 +13,7 @@
 #if !DART_HOST_OS_IOS
 #include <crt_externs.h>  // NOLINT
 #endif                    // !DART_HOST_OS_IOS
+#include <dlfcn.h>        // NOLINT
 #include <errno.h>        // NOLINT
 #include <mach-o/dyld.h>
 #include <signal.h>        // NOLINT
@@ -251,7 +252,98 @@
   return path_size;
 }
 
-void Platform::SetProcessName(const char* name) {}
+void Platform::SetProcessName(const char* name) {
+  pthread_setname_np(name);
+
+#if !defined(DART_HOST_OS_IOS) && !defined(DART_PRECOMPILED_RUNTIME)
+  // Attempt to set the name displayed in ActivityMonitor.
+  // https://codereview.chromium.org/659007/
+
+  class ScopedDLHandle : public ValueObject {
+   public:
+    explicit ScopedDLHandle(void* handle) : handle_(handle) {}
+    ~ScopedDLHandle() {
+      if (handle_ != NULL) dlclose(handle_);
+    }
+    void* get() const { return handle_; }
+
+   private:
+    void* handle_;
+    DISALLOW_COPY_AND_ASSIGN(ScopedDLHandle);
+  };
+
+  class ScopedCFStringRef : public ValueObject {
+   public:
+    explicit ScopedCFStringRef(const char* s)
+        : ref_(CFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8)) {}
+    ~ScopedCFStringRef() {
+      if (ref_ != NULL) CFRelease(ref_);
+    }
+    CFStringRef get() const { return ref_; }
+
+   private:
+    CFStringRef ref_;
+    DISALLOW_COPY_AND_ASSIGN(ScopedCFStringRef);
+  };
+
+  ScopedDLHandle application_services_handle(
+      dlopen("/System/Library/Frameworks/ApplicationServices.framework/"
+             "Versions/A/ApplicationServices",
+             RTLD_LAZY | RTLD_LOCAL));
+  if (application_services_handle.get() == NULL) return;
+
+  ScopedCFStringRef launch_services_bundle_name("com.apple.LaunchServices");
+  CFBundleRef launch_services_bundle =
+      CFBundleGetBundleWithIdentifier(launch_services_bundle_name.get());
+  if (launch_services_bundle == NULL) return;
+
+#define GET_FUNC(name, cstr)                                                   \
+  ScopedCFStringRef name##_id(cstr);                                           \
+  *reinterpret_cast<void**>(&name) = CFBundleGetFunctionPointerForName(        \
+      launch_services_bundle, name##_id.get());                                \
+  if (name == NULL) return;
+
+#define GET_DATA(name, cstr)                                                   \
+  ScopedCFStringRef name##_id(cstr);                                           \
+  *reinterpret_cast<void**>(&name) =                                           \
+      CFBundleGetDataPointerForName(launch_services_bundle, name##_id.get());  \
+  if (name == NULL) return;
+
+  CFTypeRef (*_LSGetCurrentApplicationASN)(void);
+  GET_FUNC(_LSGetCurrentApplicationASN, "_LSGetCurrentApplicationASN");
+
+  OSStatus (*_LSSetApplicationInformationItem)(int, CFTypeRef, CFStringRef,
+                                               CFStringRef, CFDictionaryRef*);
+  GET_FUNC(_LSSetApplicationInformationItem,
+           "_LSSetApplicationInformationItem");
+
+  CFDictionaryRef (*_LSApplicationCheckIn)(int, CFDictionaryRef);
+  GET_FUNC(_LSApplicationCheckIn, "_LSApplicationCheckIn");
+
+  void (*_LSSetApplicationLaunchServicesServerConnectionStatus)(uint64_t,
+                                                                void*);
+  GET_FUNC(_LSSetApplicationLaunchServicesServerConnectionStatus,
+           "_LSSetApplicationLaunchServicesServerConnectionStatus");
+
+  CFStringRef* _kLSDisplayNameKey;
+  GET_DATA(_kLSDisplayNameKey, "_kLSDisplayNameKey");
+  if (*_kLSDisplayNameKey == NULL) return;
+
+  _LSSetApplicationLaunchServicesServerConnectionStatus(0, NULL);
+
+  _LSApplicationCheckIn(-2, CFBundleGetInfoDictionary(CFBundleGetMainBundle()));
+
+  CFTypeRef asn;
+  asn = _LSGetCurrentApplicationASN();
+  if (asn == NULL) return;
+
+  ScopedCFStringRef cf_name(name);
+  _LSSetApplicationInformationItem(-2, asn, *_kLSDisplayNameKey, cf_name.get(),
+                                   NULL);
+#undef GET_DATA
+#undef GET_FUNC
+#endif  // !defined(DART_HOST_OS_IOS)
+}
 
 void Platform::Exit(int exit_code) {
   Console::RestoreConfig();