Skip to content

Commit 3171b27

Browse files
committed
fix: restart macOS input method after upgrades
1 parent 0e27ae2 commit 3171b27

6 files changed

Lines changed: 106 additions & 1 deletion

File tree

.github/release-notes/v5.0.8.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# VoCoType-linux v5.0.8
2+
3+
VoCoType-linux v5.0.8 是 V5 稳定线的 macOS 输入法更新可靠性热修复版本。它修复了更新后旧 InputMethod 进程可能继续驻留、导致麦克风 TCC 身份与磁盘中新 bundle 不一致的问题。
4+
5+
发布日期:2026-09-12。
6+
7+
## 修复
8+
9+
- **更新前先禁用旧输入源**:DMG 安装脚本在替换 `~/Library/Input Methods/VoCoType-linux.app` 前先禁用旧 VoCoType 输入源,再终止旧 InputMethod 和录音相关进程,避免 InputMethodKit 在文件复制过程中自动重新拉起旧进程。
10+
- **最终安装后强制建立新的进程边界**:新 bundle 完整复制、LaunchServices 注册和输入源安装完成后,再终止一次 InputMethod 并重新激活,确保最终常驻进程一定从最终安装、最终签名的 bundle 启动。
11+
- **Settings App 自动更新采用同样策略**:嵌入式 InputMethod 更新完成并激活后,也会做最终进程重启,DMG 安装与应用内更新行为保持一致。
12+
- **保留 v5.0.7 的录音启动 watchdog**:本次没有放宽或移除 CoreAudio 5 秒启动保护;现场验证表明当前问题不是 watchdog 阈值,而是更新后遗留的进程身份错位。
13+
14+
## 真机证据
15+
16+
受影响机器上,磁盘中的 `VoCoType-linux.app` 能通过 `codesign --verify --deep --strict`,但常驻 InputMethod 进程仍是前一天更新前启动的旧进程。真实 F9 录音时,TCC 日志出现:
17+
18+
`IDENTITY_ATTRIBUTION: Failed to copy signing info ... -67034`
19+
20+
这意味着负责麦克风访问的常驻 InputMethod 进程与当前磁盘 bundle 的签名身份无法正常对应。
21+
22+
终止旧 InputMethod 并从当前已签名 bundle 重新激活后:
23+
24+
- 新 InputMethod PID 启动;
25+
- 后续真实 F9 第一块音频分别约 145 ms / 144 ms 到达;
26+
- WAV 在松手后约 134–135 ms 完成;
27+
- 最终 ASR 正常完成并成功上屏;
28+
- 新 PID 的录音路径不再出现上述 `IDENTITY_ATTRIBUTION -67034`
29+
30+
验证结果:
31+
32+
- macOS CTest:10/10 PASS;
33+
- native source contracts:PASS;
34+
- `packaging/macos/install.command` shell syntax:PASS。
35+
36+
## 下载资产
37+
38+
- macOS Apple Silicon:`VoCoType-linux-5.0.8-macOS-arm64.dmg`
39+
- Debian / Ubuntu:Universal、IBus-only、Fcitx5-only;
40+
- Fedora / RHEL:Universal、IBus-only、Fcitx5-only;
41+
- Arch Linux:Universal、IBus-only、Fcitx5-only;
42+
- 所有安装资产统一提供 `SHA256SUMS`
43+
44+
**Full Changelog**: https://github.com/LeonardNJU/VocoType-linux/compare/v5.0.7...v5.0.8

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [5.0.8] - 2026-09-12
11+
12+
### Fixed
13+
14+
- macOS upgrades now disable the old input source before replacing its bundle and force a final InputMethod process restart only after the new bundle is fully installed and registered. This prevents a stale in-memory input-method executable from remaining responsible for a newly signed on-disk bundle, which can make TCC microphone identity attribution fail intermittently even though the replacement bundle passes `codesign` verification.
15+
- The Settings App embedded-input-method updater now enforces the same final process boundary after activation, so both DMG installs and in-app upgrades converge on a fresh process loaded from the final installed bundle.
16+
1017
## [5.0.7] - 2026-09-11
1118

1219
### Fixed

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
5.0.7
1+
5.0.8

packaging/macos/install.command

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@ if [[ ! -d "$SOURCE_INPUT" || ! -d "$SOURCE_SETTINGS" ]]; then
1515
fi
1616

1717
mkdir -p "$HOME/Library/Input Methods" "$HOME/Applications"
18+
# Disable the old source before touching its bundle. InputMethodKit may
19+
# otherwise relaunch a killed input-method process while ditto is replacing
20+
# the app, leaving an old in-memory executable responsible for a newly signed
21+
# on-disk bundle. TCC then cannot reliably attribute microphone access.
22+
OLD_TOOL="$INPUT_DESTINATION/Contents/Resources/bin/vocotype-input-source-tool"
23+
if [[ -x "$OLD_TOOL" ]]; then
24+
"$OLD_TOOL" --disable "$IDENTIFIER" >/dev/null 2>&1 || true
25+
fi
1826
pkill -f "$INPUT_DESTINATION/Contents/MacOS/VoCoTypeLinuxInputMethod" 2>/dev/null || true
1927
pkill -f "$SETTINGS_DESTINATION/Contents/MacOS/VoCoTypeLinuxSettings" 2>/dev/null || true
2028
for runtime in vocotype-audio-recorder vocotype-core vocotype-streaming-worker vocotype-offline-worker; do
@@ -40,6 +48,12 @@ fi
4048

4149
TOOL="$INPUT_DESTINATION/Contents/Resources/bin/vocotype-input-source-tool"
4250
"$TOOL" --install "$INPUT_DESTINATION" "$IDENTIFIER"
51+
# Establish a process boundary after the final bundle bytes are installed and
52+
# registered. Even if macOS launched the input method during registration,
53+
# the surviving process must come from the final signed bundle on disk.
54+
pkill -f "$INPUT_DESTINATION/Contents/MacOS/VoCoTypeLinuxInputMethod" 2>/dev/null || true
55+
sleep 0.2
56+
"$TOOL" --activate "$IDENTIFIER"
4357
open "$SETTINGS_DESTINATION" --args --settings-page 1 2>/dev/null || true
4458

4559
cat <<'MESSAGE'

scripts/test/contracts.sh

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,23 @@ rg -Fq 'prewarm_offline_asr(socket, config, asr_lease)' src/integrations/macos/V
239239
fail "macOS does not prewarm final ASR at recording start"
240240
rg -Fq 'wait_for_asr_prepare(asr_lease' src/integrations/macos/VocoTypeInputController.mm || \
241241
fail "macOS final ASR does not wait for recording-time preparation"
242+
mac_install=packaging/macos/install.command
243+
rg -Fq '"$OLD_TOOL" --disable "$IDENTIFIER"' "$mac_install" || \
244+
fail "macOS installer does not disable the old input source before replacement"
245+
mac_copy_line=$(grep -nF 'ditto "$SOURCE_INPUT" "$INPUT_DESTINATION"' "$mac_install" | head -1 | cut -d: -f1)
246+
mac_final_kill_line=$(grep -nF 'pkill -f "$INPUT_DESTINATION/Contents/MacOS/VoCoTypeLinuxInputMethod"' "$mac_install" | tail -1 | cut -d: -f1)
247+
mac_final_activate_line=$(grep -nF '"$TOOL" --activate "$IDENTIFIER"' "$mac_install" | tail -1 | cut -d: -f1)
248+
if [[ -z "$mac_copy_line" || -z "$mac_final_kill_line" || -z "$mac_final_activate_line" ]] || \
249+
(( mac_final_kill_line <= mac_copy_line || mac_final_activate_line <= mac_final_kill_line )); then
250+
fail "macOS installer does not force a fresh InputMethod process after the final bundle is installed"
251+
fi
252+
for token in \
253+
'Contents/MacOS/VoCoTypeLinuxInputMethod' \
254+
'(void)run_task(@"/usr/bin/pkill", @[ @"-f", inputExecutable ], nil);' \
255+
'输入法组件已安装,但最终进程重启失败'; do
256+
rg -Fq "$token" src/integrations/macos/VocoTypeRuntime.mm || \
257+
fail "macOS in-app upgrade does not enforce a final InputMethod process restart: $token"
258+
done
242259
for service in scripts/install/common/install-native-user.sh \
243260
packaging/common/systemd/vocotype-fcitx5-backend.service; do
244261
rg -Fq 'Restart=always' "$service" || \

src/integrations/macos/VocoTypeRuntime.mm

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,29 @@ BOOL VocoTypeEnsureEmbeddedInputMethod(NSString **errorMessage) {
237237
toolOutput.length > 0 ? toolOutput : @"未知错误"];
238238
return NO;
239239
}
240+
241+
// TIS/InputMethodKit may start the input-method process as soon as the
242+
// source is registered. Force one process boundary after the final bundle
243+
// is fully in place so the process responsible for microphone access is
244+
// guaranteed to match the final on-disk code signature. A stale process
245+
// from an earlier bundle can make TCC identity attribution fail even though
246+
// codesign verification of the replacement bundle succeeds.
247+
NSString *inputExecutable = [destination stringByAppendingPathComponent:
248+
@"Contents/MacOS/VoCoTypeLinuxInputMethod"];
249+
(void)run_task(@"/usr/bin/pkill", @[ @"-f", inputExecutable ], nil);
250+
[NSThread sleepForTimeInterval:0.2];
251+
activated = run_task(
252+
tool,
253+
@[ @"--activate",
254+
@"io.github.LeonardNJU.VoCoTypeLinux.InputMethod" ],
255+
&toolOutput);
256+
if (!activated) {
257+
if (errorMessage)
258+
*errorMessage = [NSString stringWithFormat:
259+
@"输入法组件已安装,但最终进程重启失败。\n\n%@",
260+
toolOutput.length > 0 ? toolOutput : @"未知错误"];
261+
return NO;
262+
}
240263
return YES;
241264
}
242265

0 commit comments

Comments
 (0)