3

我正在开发一个具有 Objective-C 守护进程的 Cocoa GUI 应用程序。守护进程由 LaunchDaemon 启动,GUI 使用 loginItems 为每个用户启动。

部署更新时,我需要更新守护进程,这很简单,并更新 GUI。我希望能够退出 GUI,替换应用程序,然后在当前运行的每个用户帐户上重新启动它。我想从当然以 root 身份运行的守护进程完成所有这些工作。

我怎么能:1)作为root,退出然后在另一个用户界面中重新启动应用程序?2) 作为root,退出然后为每个当前登录的用户重新启动一个特定的loginItem 吗?

我试过搜索,有很多讨论,包括这个类似的问题,但似乎没有可用的工作解决方案。

任何帮助是极大的赞赏。

4

3 回答 3

3

我相信 NSDistributedNotificationCenter 应该为此工作。请注意,使用 NSDistributedNotificationCenter 在不同用户帐户中的进程之间进行通信本身并不需要 root 权限。

为了帮助用户帐户之间的协调,它可能有助于区分 GUI 应用程序和守护程序的哪个实例当前处于活动状态并受控制,以及哪些实例是被动的。您可以使用 NSWorkspace 的通知(NSWorkspaceSessionDidBecomeActiveNotification、NSWorkspaceSessionDidResignActiveNotification)来确定用户何时在用户帐户之间切换等,并让您的实例进行相应的设置。

假设您的 GUI 应用程序和守护程序在 3 个不同的用户帐户中运行实例。例如,如果在活动用户帐户中,您想开始更新过程,您可以使用 NSDistributedNotificationCenter 轻松告诉所有其他实例立即关闭。为此,您需要定义如下内容。

在 .h 文件中,声明不同通知的名称:

extern NSString * const MDShouldTerminateImmediatelyNotification;

在(一个)实现文件中,创建名称,并将类设置为对该名称的分布式通知感兴趣,等等:

NSString * const MDShouldTerminateImmediatelyNotification = @"MDShouldTerminateImmediately";


- (id)init {
   if (self = [super init]) {
       [[NSDistributedNotificationCenter defaultCenter]
       addObserver:self
       selector:@selector(shouldTerminateImmediately:)
       name:MDShouldTerminateImmediatelyNotification
       object:nil];
   }
   return self;
}

- (void)dealloc {
   [[NSDistributedNotificationCenter defaultCenter] removeObserver:self];
   [super dealloc];
}

- (void)shouldTerminateImmediately:(NSNotification *)notification {
   if (ourInstanceIsInControl == NO) {
     [NSApp terminate:nil];
    }
}

在将启动更新过程的类中,您将执行以下操作来发送通知:

- (void)beginUpdate {
   [[NSDistributedNotificationCenter defaultCenter]
    postNotificationName:MDShouldTerminateImmediatelyNotification
       object:[self description] // or just nil
       userInfo:nil
       options:NSNotificationDeliverImmediately | NSNotificationPostToAllSessions];
    // continue

}

我认为这至少应该是一个开始工作的开始。

实际上,如果您正在谈论让一个守护进程实例以 root 身份运行,它可以在所有用户帐户中执行所有操作,您可能需要考虑将该部分分解为 Launchd Agent 类型的进程(后台进程,在用户级别运行,每个用户帐户会有自己的实例)。

欲了解更多信息:

技术说明 TN2083 守护程序和代理

根和登录会话

创建启动的守护进程和代理

于 2010-12-01T15:52:51.897 回答
3

因此,我使用 Apple 的支持请求来获得最佳答案,并结合一些在线研究。

攻击的基本计划是让每个 GUI 实例在守护进程要求时重新启动。

首先,我让守护进程替换了 GUI 的包(.app 文件夹)。您可以在应用程序仍在惊人地运行时执行此操作。这就是 Apple 支持提供帮助的地方。我仍然对可以在运行时更换应用程序感到惊讶,但他们告诉我这样做并且没问题。

然后我让守护进程向 GUI 发送 DistributedNotification 并显示一条消息以自行重启。为了让 GUI 正确响应,我创建了重新启动器类,它将获取它自己的 pid 和包路径,然后我在内存中构建了一个 shell 脚本来杀死 pid,等待 10 秒,然后执行一个 shell“打开 bundlepath.app”,然后它重新启动。

我使用 NSTask 调用“内存中”的 shell 脚本,它实际上只是一个 @"kill %@; sleep 10; open %@", pid, bundlePath....

效果惊人!

感谢您的建议!

于 2010-12-17T13:51:50.890 回答
0

在 Apple 的文档中查找“授权服务”。

于 2010-12-01T00:24:15.177 回答