2010-11-18 5 views
15

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

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

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

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

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

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

Спасибо,

Marco

Edit: Если это в любом случае необходимо, я использую Mac OS X 10.6.5 и Xcode 3.2.5

+0

@ Alex Brown (кто редактировал теги): Я намеренно установил тег для этого вопроса на «Mac» вместо «posix», потому что POSIXy-пути, которые я нашел для этого, не сработали для меня ('argv [0]' и 'setproctitle()'). –

ответ

11

Там хорошие причины для изменения имени процесса. Программное обеспечение 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's 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; 
} 

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

На 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.

+0

Спасибо, это работает как шарм! –

+1

Кстати, ваш проект с открытым исходным кодом? Если нет, подумайте об авторских правах, потому что код принадлежит проекту Chromium. – nalply

+0

Нет, мне нужен проект, который не является открытым исходным кодом. Но не беспокойтесь, я не буду копировать код так, как есть. То, что я искал, - это, по сути, информация о том, что вызов _LSSetApplicationInformationItem() дает мне то, что я хочу. Код, который я напишу об этой функции, будет выглядеть совсем по-другому в контексте нашей собственной библиотеки и поэтому не должен нарушать GPL. –

2

Вы можете использовать lsappinfo инструмент, который поставляется с MacOS, по крайней мере, 10,6 и до сегодняшнего дня (10.13.2):

Shell:

lsappinfo setinfo <PID> --name <NAME> 

C++:

#include <sstream> 
#include <string> 
#include <stdlib.h> 

void setProcessName (pid_t pid, std::string name) 
{ 
    std::ostringstream cmd; 
    cmd << "/usr/bin/lsappinfo setinfo " << pid; 
    cmd << " --name \"" << name << "\""; 
    system (cmd.str().c_str()); 
} 
+1

Вау, я не знал об этой команде, кажется довольно интересным. Настройка имени, как это работает, как шарм! 'lsappinfo' представляется интерфейсом для функций, описанных в коде @ nalply. Более семи лет спустя, необходимость в этом ушла, хотя –

+0

Я боялся, что код в предыдущем ответе может перестать работать или потребовать обслуживания, поэтому, увидев этот ответ, я продолжал искать и находить о 'lsappinfo'. Надеюсь, что это открытый API, а не «секретный API», этот инструмент будет хорошо работать в будущих ОС :) – yairchu

Смежные вопросы