2014-12-01 3 views
2

Я ищу подход для обнаружения закрытия приложения (например, cmd-q) в пространстве ядра для обработки в расширении сетевого ядра.Как обнаружить завершение приложения в расширении ядра, Mac OS X

Точнее: Хотя процесс (например, терминал ping) хранится в IOLockSleep (... THREAD_ABORTSAFE), ctrl-c может освободить блокировку. Спрашивая proc_issignal(), он отвечает на сигмаску (SIGINT).

Теперь я ищу способ обнаружить другой процесс, например, firefox (строка меню: приложение quit (cmd-q)).

Вот что я пробовал:

#define FLAG(X) ((dispatch_source_get_data(src) & DISPATCH_PROC_##X) ? #X" " : "") 

struct ProcessInfo { 
    int pid; 
    dispatch_source_t source; 
}; 

// function called back on event 
void process_termination_event(struct ProcessInfo* procinfo) { 
    dispatch_source_t src = procinfo->source; 
    printf("process_termination_event: %d \n", procinfo->pid); 
    printf("flags: %s%s\n", FLAG(EXIT), FLAG(SIGNAL)); 
    dispatch_source_cancel(procinfo->source); 
} 

// function called back when the dispatch source is cancelled 
void process_termination_finalize(struct ProcessInfo* procinfo) { 
    printf("process_termination_finalize: %d \n", procinfo->pid); 
    dispatch_release(procinfo->source); 
} 

// Monitor a process by pid, for termination 
void MonitorTermination(int pid) { 
    struct ProcessInfo* procinfo = (struct ProcessInfo*)malloc(sizeof(struct ProcessInfo)); 

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
    dispatch_source_t dsp = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC, pid, DISPATCH_PROC_EXIT|DISPATCH_PROC_SIGNAL, queue); 

    procinfo->pid = pid; 
    procinfo->source = dsp; 

    dispatch_source_set_event_handler_f(procinfo->source, (dispatch_function_t)process_termination_event); 
    dispatch_source_set_cancel_handler_f(procinfo->source, (dispatch_function_t)process_termination_finalize); 
    dispatch_set_context(procinfo->source, procinfo); 
    dispatch_resume(procinfo->source); 
} 

int main(int argc, const char * argv[]) 
{ 
    for (int i = 0; i < argc; ++i) { 
     pid_t pid = atoi(argv[i]); 
     printf("MonitorTermination: %d\n", pid); 
     fflush(stdout); 

     MonitorTermination(pid); 
    } 

    CFRunLoopRun(); 
    return 0; 
} 

process_termination_event не будет вызывать после CMD-ц, как описано выше. Даже после того, как сила ушла.

Сам процесс проходит в цикле в функции сетевого расширения ядра:

errno_t KEXT::data_out(void *cookie, socket_t so, const struct sockaddr *to, mbuf_t *data, mbuf_t *control, sflt_data_flag_t flags) 
{ 
    // at this point I would like to detect the app quit/termination signal. 
    while(PROCESS_IS_NOT_TEMINATING); // <-- pseudo code, actually held with IOLockSleep... 
    return 0; 
} 

Я был бы очень признателен за любую помощь! Заранее спасибо.

ответ

1

Возможно, это не так, как вы думали, но если вы находитесь в пространстве ядра, то я предполагаю, что вы пишете расширение ядра (kext). С расширением ядра вы можете использовать monitor Vnodes для выполнения приложений. Вместо этого вы можете использовать область файлов.

В сочетании с приложением (демоном) на уровне пользователя kext уведомляет демона о начале процесса, а затем отслеживает завершение запущенного приложения с демона уровня пользователя, используя функции Grand Central Dispatch. При необходимости пользовательское приложение может уведомить kext о завершенном приложении.

Чтобы контролировать окончание из приложений пользовательского уровня, вы можете сделать что-то вроде этого, когда вы будете получать уведомления о приложение выполняется: -

// pid and path provided from vNode scope kext... 
void UserLevelApp::MonitorProcessTermination(int pid, const QString &path) 
{  
    ProcessInfo* procinfo = new ProcessInfo; 

    procinfo->pid = pid; 
    procinfo->path = path; 
    procinfo->context = this; 

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
    dispatch_source_t dsp = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC, pid, DISPATCH_PROC_EXIT, queue); 

    dispatch_source_set_event_handler_f(dsp, (dispatch_function_t)process_termination_event); 
    dispatch_source_set_cancel_handler_f(dsp, (dispatch_function_t)process_termination_finalize); 

    procinfo->source = dsp; 
    dispatch_set_context(dsp, procinfo); 

    dispatch_resume(dsp); 
} 

// app terminated call-back function 
void UserLevelApp::process_termination_event(struct ProcessInfo* procinfo) 
{ 
    dispatch_source_cancel(procinfo->source); 

    // example of how to use the context to call a class function 
    procinfo->context->SomeClassFunction(procinfo->pid, procinfo->path); 

    qDebug("App Terminated: %d, %s\n", procinfo->pid, procinfo->path.toUtf8().data()); 
} 

// finalize callback function 
void UserLevelApp::process_termination_finalize(struct ProcessInfo* procinfo) 
{ 
    dispatch_release(procinfo->source); 
    delete procinfo; 
} 

Таким образом, каждый запущенное приложение, уведомляется Kext, имеют обработчик событий, связанный с ним, и, когда приложение завершается, вы получите перезвонили в зарегистрированных функциях process_termination_event и process_termination_finalize

Хотя этот метод требует Associa ted на уровне пользователя с помощью kext, это не так уж плохо с точки зрения безопасности и стабильности.

+0

Подход хороший. Но я застрял с проблемой «завершение работы приложения». Поскольку функция kext сохраняет приложение в активном режиме. Приложение не может завершиться до завершения обработки kext. – Jan

+0

Если вы реализовали то, что я описал, не должно быть никаких проблем с завершением приложения - я все время использую это. Расширение ядра делает не что иное, как уведомление демона активности процесса, оно не должно содержать никаких ресурсов процесса. – TheDarkKnight

+0

Я думаю, что я реализовал, как описано. Теперь я добавил более подробное описание и код демона. Может быть, что-то не так, или обработка kext (в то время как цикл/блокировка) совсем не соответствует намерению? – Jan

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