一个带菜单栏开关的 macOS 小工具,缓解特定的 ArcadeResetPO 调度循环导致 dasd 持续高 CPU 的问题。
更新软件时:菜单栏盾牌 →「恢复商店更新并打开 App Store」。 它会先关闭保护,再恢复本工具暂停的进程。更新完成后,手动点「开启自动保护」。关闭状态跨登录保留,不会偷偷重新开启。
这是针对已观察到的系统异常的绕过方案,不是 macOS 补丁,也不是通用的 CPU 优化器。暂挂
appstoreagent会影响 App Store 下载、更新,以及依赖该进程的商店服务。不能只暂停其中一个 Arcade 任务。
需要 macOS 13+ 和 Xcode Command Line Tools(含 Swift 5.9+)。目前真实复现验证的系统为 macOS 27.0 26A5425a、Apple Silicon;其他系统、Intel Mac 未做实机验证。
git clone https://github.com/linking2014/ArcadeGuard.git
cd ArcadeGuard
bash scripts/install.sh安装脚本在本地编译,不需要第三方依赖,也不需要 sudo。如果缺少编译工具,先执行 xcode-select --install,完成安装后重试。
安装后菜单栏出现盾牌,保护自动开启,并通过当前用户的 LaunchAgent 在登录后启动。可在系统设置的登录项中检查后台运行许可。手动关闭保护的状态会跨登录保留;重新运行安装脚本会重新开启保护。
应用安装在 ~/Applications/ArcadeGuard.app。如果点击「退出并关闭保护」,可以从 Finder 的个人「应用程序」目录重新打开,再开启保护。
双击应用会打开控制面板,里面直接提供「恢复商店更新并打开 App Store」和「开启自动保护」两个按钮,不必寻找菜单栏图标。
| 菜单 | 行为 |
|---|---|
| 开启自动保护 | 启用每分钟检查;不会立刻无条件暂停进程 |
| 关闭保护并恢复商店 | 保存关闭状态,并恢复本工具暂停的进程 |
| 恢复商店更新并打开 App Store | 关闭保护、恢复进程,然后打开商店 |
| 立即检查 | 额外采样一次;仍需满足持续时间和日志条件 |
| 查看本地记录 | 打开状态和事件记录所在目录 |
| 退出并关闭保护 | 先恢复进程再退出;正常退出后不会立即自动重启 |
| 卸载 ArcadeGuard… | 打开卸载脚本,先恢复进程再移除应用和登录项 |
菜单栏图标:盾牌表示保护开启,空盾牌表示关闭,暂停图标表示本工具已暂挂进程。
菜单栏找不到或程序异常时,可以在 Finder「前往文件夹」中打开:
~/Library/Application Support/ArcadeGuard/
双击 恢复商店更新.command,不依赖菜单栏进程即可关闭保护并打开商店。恢复失败时会报错,不会显示成功,也不会自动卸载恢复工具。
终端也可操作:
"$HOME/Applications/ArcadeGuard.app/Contents/MacOS/ArcadeGuard" off
"$HOME/Applications/ArcadeGuard.app/Contents/MacOS/ArcadeGuard" on
"$HOME/Applications/ArcadeGuard.app/Contents/MacOS/ArcadeGuard" statuson 只修改保护状态。如果之前退出了菜单栏程序,需要再打开应用,才有定时检查。
- 默认每 60 秒采样
dasd的ps %cpu;它是进程 CPU 占用,100% 约为一个 CPU 核心。 - 相隔至少 50 秒的高 CPU 采样均达到 80%,且采样间隔不超过 150 秒,才进一步实时采集 3 秒的特定任务日志。低 CPU、长时间休眠或时间倒退会重置确认过程。
- 实时日志必须包含当前用户至少 3 个不同的
com.apple.appstored.ArcadeResetPO任务实例;每个实例都要有提交与完成事件,重复日志不会重复计数。 - 记录目标 PID、启动时间,再发送
SIGSTOP暂挂当前用户的appstoreagent。不结束或重启dasd。 - 关闭时先保存 OFF 状态,再核对进程身份并发送
SIGCONT;其他工具已暂停的进程不会被接管。
这是保守的启发式判断,不是根因证明。历史日志会被限流,所以采用短时实时采集,并按不同任务实例计数;不以相同事件的重复行数判断循环。即使如此,其他 CPU 负载与该任务的合法密集运行重合时仍可能误判。没有匹配日志或日志读取失败时不干预,也可能因此漏检。CPU 采用离散采样,不能保证期间每一秒都高 CPU。
macOS 没有在该服务的公开配置中提供单独关闭 ArcadeResetPO 的开关。本工具暂停的是整个 appstoreagent。不要在需要无人值守商店自动更新的机器上长期保持已暂挂状态。 打开 App Store 窗口本身不会自动解除保护,因为窗口是否打开不能可靠判断后台下载是否结束。
程序异常退出后 LaunchAgent 会尝试重启;暂停记录用于继续管理同一个进程。关闭恢复失败时保留记录,后续检查可重试恢复。机器重启后旧 PID/启动时间不匹配时不会恢复错误的进程,而是重新检测。
菜单栏「卸载 ArcadeGuard…」,或:
bash scripts/uninstall.sh会关闭保护、恢复本工具暂停的进程,并移除应用和 LaunchAgent。状态及有限长度的事件日志保留在 ~/Library/Application Support/ArcadeGuard/,便于排查;确认无需保留后可手动删除。
如果应用被手动删除,先重新安装再卸载。若状态损坏导致恢复工具无法运行,可以先在系统设置中关闭该工具的登录/后台运行,退出工具,再自行确认是否需要 pkill -CONT -x appstoreagent。该应急命令无法区分是哪个工具暂停的进程,因此不作为自动恢复方式。
- 不上传日志、没有遥测、没有联网检测或自动更新。
- 不修改系统文件、不搬移 PowerLog 数据库、不关闭 SIP、不禁用系统守护服务。
- 只有 CPU 持续偏高时才读取针对性日志;临时原始输出会删除,事件记录不复制系统日志正文。
- 持久化文件仅位于用户的
Applications、Library/LaunchAgents和Library/Application Support/ArcadeGuard。 - 本地构建使用 ad-hoc 签名,没有 Apple Developer ID 公证。
swift test
bash scripts/build.sh核心状态机使用可替换的系统接口,测试涵盖持续 CPU 与日志双重条件、短暂尖峰、其他任务、休眠/时钟跳变、日志失败、写入失败、PID 复用、外部暂停、恢复失败重试以及关闭状态持久化顺序。
真实运行验证与已知限制见 VALIDATION.md。系统升级后建议关闭保护,观察问题是否已经修复。
本项目来自一次 ArcadeResetPO 将任务安排到已经过去的时间、完成后重新提交的本地故障。观察到 dasd 约占一个 CPU 核心;暂挂上游 appstoreagent 后 CPU 降到接近零。
相关社区资料:
- appstoreagent-watchdog:以高 CPU 阈值触发结束/重启进程的另一种方案。本项目采用按需暂挂与显式恢复,代码独立实现。
- macOS 27 Arcade 调度问题记录:报告者记录了 Apple Feedback
FB23413997。其中是ArcadePostSummary被拒后重试,与本项目的ArcadeResetPO症状不完全相同,不能认定是同一根因。
MIT License。与 Apple 无隶属关系。