Подтвердить что ты не робот

Установка имени процесса в Mac OS X во время выполнения

Я пытаюсь изменить имя моего процесса, как показано в ps и Activity Monitor во время выполнения. Я нашел несколько заметок о том, что нет никакого переносного способа сделать это (что меня не волнует).

Вот что я пробовал. Ни один из этих подходов не работал у меня.

  • Изменение argv[0] (похоже, это путь для некоторых Unix-систем)
  • Вызов [[NSProcessInfo processInfo] setProcessName:@"someName"]
  • Вызов setprogname (вызов getprogname возвращает имя, которое я установил, но это не имеет значения)

Я также читал о функции под названием setproctitle, которая должна быть определена в stdlib.h, если она доступна, но она не существует.

Должен быть способ сделать это, потому что QTKitServer - безликий декодер для QuickTime Player X - имеет свой соответствующий идентификатор проигрывателя QuickTime Player в его имени процесса.

Кто-нибудь знает, как это сделать? Я бы предпочел использовать Core Foundation или POSIXy для метода Objective-C для этого.

Спасибо,

Marco

Изменить: Если это так важно, я использую Mac OS X 10.6.5 и Xcode 3.2.5

4b9b3361

Ответ 1

Есть веские причины для изменения имени процесса. Программное обеспечение Java должно менять имена процессов, потому что при запуске различных инструментов Java я хочу посмотреть, какой Java-процесс для какого инструмента.

Chromium делает это: http://src.chromium.org/viewvc/chrome/trunk/src/base/mac/mac_util.mm.

Node.js использует тот же код для реализации Process.title = 'newtitle': https://github.com/joyent/node/blob/master/src/platform_darwin_proctitle.cc

Примечание.. Это не удается, если кто-то делает su другому не зарегистрированному пользователю: https://github.com/joyent/node/issues/1727

Здесь исходный код в его полной комплексной славе. Кстати, кто-то сказал мне, что он также работает для Mac OS X Lion, а также не работает с su.

// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
void SetProcessName(CFStringRef process_name) {
  if (!process_name || CFStringGetLength(process_name) == 0) {
    NOTREACHED() << "SetProcessName given bad name.";
    return;
  }

  if (![NSThread isMainThread]) {
    NOTREACHED() << "Should only set process name from main thread.";
    return;
  }

  // Warning: here be dragons! This is SPI reverse-engineered from WebKit's
  // plugin host, and could break at any time (although realistically it only
  // likely to break in a new major release).
  // When 10.7 is available, check that this still works, and update this
  // comment for 10.8.

  // Private CFType used in these LaunchServices calls.
  typedef CFTypeRef PrivateLSASN;
  typedef PrivateLSASN (*LSGetCurrentApplicationASNType)();
  typedef OSStatus (*LSSetApplicationInformationItemType)(int, PrivateLSASN,
                                                          CFStringRef,
                                                          CFStringRef,
                                                          CFDictionaryRef*);

  static LSGetCurrentApplicationASNType ls_get_current_application_asn_func =
      NULL;
  static LSSetApplicationInformationItemType
      ls_set_application_information_item_func = NULL;
  static CFStringRef ls_display_name_key = NULL;

  static bool did_symbol_lookup = false;
  if (!did_symbol_lookup) {
    did_symbol_lookup = true;
    CFBundleRef launch_services_bundle =
        CFBundleGetBundleWithIdentifier(CFSTR("com.apple.LaunchServices"));
    if (!launch_services_bundle) {
      LOG(ERROR) << "Failed to look up LaunchServices bundle";
      return;
    }

    ls_get_current_application_asn_func =
        reinterpret_cast<LSGetCurrentApplicationASNType>(
            CFBundleGetFunctionPointerForName(
                launch_services_bundle, CFSTR("_LSGetCurrentApplicationASN")));
    if (!ls_get_current_application_asn_func)
      LOG(ERROR) << "Could not find _LSGetCurrentApplicationASN";

    ls_set_application_information_item_func =
        reinterpret_cast<LSSetApplicationInformationItemType>(
            CFBundleGetFunctionPointerForName(
                launch_services_bundle,
                CFSTR("_LSSetApplicationInformationItem")));
    if (!ls_set_application_information_item_func)
      LOG(ERROR) << "Could not find _LSSetApplicationInformationItem";

    CFStringRef* key_pointer = reinterpret_cast<CFStringRef*>(
        CFBundleGetDataPointerForName(launch_services_bundle,
                                      CFSTR("_kLSDisplayNameKey")));
    ls_display_name_key = key_pointer ? *key_pointer : NULL;
    if (!ls_display_name_key)
      LOG(ERROR) << "Could not find _kLSDisplayNameKey";

    // Internally, this call relies on the Mach ports that are started up by the
    // Carbon Process Manager.  In debug builds this usually happens due to how
    // the logging layers are started up; but in release, it isn't started in as
    // much of a defined order.  So if the symbols had to be loaded, go ahead
    // and force a call to make sure the manager has been initialized and hence
    // the ports are opened.
    ProcessSerialNumber psn;
    GetCurrentProcess(&psn);
  }
  if (!ls_get_current_application_asn_func ||
      !ls_set_application_information_item_func ||
      !ls_display_name_key) {
    return;
  }

  PrivateLSASN asn = ls_get_current_application_asn_func();
  // Constant used by WebKit; what exactly it means is unknown.
  const int magic_session_constant = -2;
  OSErr err =
      ls_set_application_information_item_func(magic_session_constant, asn,
                                               ls_display_name_key,
                                               process_name,
                                               NULL /* optional out param */);
  LOG_IF(ERROR, err) << "Call to set process name failed, err " << err;
}

Изменить. Это сложная и запутанная проблема.

В OS X нет setproctitle (3). Нужно писать в массив argv (уродливый и немного опасно, потому что можно переписать некоторые переменные среды фиктивными элементами). Выполнено правильно, он работает очень хорошо.

Кроме того, у Apple есть приложение ActivityMonitor, что-то вроде диспетчера задач под Windows. В приведенном выше коде манипулирует ActivityMonitor, но эта манипуляция, похоже, не поощряется Apple (отсюда и использование недокументированных функций).

Важно: ps и ActivityMonitor не отображают ту же информацию.

Также важно: ActivityMonitor недоступен, если у вас нет графического интерфейса. Это может произойти, если вы подключились к удаленному ящику Apple, и никому не удалось войти в систему по графическому интерфейсу. К сожалению, есть ошибка Apple IMO. Просто запрос, если есть GUI, отправляет раздражающее предупреждающее сообщение в stderr.

Резюме. Если вам нужно изменить ActivityMonitor, используйте приведенный выше код. Если у вас есть ситуации с графическим интерфейсом и не нравятся предупреждения stderr, временно переадресовывайте stderr в /dev/null во время вызова SetProcessName. Если вам нужно изменить информацию о ps, напишите в argv.