From 302e43f184d2448c6774b85605e0ad85f5b66190 Mon Sep 17 00:00:00 2001 From: qiyinxi Date: Mon, 9 Nov 2026 16:55:19 +0100 Subject: [PATCH 1/3] =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E9=87=8C=E7=9A=84?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E8=AF=B4=E6=98=8E=E7=85=A7=E5=AE=9E=E5=86=99?= =?UTF-8?q?=EF=BC=9AAUTO-MAS=20=E7=94=A8=E8=87=AA=E5=B7=B1=E7=9A=84?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=99=A8=E5=92=8C=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 原文说 AUTO-MAS 调用 modavd update、按这里的更新源和 CDK 下载,两处都不对: AUTO-MAS 到 v5.8.0 还是用自己的更新器,更新源和 CDK 读它自己的设置。 改成写清这里只能检查新版本、用和不用 AUTO-MAS 各自怎么更新、这里的设置 管什么。按钮照旧不可用。 --- internal/ui/web/js/update.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/internal/ui/web/js/update.js b/internal/ui/web/js/update.js index 9404380..9c83936 100644 --- a/internal/ui/web/js/update.js +++ b/internal/ui/web/js/update.js @@ -1,6 +1,7 @@ // 设置 → ModAVD 更新 (API.md "更新"): version and update state of this root, the update source and the Mirror 酱 CDK, -// a check on request. Installing is not offered here yet (AUTO-MAS installs, through `modavd update`, with these -// settings); the button is shown and disabled. +// a check on request. Installing is not offered here yet: AUTO-MAS still updates with its own updater, source and +// CDK, and the two updaters share no lock; the button is shown and disabled. These settings are used by the check +// and by `modavd update`. import { h, icon, btn, attr, setText, showError } from './dom.js'; import { S, update, subscribe } from './store.js'; @@ -87,12 +88,12 @@ export function openUpdate() { h('div', { class: 'f-ctl' }, h('div', { class: 'upd-cdk' }, cdk, save, clear), cdkState), h('label', { class: 'f-label', for: 'upd-comp', text: '组件下载源' }), h('div', { class: 'f-ctl' }, componentSource, componentURLsRow, h('p', { class: 'f-hint', text: '「补全组件」和 modavd components fetch 都从这里选的源下载;选了就保存。' }))); - const note = h('p', { class: 'f-hint', text: '更新现在由 AUTO-MAS 发起(它调用 modavd update),会按这里选的更新源和 CDK 下载;这里先不能直接更新。' }); + const note = h('p', { class: 'f-hint', text: '这里暂时只能检查新版本。用 AUTO-MAS 的,在 AUTO-MAS 里更新(它用 AUTO-MAS 设置里的更新源和 CDK);不用 AUTO-MAS 的,关掉所有实例和管理器,把新版整包覆盖解压到这个文件夹,avd 文件夹不会被动到。这里的更新源和 CDK 只用于「检查更新」和命令行 modavd update。' }); const diagBtn = btn('btn btn-secondary', [icon('shield'), '组件与问题反馈'], () => { ctl.close(); openDiagnostics(); }); const when = h('span', { class: 'foot-note' }); const checkBtn = btn('btn btn-secondary', null, () => run(api.post('/api/update/check'))); const installBtn = btn('btn btn-primary', [icon('download'), '更新'], null, - { disabled: true, 'aria-disabled': 'true', title: '暂时由 AUTO-MAS 发起更新' }); + { disabled: true, 'aria-disabled': 'true', title: '这里暂时不能直接更新' }); for (const r of radios) r.addEventListener('change', () => r.checked && post({ source: r.value }, r.value === 'github' ? '改用 GitHub 更新' : '改用 Mirror 酱更新')); ctl = openDialog({ From 240e74370fcd43e7464003eb25a99cdd0d0d2190 Mon Sep 17 00:00:00 2001 From: qiyinxi Date: Mon, 9 Nov 2026 17:05:33 +0100 Subject: [PATCH 2/3] =?UTF-8?q?=E4=B8=8D=E5=86=8D=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E9=83=BD=E7=94=A8=20AUTO-MAS=EF=BC=9A?= =?UTF-8?q?=E8=A1=A5=E5=85=A8=E7=BB=84=E4=BB=B6=E3=80=81=E9=97=AE=E9=A2=98?= =?UTF-8?q?=E5=8C=85=E5=92=8C=E9=85=8D=E7=BD=AE=E4=BF=A1=E6=81=AF=E7=9A=84?= =?UTF-8?q?=E6=96=87=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 补全组件完成:先说可以新建实例了,再说用 AUTO-MAS 的可以去添加。 - 问题包没找到 AUTO-MAS:只请用 AUTO-MAS 的附上它的日志,不用的不用管 (管理器、命令行、summary.txt 三处);隐私说明里 AUTO-MAS 日志写成 找到它时才有;qemu 命令行读不到时不再说多半是 AUTO-MAS 以管理员运行。 - 复制配置信息:「AUTO-MAS 版本」「用的脚本」两行并成「怎么用的 (自己玩 / AUTO-MAS 及版本 / MAA、M9A 等脚本)」;没开实例时不再叫人 在 AUTO-MAS 里开着实例再双击运行。 - portBase 的建议写「默认值」,不写「和 AUTO-MAS 一样」;换包恢复失败的 提示先说下次更新时恢复。 对照旧脚本输出的测试照原来的做法,把这些有意改动的行列进对照表,基准文件不动。 --- internal/cli/commands.go | 2 +- internal/cli/components_test.go | 2 +- internal/cli/format.go | 2 +- internal/cli/report_test.go | 3 ++ internal/components/fetch.go | 4 +-- internal/components/fetch_windows_test.go | 2 +- internal/report/collect.go | 8 ++--- internal/report/config.go | 6 ++-- internal/report/parity_windows_test.go | 40 +++++++++++++++++++---- internal/report/report.go | 13 +++++--- internal/root/root.go | 2 +- internal/ui/web/js/diagnostics.js | 2 +- internal/update/swap.go | 2 +- 13 files changed, 62 insertions(+), 26 deletions(-) diff --git a/internal/cli/commands.go b/internal/cli/commands.go index c1c25ed..89441b5 100644 --- a/internal/cli/commands.go +++ b/internal/cli/commands.go @@ -933,7 +933,7 @@ func humanCollectInfo(w io.Writer, data any) { fmt.Fprintln(w, l) } if !r.MasFound { - fmt.Fprintln(w, "没找到 AUTO-MAS 安装目录,反馈时请附上 AUTO-MAS 的 debug 文件夹里的日志") + fmt.Fprintln(w, report.MasMissingNote) } if len(r.Problems) > 0 { fmt.Fprintf(w, "有 %d 节没收集成功,原因写在 zip 里的 summary.txt,照样提交就行。\n", len(r.Problems)) diff --git a/internal/cli/components_test.go b/internal/cli/components_test.go index 050aa35..4725106 100644 --- a/internal/cli/components_test.go +++ b/internal/cli/components_test.go @@ -186,7 +186,7 @@ func TestComponentsFetchOptions(t *testing.T) { t.Fatalf("quiet: %q", res.stderr) } if !strings.Contains(res.stdout, "已装好:平台工具(adb)(版本 37.0.1)") || !strings.Contains(res.stdout, "原来不完整的目录改名为") || - !strings.Contains(res.stdout, "完成,可以在 AUTO-MAS 里添加这个文件夹了。") { + !strings.Contains(res.stdout, "完成,可以新建实例了;用 AUTO-MAS 的,也可以在 AUTO-MAS 里添加这个文件夹了。") { t.Fatalf("summary %q", res.stdout) } } diff --git a/internal/cli/format.go b/internal/cli/format.go index 6d9914a..e6c4768 100644 --- a/internal/cli/format.go +++ b/internal/cli/format.go @@ -602,7 +602,7 @@ func formatComponents(w io.Writer, data any) { if !fetched { fmt.Fprint(w, "组件都已齐全,不需要下载。") } - fmt.Fprintln(w, "完成,可以在 AUTO-MAS 里添加这个文件夹了。") + fmt.Fprintln(w, "完成,可以新建实例了;用 AUTO-MAS 的,也可以在 AUTO-MAS 里添加这个文件夹了。") } } diff --git a/internal/cli/report_test.go b/internal/cli/report_test.go index 603c587..7324fb1 100644 --- a/internal/cli/report_test.go +++ b/internal/cli/report_test.go @@ -54,6 +54,9 @@ func TestHumanCollectInfoMatchesScript(t *testing.T) { t.Fatalf("%s: the script's privacy note head not found once", c.name) } want = strings.Replace(want, scriptPrivacyHead+"\n", head+"\n", 1) + // and for what the script said as if every user had AUTO-MAS (report's notAllMAS) + want = strings.Replace(want, "实例配置、AUTO-MAS 日志(mas 文件夹);", "实例配置;找到 AUTO-MAS 时还有它的日志(mas 文件夹);", 1) + want = strings.Replace(want, "没找到 AUTO-MAS 安装目录,反馈时请附上 AUTO-MAS 的 debug 文件夹里的日志\n", report.MasMissingNote+"\n", 1) res := &report.CollectResult{ ZipPath: `{{BASE}}\out\魔改AVD问题信息-20260115-120000.zip`, ZipSize: "{{SIZE}}", PrivacyNote: report.PrivacyNote, MasFound: c.mas, Problems: c.problems, diff --git a/internal/components/fetch.go b/internal/components/fetch.go index f4f0864..3ea6a9a 100644 --- a/internal/components/fetch.go +++ b/internal/components/fetch.go @@ -459,7 +459,7 @@ func (f *fetcher) run(ctx context.Context) (res *Result, err error) { if f.darwin() { f.say("组件都已齐全,不需要下载。当前 macOS 版本暂未开放实例创建与启动。") } else { - f.say("组件都已齐全,不需要下载。完成,可以在 AUTO-MAS 里添加这个文件夹了。") + f.say("组件都已齐全,不需要下载。完成,可以新建实例了;用 AUTO-MAS 的,也可以在 AUTO-MAS 里添加这个文件夹了。") } return res, nil } @@ -534,7 +534,7 @@ func (f *fetcher) run(ctx context.Context) (res *Result, err error) { if f.darwin() { f.say("组件补全完成。当前 macOS 版本暂未开放实例创建与启动。") } else { - f.say("完成,可以在 AUTO-MAS 里添加这个文件夹了。") + f.say("完成,可以新建实例了;用 AUTO-MAS 的,也可以在 AUTO-MAS 里添加这个文件夹了。") } return res, nil } diff --git a/internal/components/fetch_windows_test.go b/internal/components/fetch_windows_test.go index 08058da..3cec353 100644 --- a/internal/components/fetch_windows_test.go +++ b/internal/components/fetch_windows_test.go @@ -471,7 +471,7 @@ func TestFetchInstallsThenSkips(t *testing.T) { t.Errorf("the download source line is not before the license:\n%s", logged) } for _, s := range []string{"参数:AcceptLicense=true", " URL " + m.url() + "pt.zip", "下载结束:", "退出码 0", - "完成,可以在 AUTO-MAS 里添加这个文件夹了。"} { + "完成,可以新建实例了;用 AUTO-MAS 的,也可以在 AUTO-MAS 里添加这个文件夹了。"} { if !strings.Contains(logged, s) { t.Errorf("log lacks %q:\n%s", s, logged) } diff --git a/internal/report/collect.go b/internal/report/collect.go index cdb35b2..d7e84e8 100644 --- a/internal/report/collect.go +++ b/internal/report/collect.go @@ -293,7 +293,7 @@ func collect(ctx context.Context, rootDir string, h Host, opt CollectOptions) (r } if !c.masFound { c.L("") - c.L("提示:没找到 AUTO-MAS 安装目录,反馈时请附上 AUTO-MAS 的 debug 文件夹里的日志。") + c.L("提示:" + MasMissingNote) } res := &CollectResult{Stage: stage, Problems: append([]string{}, c.problems...), MasFound: c.masFound, @@ -747,7 +747,7 @@ func (c *collector) runningAndAdb() error { c.L(fmt.Sprintf("pid %d 启动于 %s", q.PID, ct)) cmd := q.CommandLine if cmd == "" { - c.L(" qemu 命令行读不到(多半是 AUTO-MAS 以管理员运行),现场按 adb 设备列表推算") + c.L(" qemu 命令行读不到(多半是模拟器以管理员身份运行),现场按 adb 设备列表推算") c.cmdlineUnreadable = true continue } @@ -1458,7 +1458,7 @@ func (c *collector) autoMAS() error { } } if loc == "" { - c.L("没找到 AUTO-MAS 安装目录,反馈时请附上 AUTO-MAS 的 debug 文件夹里的日志") + c.L("没找到 AUTO-MAS 安装目录(不用 AUTO-MAS 的不用管)") return nil } c.masFound = true @@ -1608,7 +1608,7 @@ func (c *collector) live() error { targets := append([]liveTarget(nil), c.running...) if c.cmdlineUnreadable { // fallback: the emulator- serials of the device list, mapped to instance names with the port plan - c.L("qemu 命令行读不到(多半是 AUTO-MAS 以管理员运行),现场按 adb 设备列表推算") + c.L("qemu 命令行读不到(多半是模拟器以管理员身份运行),现场按 adb 设备列表推算") res := c.adbDevicesCommand() if res.TimedOut { c.L(" adb devices:超时(20 秒),已放弃") diff --git a/internal/report/config.go b/internal/report/config.go index 4f24d4e..0592e90 100644 --- a/internal/report/config.go +++ b/internal/report/config.go @@ -46,13 +46,13 @@ func GameName(pkg string) (string, bool) { var notGames = []string{"de.jrpie.android.launcher"} // The lines the user fills in. -var configTail = []string{"AUTO-MAS 版本:", "用的脚本(MAA / M9A / …):", "效果(能跑 / 有问题,问题是…):"} +var configTail = []string{"怎么用的(自己玩 / AUTO-MAS 及版本 / MAA、M9A 等脚本):", "效果(能跑 / 有问题,问题是…):"} const ( configTitle = "【魔改 AVD 试用配置】" - configNotOpen = "游戏包:没有实例开着,读不到。在 AUTO-MAS 里开着实例时再双击运行一次,就会列出来" + configNotOpen = "游戏包:没有实例开着,读不到。开着实例时再生成一次,就会列出来" emuCheckWait = 20 * time.Second - clipboardOK = "已复制到剪贴板:粘贴到群里,再把最后三行补上就行。" + clipboardOK = "已复制到剪贴板:粘贴到群里,再把最后两行补上就行。" clipboardError = "复制到剪贴板失败(%s),请手动选中上面的文字复制。" ) diff --git a/internal/report/parity_windows_test.go b/internal/report/parity_windows_test.go index 7dff44f..53082a7 100644 --- a/internal/report/parity_windows_test.go +++ b/internal/report/parity_windows_test.go @@ -161,11 +161,23 @@ func modavdPrivacyHead() string { return head } +// notAllMAS: what the scripts said as if every user had AUTO-MAS, and what modavd says instead (many use ModAVD +// without it). Applied in order, to the scripts' lines. +var notAllMAS = []struct{ script, modavd string }{ + {"提示:没找到 AUTO-MAS 安装目录,反馈时请附上 AUTO-MAS 的 debug 文件夹里的日志。", "提示:" + MasMissingNote}, + {"没找到 AUTO-MAS 安装目录,反馈时请附上 AUTO-MAS 的 debug 文件夹里的日志", "没找到 AUTO-MAS 安装目录(不用 AUTO-MAS 的不用管)"}, + {"(多半是 AUTO-MAS 以管理员运行)", "(多半是模拟器以管理员身份运行)"}, + {"实例配置、AUTO-MAS 日志(mas 文件夹);", "实例配置;找到 AUTO-MAS 时还有它的日志(mas 文件夹);"}, + {"在 AUTO-MAS 里开着实例时再双击运行一次", "开着实例时再生成一次"}, + {"再把最后三行补上就行。", "再把最后两行补上就行。"}, +} + // modavdLine is what modavd writes on purpose instead of a line of collect-info.ps1's summary.txt: // - the PowerShell that ran the script: modavd's version and Go version; // - the adb.exe the live section runs: modavd speaks the adb host protocol itself (no adb.exe, never a server of // its own), to the server that listens on the port; -// - the first line of the privacy note: who does not upload is the manager or the CLI, not a script. +// - the first line of the privacy note: who does not upload is the manager or the CLI, not a script; +// - notAllMAS. func (f *fixture) modavdLine(line string) string { if line == "PowerShell:{{PSVERSION}}" { return "modavd:" + buildinfo.Version + "(" + runtime.Version() + ")" @@ -173,6 +185,9 @@ func (f *fixture) modavdLine(line string) string { if line == scriptPrivacyHead { return modavdPrivacyHead() } + for _, r := range notAllMAS { + line = strings.Replace(line, r.script, r.modavd, 1) + } if strings.HasPrefix(line, "adb:") && strings.Contains(line, " -P "+strconv.Itoa(f.adbPort)+"(") { var pid uint32 for _, l := range f.sc.Listeners { @@ -366,14 +381,17 @@ func TestCollectMatchesScript(t *testing.T) { } } - // the end of the console output: zip path, the privacy note word for word but for its first line + // the end of the console output: zip path, the privacy note word for word but for modavdLine's console, _ := f.golden(t, name, "collect-console.txt") if !containsLine(lines(console), "文件:"+res.ZipPath) { t.Errorf("zip %s, the script printed:\n%s", res.ZipPath, console) } - scriptNote := scriptPrivacyHead + strings.TrimPrefix(PrivacyNote, modavdPrivacyHead()) - if !strings.Contains(console, scriptNote) || res.PrivacyNote != PrivacyNote { - t.Error("the privacy note is not the one collect-info.ps1 prints, but for its first line") + var consoleLines []string + for _, l := range lines(console) { + consoleLines = append(consoleLines, f.modavdLine(l)) + } + if !strings.Contains(strings.Join(consoleLines, "\r\n"), PrivacyNote) || res.PrivacyNote != PrivacyNote { + t.Error("the privacy note is not the one collect-info.ps1 prints, but for modavdLine's") } if strings.Contains(PrivacyNote, "脚本") || !strings.HasPrefix(PrivacyNote, "隐私提示:问题包只保存在本机,") { t.Errorf("privacy note head %q", modavdPrivacyHead()) @@ -407,7 +425,17 @@ func TestReportConfigMatchesScript(t *testing.T) { } // the script prints a blank line, the lines, a blank line and what happened to the clipboard want, _ := f.golden(t, name, "report-config.txt") - wl := lines(want) + var wl []string + for _, l := range lines(want) { + // the script asked for the AUTO-MAS version and the scripts on two lines; modavd asks how it is used + if l == "用的脚本(MAA / M9A / …):" { + continue + } + if l == "AUTO-MAS 版本:" { + l = configTail[0] + } + wl = append(wl, f.modavdLine(l)) + } if len(wl) < 3 || wl[0] != "" || wl[len(wl)-2] != "" { t.Fatalf("unexpected golden shape: %q", wl) } diff --git a/internal/report/report.go b/internal/report/report.go index 07b55e1..0993c32 100644 --- a/internal/report/report.go +++ b/internal/report/report.go @@ -28,15 +28,20 @@ import ( "modavd/internal/root" ) -// PrivacyNote is the head of summary.txt and the last thing printed: collect-info.ps1's $PrivacyNote word for word, -// but for the first line. The script's said "脚本不会上传"; from ModAVD 0.38.2 the package has no such script any -// more (ModAVD/ModAVD#45), and what collects and what could upload is the manager or the CLI, so it says those. +// PrivacyNote is the head of summary.txt and the last thing printed: collect-info.ps1's $PrivacyNote, but for the +// first line and the AUTO-MAS logs. The script's said "脚本不会上传"; from ModAVD 0.38.2 the package has no such +// script any more (ModAVD/ModAVD#45), and what collects and what could upload is the manager or the CLI, so it says +// those. The script listed the AUTO-MAS logs as if every user had AUTO-MAS; they are there only when it is found. const PrivacyNote = "隐私提示:问题包只保存在本机,管理器和命令行都不会上传它。\r\n" + - "- 里面有:summary.txt(电脑和模拟器的情况)、模拟器日志、实例配置、AUTO-MAS 日志(mas 文件夹);有实例在运行时还有现场截图和安卓状态(live 文件夹);模拟器近 7 天崩溃过的话还有崩溃转储(crash 文件夹)。不收磁盘镜像,不收 AUTO-MAS 的配置和账号数据,也不会有意收集账号密码。\r\n" + + "- 里面有:summary.txt(电脑和模拟器的情况)、模拟器日志、实例配置;找到 AUTO-MAS 时还有它的日志(mas 文件夹);有实例在运行时还有现场截图和安卓状态(live 文件夹);模拟器近 7 天崩溃过的话还有崩溃转储(crash 文件夹)。不收磁盘镜像,不收 AUTO-MAS 的配置和账号数据,也不会有意收集账号密码。\r\n" + "- 这些文件里都有本机路径,路径里可能有 Windows 用户名;截图和 AUTO-MAS 日志里可能有游戏账号名。\r\n" + "- 可以公开:在 GitHub Issue(https://github.com/ModAVD/ModAVD/issues)里贴 summary.txt 和日志,或者上传删掉 crash 文件夹后的问题包。上传前看一眼,不想公开的内容先删掉。\r\n" + "- 不要公开:crash 文件夹(崩溃转储,含模拟器进程的线程栈和少量内存片段)。带 crash 文件夹的完整问题包请发邮件到 qiyinxi@foxmail.com,邮件里写上 Issue 编号。" +// MasMissingNote: shown after collecting when no AUTO-MAS installation was found. Many users do not use AUTO-MAS, so +// it asks only those who do for its logs. +const MasMissingNote = "没找到 AUTO-MAS 安装目录。用 AUTO-MAS 的,反馈时请另附上它 debug 文件夹里的日志;不用 AUTO-MAS 的不用管。" + // ---- .NET number formatting -------------------------------------------------------------------------------------- // formatN is '{0:N}' -f v of Windows PowerShell 5.1 (.NET Framework, en-US / zh-CN): the double cut to 15 diff --git a/internal/root/root.go b/internal/root/root.go index e90e05f..3b8e21c 100644 --- a/internal/root/root.go +++ b/internal/root/root.go @@ -162,7 +162,7 @@ func (r *Root) checkPorts(allowLegacy bool) *errs.Error { legacy := p.Base == 5500 || p.Base > maxPortBase if problem != "" && !(allowLegacy && legacy) { return errs.New(errs.InvalidArgument, problem).WithAdvice(fmt.Sprintf( - "先关掉这个根目录的所有实例,再把 portBase 改成 %d(和 AUTO-MAS 一样),或者 %d–%d 之间 100 的整数倍,避开 5500(开发和测试用的根目录用 21000);原配置仍可查状态和关机", + "先关掉这个根目录的所有实例,再把 portBase 改成 %d(默认值),或者 %d–%d 之间 100 的整数倍,避开 5500(开发和测试用的根目录用 21000);原配置仍可查状态和关机", DefaultPortBase, minPortBase, maxPortBase)) } if p.Base == DefaultPortBase { diff --git a/internal/ui/web/js/diagnostics.js b/internal/ui/web/js/diagnostics.js index d7bf663..b333872 100644 --- a/internal/ui/web/js/diagnostics.js +++ b/internal/ui/web/js/diagnostics.js @@ -391,7 +391,7 @@ function collectRows(j) { () => api.post('/api/open', { what: 'collect-info', job: j.id }).catch(toastError)))]; if (r.sections?.length) rows.push(h('ul', { class: 'diag-sections' }, ...r.sections.map((x) => h('li', { class: x.error ? 'tone-err' : 'tone-ok', text: `${x.name}:${x.error || '完成'}` })))); else if (r.problems?.length) rows.push(h('p', { class: 'f-hint', text: `有 ${r.problems.length} 节没收集成功,原因写在包里的 summary.txt,照样提交就行。` })); - if (r.mas_found === false) rows.push(h('p', { class: 'f-hint', text: '没找到 AUTO-MAS 安装目录,反馈时请附上 AUTO-MAS 的 debug 文件夹里的日志。' })); + if (r.mas_found === false) rows.push(h('p', { class: 'f-hint', text: '没找到 AUTO-MAS 安装目录。用 AUTO-MAS 的,反馈时请另附上它 debug 文件夹里的日志;不用 AUTO-MAS 的不用管。' })); return rows; } diff --git a/internal/update/swap.go b/internal/update/swap.go index a947cf3..c39c2fe 100644 --- a/internal/update/swap.go +++ b/internal/update/swap.go @@ -361,7 +361,7 @@ func (u *Updater) recoverAfter(err error) error { msg, rerr := u.recoverState() switch { case rerr != nil: - msg = fmt.Sprintf("当场恢复也失败了(%v),下次更新或 AUTO-MAS 启动时会再按记录恢复", rerr) + msg = fmt.Sprintf("当场恢复也失败了(%v),下次更新时会再按记录恢复(用 AUTO-MAS 的,它启动时也会)", rerr) case msg == "": msg = "状态已经完整" } From 67b6abf7bdc4f7af8b8d0be84ee729ce99b4d236 Mon Sep 17 00:00:00 2001 From: qiyinxi Date: Mon, 9 Nov 2026 17:14:57 +0100 Subject: [PATCH 3/3] =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E9=87=8C=E7=BB=9F?= =?UTF-8?q?=E4=B8=80=E5=8F=AB=20ModAVD=EF=BC=8C=E4=B8=8D=E5=86=8D=E7=94=A8?= =?UTF-8?q?=E3=80=8C=E9=AD=94=E6=94=B9=20AVD=E3=80=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 所有语言都只用 ModAVD 这个名字:日志、报错、命令行帮助、问题包和配置信息的 标题都换掉,问题包文件名改成 ModAVD-问题信息-<时间>.zip。和中文相邻时加空格。 AUTO-MAS 只看错误码,不看消息文字,改名不影响对接。对照旧脚本输出的测试把 旧名字列进有意改动的对照表;对照 AUTO-MAS 原逻辑的 Python 参考和 jsonord 的 样例跟着换了文字,pycases.json 用 gen_pycases.py 重新生成。 --- README.en.md | 2 +- README.md | 4 +-- cmd/modavd-gui/main.go | 4 +-- internal/adb/adb.go | 6 ++-- internal/adb/adb_test.go | 4 +-- internal/adb/real_adb_test.go | 6 ++-- internal/avd/avd.go | 12 ++++---- internal/avd/avd_test.go | 14 ++++----- internal/avd/testdata/instances_ref.py | 8 ++--- internal/cli/commands.go | 8 ++--- internal/cli/format.go | 2 +- internal/cli/report_test.go | 5 ++-- internal/components/fetch.go | 6 ++-- internal/components/playstore.go | 6 ++-- internal/emu/adbcmd.go | 2 +- internal/emu/bootdiag_windows_test.go | 2 +- internal/emu/bridge.go | 6 ++-- internal/emu/check.go | 22 +++++++------- internal/emu/check_darwin.go | 2 +- internal/emu/check_test.go | 6 ++-- internal/emu/createinit.go | 8 ++--- internal/emu/crud.go | 22 +++++++------- internal/emu/crud_test.go | 2 +- internal/emu/disk.go | 16 +++++----- internal/emu/disk_lock.go | 2 +- internal/emu/firstboot.go | 10 +++---- internal/emu/install.go | 8 ++--- internal/emu/launch.go | 10 +++---- internal/emu/launch_test.go | 2 +- internal/emu/playstore.go | 2 +- internal/emu/start.go | 16 +++++----- internal/emu/stop.go | 38 ++++++++++++------------ internal/emu/stop_test.go | 14 ++++----- internal/emu/window.go | 10 +++---- internal/jsonord/testdata/gen_pycases.py | 2 +- internal/jsonord/testdata/pycases.json | 4 +-- internal/mcp/mcp_test.go | 4 +-- internal/report/collect.go | 6 ++-- internal/report/config.go | 2 +- internal/report/parity_windows_test.go | 19 +++++++----- internal/root/root.go | 18 +++++------ internal/root/root_test.go | 6 ++-- internal/ui/fake_test.go | 12 ++++---- internal/ui/proxy_test.go | 2 +- internal/ui/ui.go | 2 +- internal/ui/web/dev/mock.js | 38 ++++++++++++------------ internal/update/pkg.go | 2 +- internal/update/updater.go | 2 +- 48 files changed, 205 insertions(+), 201 deletions(-) diff --git a/README.en.md b/README.en.md index 4ffb23b..1e5fb46 100644 --- a/README.en.md +++ b/README.en.md @@ -259,7 +259,7 @@ Double-click `ModAVD.exe` in the package root: it starts a local server that lis ## Updating ModAVD -`modavd update` updates the whole ModAVD package in the root folder (the emulator, components and scripts, and also `ModAVD.exe` and `tools\modavd.exe` themselves). It does the same thing as AUTO-MAS's "ModAVD one-click update" (`魔改 AVD 一键更新`), and uses the same `\.update\` folder and state file: if an update is interrupted partway on either side, the other can finish it or roll it back. Under the current integration agreement, AUTO-MAS keeps its own updater for now; whether and when it switches to calling this command is up to the AUTO-MAS project's own maintenance, and this is not a feature or promise already delivered by this repository. +`modavd update` updates the whole ModAVD package in the root folder (the emulator, components and scripts, and also `ModAVD.exe` and `tools\modavd.exe` themselves). It does the same thing as AUTO-MAS's ModAVD one-click update, and uses the same `\.update\` folder and state file: if an update is interrupted partway on either side, the other can finish it or roll it back. Under the current integration agreement, AUTO-MAS keeps its own updater for now; whether and when it switches to calling this command is up to the AUTO-MAS project's own maintenance, and this is not a feature or promise already delivered by this repository. - It does only the step you explicitly ask for; it never goes online automatically and never downloads in the background: - `modavd update` (`status`) looks at local state only; `check` looks up the latest version; diff --git a/README.md b/README.md index ecf5311..f1a4254 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ -[ModAVD(魔改 AVD)](https://github.com/ModAVD/ModAVD) 的管理程序:图形管理器 `ModAVD.exe`,以及命令行和 MCP 服务 `modavd.exe`。Go 写,只用标准库。目前只支持 Windows x64,平台相关的部分已经拆成平台层,其他平台的安排见 [ModAVD#27](https://github.com/ModAVD/ModAVD/issues/27)。 +[ModAVD](https://github.com/ModAVD/ModAVD) 的管理程序:图形管理器 `ModAVD.exe`,以及命令行和 MCP 服务 `modavd.exe`。Go 写,只用标准库。目前只支持 Windows x64,平台相关的部分已经拆成平台层,其他平台的安排见 [ModAVD#27](https://github.com/ModAVD/ModAVD/issues/27)。 > **版本提示(`main` 与 Release)**:本文按仓库 `main` 的实现编写。当前 `main` 的版本是 `0.3.0`,最新独立 Release 是 `v0.1.0`(对应 ModAVD `0.36.0`),`v0.2.0` 已起草、还没发布;`0.2.0` 起的新建后台初始化、`update` 命令和退出码 9 都不在 `v0.1.0` 下载包里。使用已发布包时,请以对应 Release 的说明和包内版本为准。 @@ -261,7 +261,7 @@ claude mcp add --transport stdio --scope user modavd '--' D:\ModAVD\tools\modavd ## 更新 ModAVD -`modavd update` 更新根目录里的整个 ModAVD 包(模拟器、组件、脚本,也包括 `ModAVD.exe` 和 `tools\modavd.exe` 自己),和 AUTO-MAS 的「魔改 AVD 一键更新」做的是同一件事,用的也是同一个 `<根>\.update\` 目录和状态文件:哪边更新到一半被打断,另一边都能接着补完或退回。按当前对接约定,AUTO-MAS 目前保留自己的更新器;是否以及何时改成调用这个命令,由 AUTO-MAS 项目自己的维护决定,这不是本仓库已经交付的功能或承诺。 +`modavd update` 更新根目录里的整个 ModAVD 包(模拟器、组件、脚本,也包括 `ModAVD.exe` 和 `tools\modavd.exe` 自己),和 AUTO-MAS 里的 ModAVD 一键更新做的是同一件事,用的也是同一个 `<根>\.update\` 目录和状态文件:哪边更新到一半被打断,另一边都能接着补完或退回。按当前对接约定,AUTO-MAS 目前保留自己的更新器;是否以及何时改成调用这个命令,由 AUTO-MAS 项目自己的维护决定,这不是本仓库已经交付的功能或承诺。 - 只做明确要求的那一步,不自动联网、不在后台下载: - `modavd update`(`status`)只看本地;`check` 查最新版本; diff --git a/cmd/modavd-gui/main.go b/cmd/modavd-gui/main.go index 3565eb2..487db61 100644 --- a/cmd/modavd-gui/main.go +++ b/cmd/modavd-gui/main.go @@ -111,7 +111,7 @@ func run(args []string) (code int) { fs := flag.NewFlagSet("ModAVD", flag.ContinueOnError) fs.SetOutput(io.Discard) - rootFlag := fs.String("root", "", "魔改 AVD 根目录") + rootFlag := fs.String("root", "", "ModAVD 根目录") port := fs.Int("port", 0, "监听端口(0 = 随机)") noWindow := fs.Bool("no-window", false, "不打开窗口") dev := fs.Bool("dev", false, "开发模式:提供 /dev/ 的模拟后端页面,没有窗口也不自动退出") @@ -134,7 +134,7 @@ func run(args []string) (code int) { } r, err := root.Resolve(*rootFlag) if err != nil { - fatalErr("找不到魔改 AVD 根目录", err) + fatalErr("找不到 ModAVD 根目录", err) return errs.ExitCode(err) } diff --git a/internal/adb/adb.go b/internal/adb/adb.go index c08c31c..9a89c64 100644 --- a/internal/adb/adb.go +++ b/internal/adb/adb.go @@ -224,7 +224,7 @@ var ( func (c *Client) portConflict(k serverKind, port int, pid uint32, name string) *errs.Error { return errs.Newf(errs.PortConflict, - "魔改 AVD 的%s adb 端口 %d 被 %s(PID %d)占用,"+serverConflictReason+"。请在 %s 里把 %s 改成一个没被占用的端口"+ + "ModAVD 的%s adb 端口 %d 被 %s(PID %d)占用,"+serverConflictReason+"。请在 %s 里把 %s 改成一个没被占用的端口"+ "(不能用 5037 和各实例的控制台 / adb / gRPC 端口,也不能和 %s 相同),或者先关掉占用它的程序", k.label, port, name, pid, c.Root.MetadataPath(), k.key, k.otherKey) } @@ -321,7 +321,7 @@ func (c *Client) ensure(ctx context.Context, k serverKind, port int, timeout tim if err := prepareServerRoot(c.Root); err != nil { return false, err } - c.Log.Infof("启动魔改 AVD %s adb server(端口 %d)", k.label, port) + c.Log.Infof("启动 ModAVD %s adb server(端口 %d)", k.label, port) // StartOrphan rather than StartDetached: an MCP client ends modavd's whole process tree when it disconnects, and // while the start-server client (our child for ~2 s) is alive the server it forks is part of that tree. Losing // the server is not harmless: the emulator registers with it only once, at boot. Without a configured orphan @@ -329,7 +329,7 @@ func (c *Client) ensure(ctx context.Context, k serverKind, port int, timeout tim client, err := host.StartOrphan(c.Root.AdbExe(), []string{"-P", strconv.Itoa(port), "start-server"}, host.StartOptions{Env: c.Env()}) if err != nil { - return false, errs.Wrap(errs.Internal, err, fmt.Sprintf("启动魔改 AVD %s adb server(端口 %d)失败: %s", + return false, errs.Wrap(errs.Internal, err, fmt.Sprintf("启动 ModAVD %s adb server(端口 %d)失败: %s", k.label, port, errs.As(err).Message)) } return c.waitListening(ctx, k, port, timeout, client) diff --git a/internal/adb/adb_test.go b/internal/adb/adb_test.go index 8b66619..56d953d 100644 --- a/internal/adb/adb_test.go +++ b/internal/adb/adb_test.go @@ -351,14 +351,14 @@ func TestPortConflictMessage(t *testing.T) { dir := tempDir(t) c := New(&root.Root{Dir: dir}, nil) e := c.portConflict(privateServer, 20050, 1234, "foo.exe") - want := "魔改 AVD 的私有 adb 端口 20050 被 foo.exe(PID 1234)占用,它不是 adb。请在 " + c.Root.MetadataPath() + + want := "ModAVD 的私有 adb 端口 20050 被 foo.exe(PID 1234)占用,它不是 adb。请在 " + c.Root.MetadataPath() + " 里把 adbServerPort 改成一个没被占用的端口(不能用 5037 和各实例的控制台 / adb / gRPC 端口,也不能和 " + "scriptAdbServerPort 相同),或者先关掉占用它的程序" if e.Code != errs.PortConflict || e.Error() != want { t.Errorf("private conflict:\n got %s %q\nwant %q", e.Code, e.Error(), want) } e = c.portConflict(scriptServer, 20049, 1, "x.exe") - if !strings.HasPrefix(e.Message, "魔改 AVD 的脚本专用 adb 端口 20049 被 x.exe(PID 1)占用") || + if !strings.HasPrefix(e.Message, "ModAVD 的脚本专用 adb 端口 20049 被 x.exe(PID 1)占用") || !strings.Contains(e.Message, "里把 scriptAdbServerPort 改成") || !strings.Contains(e.Message, "也不能和 adbServerPort 相同") { t.Errorf("script conflict: %q", e.Message) } diff --git a/internal/adb/real_adb_test.go b/internal/adb/real_adb_test.go index e003776..c6b2c22 100644 --- a/internal/adb/real_adb_test.go +++ b/internal/adb/real_adb_test.go @@ -186,7 +186,7 @@ func TestRealAdb(t *testing.T) { t.Fatalf("EnsureServer = %v, %v", ok, err) } t.Logf("EnsureServer took %v", time.Since(start)) - if n := logs.count(fmt.Sprintf("启动魔改 AVD 私有 adb server(端口 %d)", testServerPort)); n != 1 { + if n := logs.count(fmt.Sprintf("启动 ModAVD 私有 adb server(端口 %d)", testServerPort)); n != 1 { t.Errorf("start log lines = %d", n) } pid, up, err := win.ListenerPID(testServerPort) @@ -205,7 +205,7 @@ func TestRealAdb(t *testing.T) { if err != nil || !ok { t.Errorf("second EnsureServer = %v, %v", ok, err) } - if n := logs.count("启动魔改 AVD 私有 adb server"); n != 1 { + if n := logs.count("启动 ModAVD 私有 adb server"); n != 1 { t.Errorf("second EnsureServer started again (%d log lines)", n) } // PrepareForClose with the server up asks it first; it does not know emulator-20080, and no qemu of this @@ -277,7 +277,7 @@ func TestRealAdb(t *testing.T) { if err != nil || !ok { t.Fatalf("EnsureScriptServer = %v, %v", ok, err) } - if n := logs.count(fmt.Sprintf("启动魔改 AVD 脚本专用 adb server(端口 %d)", testScriptPort)); n != 1 { + if n := logs.count(fmt.Sprintf("启动 ModAVD 脚本专用 adb server(端口 %d)", testScriptPort)); n != 1 { t.Errorf("script start log lines = %d", n) } pid, _, _ := win.ListenerPID(testScriptPort) diff --git a/internal/avd/avd.go b/internal/avd/avd.go index 4924829..a590af2 100644 --- a/internal/avd/avd.go +++ b/internal/avd/avd.go @@ -426,7 +426,7 @@ func Get(r *root.Root, i int) (*Instance, error) { return nil, notFound(i) } -func notFound(i int) error { return errs.Newf(errs.NotFound, "魔改 AVD 实例 %d 不存在", i) } +func notFound(i int) error { return errs.Newf(errs.NotFound, "ModAVD 实例 %d 不存在", i) } // lockInstance takes root.LockInstanceConfig of i. noDir: the avd directory does not exist (no lock taken, nothing on // disk to guard); err is nil then. @@ -509,10 +509,10 @@ func ValidateOptions(memoryMB, cpu, dataGB *int) (int, int, int, error) { data = *dataGB } if !slices.Contains(MemoryChoicesMB, memory) { - return 0, 0, 0, errs.New(errs.InvalidArgument, "魔改 AVD 的内存只能选 "+joinInts(MemoryChoicesMB, "%d GB", 1024)) + return 0, 0, 0, errs.New(errs.InvalidArgument, "ModAVD 的内存只能选 "+joinInts(MemoryChoicesMB, "%d GB", 1024)) } if !slices.Contains(CPUChoices, cores) { - return 0, 0, 0, errs.New(errs.InvalidArgument, "魔改 AVD 的 CPU 核数只能选 "+joinInts(CPUChoices, "%d", 1)) + return 0, 0, 0, errs.New(errs.InvalidArgument, "ModAVD 的 CPU 核数只能选 "+joinInts(CPUChoices, "%d", 1)) } if data < MinDataPartitionGB || data > MaxDataPartitionGB { return 0, 0, 0, errs.Newf(errs.InvalidArgument, "数据盘上限只能在 %d–%d GB 之间", MinDataPartitionGB, @@ -528,7 +528,7 @@ func ValidateFPS(fps *int) (int, error) { value = *fps } if !slices.Contains(FPSChoices, value) { - return 0, errs.New(errs.InvalidArgument, "魔改 AVD 的帧率只能选 "+joinInts(FPSChoices, "%d", 1)) + return 0, errs.New(errs.InvalidArgument, "ModAVD 的帧率只能选 "+joinInts(FPSChoices, "%d", 1)) } return value, nil } @@ -714,7 +714,7 @@ func pathExists(path string) bool { } // FreeIndex is the smallest valid index that has no instance and whose three ports in plan busy() reports free. -// errs.Busy "魔改 AVD 实例已满(端口段 20000–20100 最多 9 台)" (the root's plan) when there is none. A nil busy skips +// errs.Busy "ModAVD 实例已满(端口段 20000–20100 最多 9 台)" (the root's plan) when there is none. A nil busy skips // the port check. func FreeIndex(plan root.PortPlan, existing map[int]bool, busy func(ports []int) []int) (int, error) { for i := 0; i <= root.MaxIndex; i++ { @@ -727,7 +727,7 @@ func FreeIndex(plan root.PortPlan, existing map[int]bool, busy func(ports []int) } return i, nil } - return 0, errs.Newf(errs.Busy, "魔改 AVD 实例已满(端口段 %d–%d 最多 9 台)", plan.Base, plan.Base+100) + return 0, errs.Newf(errs.Busy, "ModAVD 实例已满(端口段 %d–%d 最多 9 台)", plan.Base, plan.Base+100) } type UpdateOptions struct { diff --git a/internal/avd/avd_test.go b/internal/avd/avd_test.go index c4cffdb..d0d3360 100644 --- a/internal/avd/avd_test.go +++ b/internal/avd/avd_test.go @@ -635,7 +635,7 @@ func TestListAndGet(t *testing.T) { os.Remove(r.AvdHome()) _, err := Get(r, 0) wantCode(t, err, errs.NotFound) - if err.Error() != "魔改 AVD 实例 0 不存在" { + if err.Error() != "ModAVD 实例 0 不存在" { t.Fatalf("message: %v", err) } for _, i := range []int{4, 0, 9} { @@ -727,9 +727,9 @@ func TestValidate(t *testing.T) { memory, cpu, data *int msg string }{ - {ip(1000), nil, nil, "魔改 AVD 的内存只能选 3 GB / 4 GB / 5 GB / 6 GB"}, - {ip(0), ip(3), ip(1), "魔改 AVD 的内存只能选 3 GB / 4 GB / 5 GB / 6 GB"}, - {nil, ip(3), ip(1), "魔改 AVD 的 CPU 核数只能选 2 / 4 / 6"}, + {ip(1000), nil, nil, "ModAVD 的内存只能选 3 GB / 4 GB / 5 GB / 6 GB"}, + {ip(0), ip(3), ip(1), "ModAVD 的内存只能选 3 GB / 4 GB / 5 GB / 6 GB"}, + {nil, ip(3), ip(1), "ModAVD 的 CPU 核数只能选 2 / 4 / 6"}, {nil, nil, ip(15), "数据盘上限只能在 16–512 GB 之间"}, {nil, nil, ip(513), "数据盘上限只能在 16–512 GB 之间"}, } { @@ -753,7 +753,7 @@ func TestValidate(t *testing.T) { } _, err = ValidateFPS(ip(0)) wantCode(t, err, errs.InvalidArgument) - if err.Error() != "魔改 AVD 的帧率只能选 30 / 60" { + if err.Error() != "ModAVD 的帧率只能选 30 / 60" { t.Errorf("fps message %q", err.Error()) } } @@ -805,7 +805,7 @@ func TestFreeIndex(t *testing.T) { } _, err = FreeIndex(def, all, func(ports []int) []int { return ports }) wantCode(t, err, errs.Busy) - if err.Error() != "魔改 AVD 实例已满(端口段 20000–20100 最多 9 台)" { + if err.Error() != "ModAVD 实例已满(端口段 20000–20100 最多 9 台)" { t.Fatalf("message %v", err) } // another plan: the ports asked about and the message are the plan's @@ -815,7 +815,7 @@ func TestFreeIndex(t *testing.T) { t.Fatalf("plan 21000: FreeIndex = %d %v, asked %v", i, err, asked) } _, err = FreeIndex(root.PortPlan{Base: 21000}, all, func(ports []int) []int { return ports }) - if err == nil || err.Error() != "魔改 AVD 实例已满(端口段 21000–21100 最多 9 台)" { + if err == nil || err.Error() != "ModAVD 实例已满(端口段 21000–21100 最多 9 台)" { t.Fatalf("plan 21000: message %v", err) } all[7] = true diff --git a/internal/avd/testdata/instances_ref.py b/internal/avd/testdata/instances_ref.py index adcebfc..f49f1e4 100644 --- a/internal/avd/testdata/instances_ref.py +++ b/internal/avd/testdata/instances_ref.py @@ -328,12 +328,12 @@ def validate_options(memory_mb, cpu, data_partition_gb): ) if memory not in MEMORY_CHOICES_MB: raise ValueError( - "魔改 AVD 的内存只能选 " + "ModAVD 的内存只能选 " + " / ".join(f"{value // 1024} GB" for value in MEMORY_CHOICES_MB) ) if cores not in CPU_CHOICES: raise ValueError( - "魔改 AVD 的 CPU 核数只能选 " + " / ".join(str(v) for v in CPU_CHOICES) + "ModAVD 的 CPU 核数只能选 " + " / ".join(str(v) for v in CPU_CHOICES) ) low, high = DATA_PARTITION_RANGE_GB if not low <= data_gb <= high: @@ -345,7 +345,7 @@ def validate_fps(fps): value = DEFAULT_FPS if fps is None else int(fps) if value not in FPS_CHOICES: raise ValueError( - "魔改 AVD 的帧率只能选 " + " / ".join(str(v) for v in FPS_CHOICES) + "ModAVD 的帧率只能选 " + " / ".join(str(v) for v in FPS_CHOICES) ) return value @@ -432,7 +432,7 @@ def write_instance_settings(root, idx, changes): """AvdManager.write_instance_settings for cpu / memoryMb / fps (no display keys, no expected values).""" instance = list_instances(root).get(str(idx)) if instance is None: - raise RuntimeError(f"魔改 AVD 实例 {idx} 不存在") + raise RuntimeError(f"ModAVD 实例 {idx} 不存在") fps = validate_fps(changes["fps"]) if "fps" in changes else None memory, cpu, _ = validate_options( changes.get("memoryMb", memory_for(instance_meta(root, idx))), diff --git a/internal/cli/commands.go b/internal/cli/commands.go index 89441b5..22ec6a6 100644 --- a/internal/cli/commands.go +++ b/internal/cli/commands.go @@ -124,7 +124,7 @@ func init() { "status 列出这五个文件在不在、从哪来(download / import),不把它算进必需组件。" + "不带参数时默认查看组件;source 查看或修改记住的下载源(auto、googledownloads_cn、tencent、google)。" + "--json 时必须给 --accept-license(仅 fetch)。只有 Windows 有组件清单,darwin、linux 返回 unsupported。" + - "退出码:没同意许可协议是 2(license_declined),路径有中文、空间不够、不是魔改 AVD 的文件夹是 4," + + "退出码:没同意许可协议是 2(license_declined),路径有中文、空间不够、不是 ModAVD 的文件夹是 4," + "正在补全是 5,下不成是 9(components_unavailable),下载或解压后没通过校验、导入的文件被拒收也是 9(components_rejected," + "--json 的 error.details.reason 是 unknown_file、mismatch 或 incomplete)。" if runtime.GOOS == "darwin" && runtime.GOARCH == "arm64" { @@ -236,7 +236,7 @@ func init() { { name: "collect-info", args: "[--out-dir 目录] [--stage-dir 目录] [--keep-stage] [--no-explorer]", summary: "收集问题信息,打成 zip", - details: "打成「魔改AVD问题信息-<时间>.zip」,默认放桌面,再打开资源管理器选中它(--no-explorer 不打开)。" + + details: "打成「ModAVD-问题信息-<时间>.zip」,默认放桌面,再打开资源管理器选中它(--no-explorer 不打开)。" + "--stage-dir 是暂存目录的父目录(默认 %TEMP%),--keep-stage 保留暂存目录。每一节单独收,出错写进 summary.txt 接着收下一节。" + "只读:不收磁盘镜像,不收 AUTO-MAS 的配置和账号数据,不起 adb server、不碰 5037。目前只支持 Windows。", flags: []flagSpec{optOutDir, optStageDir, optKeepStage, optNoExplorer}, final: true, @@ -805,7 +805,7 @@ func stopAll(c *cmdCtx, m manager, opt emu.StopOptions) (*StopAllResult, error) c.log.Infof("没有正在运行的实例") return res, nil } - c.log.Infof("同时正常关闭 %d 台魔改 AVD 实例(安卓正常关机):%s", len(targets), joinInts(targets, "、")) + c.log.Infof("同时正常关闭 %d 台 ModAVD 实例(安卓正常关机):%s", len(targets), joinInts(targets, "、")) type outcome struct { r *emu.StopResult err error @@ -830,7 +830,7 @@ func stopAll(c *cmdCtx, m manager, opt emu.StopOptions) (*StopAllResult, error) if c.ctx.Err() != nil && errs.CodeOf(e) != errs.Canceled { e = errs.Wrap(errs.Canceled, e, "已取消") } - c.log.Warnf("魔改 AVD 实例 %d 关机失败: %s", targets[k], errs.As(e).Error()) + c.log.Warnf("ModAVD 实例 %d 关机失败: %s", targets[k], errs.As(e).Error()) res.Failed = append(res.Failed, StopFailure{Index: targets[k], Error: errorInfo(e)}) continue } diff --git a/internal/cli/format.go b/internal/cli/format.go index e6c4768..1bf4b69 100644 --- a/internal/cli/format.go +++ b/internal/cli/format.go @@ -801,7 +801,7 @@ func formatHelp(w io.Writer, r *HelpResult) { } return } - fmt.Fprintln(w, "modavd:魔改 AVD 实例管理(新建、删除、修改、列出、开机、关机)和 MCP 服务") + fmt.Fprintln(w, "modavd:ModAVD 实例管理(新建、删除、修改、列出、开机、关机)和 MCP 服务") fmt.Fprintf(w, "\n用法:%s\n\n命令:\n", r.Usage) // Usage and summary on separate lines: create's usage alone is ~80 columns. for _, e := range r.Commands { diff --git a/internal/cli/report_test.go b/internal/cli/report_test.go index 7324fb1..7e07542 100644 --- a/internal/cli/report_test.go +++ b/internal/cli/report_test.go @@ -54,11 +54,12 @@ func TestHumanCollectInfoMatchesScript(t *testing.T) { t.Fatalf("%s: the script's privacy note head not found once", c.name) } want = strings.Replace(want, scriptPrivacyHead+"\n", head+"\n", 1) - // and for what the script said as if every user had AUTO-MAS (report's notAllMAS) + // and for what it says differently on purpose (report's reworded) + want = strings.Replace(want, "魔改AVD问题信息-", "ModAVD-问题信息-", 1) want = strings.Replace(want, "实例配置、AUTO-MAS 日志(mas 文件夹);", "实例配置;找到 AUTO-MAS 时还有它的日志(mas 文件夹);", 1) want = strings.Replace(want, "没找到 AUTO-MAS 安装目录,反馈时请附上 AUTO-MAS 的 debug 文件夹里的日志\n", report.MasMissingNote+"\n", 1) res := &report.CollectResult{ - ZipPath: `{{BASE}}\out\魔改AVD问题信息-20260115-120000.zip`, ZipSize: "{{SIZE}}", + ZipPath: `{{BASE}}\out\ModAVD-问题信息-20260115-120000.zip`, ZipSize: "{{SIZE}}", PrivacyNote: report.PrivacyNote, MasFound: c.mas, Problems: c.problems, } var b bytes.Buffer diff --git a/internal/components/fetch.go b/internal/components/fetch.go index 3ea6a9a..596f1bb 100644 --- a/internal/components/fetch.go +++ b/internal/components/fetch.go @@ -334,7 +334,7 @@ func Fetch(ctx context.Context, r *root.Root, o Options) (*Result, error) { return nil, errs.New(errs.Unsupported, "这个系统还没有组件清单").WithAdvice("目前支持 Windows 和 Apple Silicon macOS") } if r == nil { - return nil, errs.New(errs.NotFound, "找不到魔改 AVD 根目录") + return nil, errs.New(errs.NotFound, "找不到 ModAVD 根目录") } if err := o.CheckTimeouts(); err != nil { return nil, err @@ -389,7 +389,7 @@ func (f *fetcher) run(ctx context.Context) (res *Result, err error) { if f.o.PlayStore { what += "、Google Play 商店" } - f.say("魔改 AVD:补全 Google 组件(" + what + ")") + f.say("ModAVD:补全 Google 组件(" + what + ")") f.say("文件夹:" + r.Dir) free := "-1" if f.o.TestFreeSpaceMB != nil { @@ -413,7 +413,7 @@ func (f *fetcher) run(ctx context.Context) (res *Result, err error) { if f.darwin() { advice = "请完整解压 Apple Silicon 发行包,再在包根目录运行 modavd components fetch" } - return nil, errs.Newf(errs.NotReady, "这里没有 %s,不像是魔改 AVD 的文件夹:%s", filepath.Join("sdk", "emulator", root.CurrentPlatform().Emulator), r.Dir). + return nil, errs.Newf(errs.NotReady, "这里没有 %s,不像是 ModAVD 的文件夹:%s", filepath.Join("sdk", "emulator", root.CurrentPlatform().Emulator), r.Dir). WithAdvice(advice) } if r.LocalSDKRoot() != "" { diff --git a/internal/components/playstore.go b/internal/components/playstore.go index d5d5b4e..38fae24 100644 --- a/internal/components/playstore.go +++ b/internal/components/playstore.go @@ -184,7 +184,7 @@ func ImportPlayStore(ctx context.Context, r *root.Root, files []ImportFile, o Op return nil, errs.New(errs.Unsupported, "这个系统还没有组件清单").WithAdvice("目前支持 Windows 和 Apple Silicon macOS") } if r == nil { - return nil, errs.New(errs.NotFound, "找不到魔改 AVD 根目录") + return nil, errs.New(errs.NotFound, "找不到 ModAVD 根目录") } if len(files) == 0 { return nil, errs.New(errs.Usage, "没有给要导入的文件"). @@ -197,7 +197,7 @@ func ImportPlayStore(ctx context.Context, r *root.Root, files []ImportFile, o Op f := &fetcher{r: r, o: o, sdk: r.SDK()} emulator := filepath.Join("sdk", "emulator", root.CurrentPlatform().Emulator) if _, err := os.Stat(filepath.Join(f.sdk, "emulator", root.CurrentPlatform().Emulator)); err != nil { - return nil, errs.Newf(errs.NotReady, "这里没有 %s,不像是魔改 AVD 的文件夹:%s", emulator, r.Dir) + return nil, errs.Newf(errs.NotReady, "这里没有 %s,不像是 ModAVD 的文件夹:%s", emulator, r.Dir) } if r.LocalSDKRoot() != "" { return nil, errs.New(errs.NotReady, "这个根目录在 mas-avd.json 里设了 sdkRoot(开发用的本地 SDK),不导入组件"). @@ -230,7 +230,7 @@ func ImportPlayStore(ctx context.Context, r *root.Root, files []ImportFile, o Op } f.note(fmt.Sprintf("退出码 %d", errs.ExitCode(err))) }() - f.say("魔改 AVD:用自己的文件补全 Google Play 商店") + f.say("ModAVD:用自己的文件补全 Google Play 商店") f.say("文件夹:" + r.Dir) if f.darwin() { if err := f.platformPaths(); err != nil { diff --git a/internal/emu/adbcmd.go b/internal/emu/adbcmd.go index f4f1650..dc57038 100644 --- a/internal/emu/adbcmd.go +++ b/internal/emu/adbcmd.go @@ -29,7 +29,7 @@ func (m *Manager) Shell(ctx context.Context, i int, command string, timeout time if _, ok, err := m.qemuOf(i); err != nil { return nil, err } else if !ok { - return nil, errs.Newf(errs.Unsupported, "魔改 AVD 实例 %d 没有在运行", i) + return nil, errs.Newf(errs.Unsupported, "ModAVD 实例 %d 没有在运行", i) } res := m.shell(ctx, i, command, timeout) if err := ctxErr(ctx); err != nil { diff --git a/internal/emu/bootdiag_windows_test.go b/internal/emu/bootdiag_windows_test.go index b052e6b..606d11c 100644 --- a/internal/emu/bootdiag_windows_test.go +++ b/internal/emu/bootdiag_windows_test.go @@ -35,7 +35,7 @@ func TestSaveBootFailure(t *testing.T) { return m.saveBootFailure(ctx, i, err, running) } - failure := errs.New(errs.Timeout, "魔改 AVD 实例 6 启动超时") + failure := errs.New(errs.Timeout, "ModAVD 实例 6 启动超时") diagDirs := func() []string { matches, _ := filepath.Glob(filepath.Join(r.LogsDir(), "mas_6-*-bootfail")) return matches diff --git a/internal/emu/bridge.go b/internal/emu/bridge.go index 331c7ad..30dc23b 100644 --- a/internal/emu/bridge.go +++ b/internal/emu/bridge.go @@ -359,7 +359,7 @@ func (m *Manager) installBridge(ctx context.Context, i int, opt StartOptions, re // The script's notes go to this log; the warnings of the cold boots come with their results (m, not mm, starts them). col := &logx.Collector{} mm := m.withLog(col.Sink()) - mm.Log.Infof("魔改 AVD 实例 %d 有执行桥的开机标记,桥还没装:现在装(中间要关机再开机一到两次)", i) + mm.Log.Infof("ModAVD 实例 %d 有执行桥的开机标记,桥还没装:现在装(中间要关机再开机一到两次)", i) notWritable := 0 for round := 1; round <= bridgeInstallRounds; round++ { if opt.Progress != nil { @@ -455,7 +455,7 @@ func (m *Manager) updateBridgeLocked(ctx context.Context, i int, opt StartOption res.Warnings = append(res.Warnings, col.Messages()...) return res, nil } - mm.Log.Infof("魔改 AVD 实例 %d 的执行桥文件和根目录里的载荷不一样(多半是更新过 ModAVD 包):现在更新,之后冷启动一次", i) + mm.Log.Infof("ModAVD 实例 %d 的执行桥文件和根目录里的载荷不一样(多半是更新过 ModAVD 包):现在更新,之后冷启动一次", i) if opt.Progress != nil { opt.Progress(Progress{Step: "bridge", Message: fmt.Sprintf("实例 %d 更新 arm64 执行桥", i), Done: 0, Total: progressTotal}) @@ -603,7 +603,7 @@ func (m *Manager) Bridge(ctx context.Context, i int, action string) (*BridgeResu return nil, err } if !ok { - return nil, errs.WithDetails(errs.Newf(errs.Busy, "魔改 AVD 实例 %d 正在装或卸执行桥,稍后再试", i), map[string]string{errs.Reason: "locked", errs.Lock: "bridge"}) + return nil, errs.WithDetails(errs.Newf(errs.Busy, "ModAVD 实例 %d 正在装或卸执行桥,稍后再试", i), map[string]string{errs.Reason: "locked", errs.Lock: "bridge"}) } defer bridgeLock.Unlock() res := &BridgeResult{Index: i, Action: action, ExitCode: -1, Warnings: []string{}} diff --git a/internal/emu/check.go b/internal/emu/check.go index 97bb9ef..cdeb830 100644 --- a/internal/emu/check.go +++ b/internal/emu/check.go @@ -39,7 +39,7 @@ const ( "「Windows 虚拟机监控程序平台」,然后重启" vulkanAdvice = "安装或更新显卡驱动(NVIDIA / AMD / Intel 官网驱动自带 Vulkan)。没有可用的显卡时模拟器只能" + "软件渲染,游戏会占满 CPU,性能会很差" - testPackageAdvice = `请把魔改 AVD 内测包解压到这个目录(解压后目录里应有 sdk\emulator)` + testPackageAdvice = `请把 ModAVD 内测包解压到这个目录(解压后目录里应有 sdk\emulator)` // How long a result of the same check is reused within one process (MCP server): AUTO-MAS // _ACCEL_CACHE_SECONDS, VULKAN_PROBE_CACHE_SECONDS, VULKAN_PROBE_TIMEOUT_CACHE_SECONDS. @@ -132,7 +132,7 @@ func (m *Manager) precheckBeforeLaunch(ctx context.Context, memoryMB int) error return err } if vulkan.OK != nil && !*vulkan.OK { - m.Log.Warnf("魔改 AVD 开机前检查:%s", itemMessage(vulkan)) + m.Log.Warnf("ModAVD 开机前检查:%s", itemMessage(vulkan)) } items = append(items, vulkan) m.Log.Infof("%s", precheckSummary(items)) @@ -179,7 +179,7 @@ func precheckError(it CheckItem, missingErr func() error) error { } } -// precheckSummary is AUTO-MAS's one log line: "魔改 AVD 开机前检查:目录路径通过(<根目录>);组件通过(...);...". +// precheckSummary is AUTO-MAS's one log line: "ModAVD 开机前检查:目录路径通过(<根目录>);组件通过(...);...". func precheckSummary(items []CheckItem) string { parts := make([]string, len(items)) for k, it := range items { @@ -192,7 +192,7 @@ func precheckSummary(items []CheckItem) string { } parts[k] = fmt.Sprintf("%s%s(%s)", it.Title, verdict, it.Reason) } - return "魔改 AVD 开机前检查:" + strings.Join(parts, ";") + return "ModAVD 开机前检查:" + strings.Join(parts, ";") } func pathIsASCII(s string) bool { @@ -307,7 +307,7 @@ func emulatorItem(f emulatorFacts) CheckItem { if !f.Present { return CheckItem{ ID: "emulator", Title: title, OK: checkOK(false), Blocking: true, - Reason: "这个目录里还没有魔改 AVD 内测包", Advice: platformPackageAdvice(), + Reason: "这个目录里还没有 ModAVD 内测包", Advice: platformPackageAdvice(), } } version := f.Version @@ -317,7 +317,7 @@ func emulatorItem(f emulatorFacts) CheckItem { if !f.SelfBuilt { return CheckItem{ ID: "emulator", Title: title, OK: checkOK(false), Blocking: true, - Reason: fmt.Sprintf("这里的模拟器(%s)不是魔改 AVD 内测包里的版本,只支持内测包", version), + Reason: fmt.Sprintf("这里的模拟器(%s)不是 ModAVD 内测包里的版本,只支持内测包", version), Advice: platformPackageAdvice(), } } @@ -334,7 +334,7 @@ func emulatorItem(f emulatorFacts) CheckItem { return CheckItem{ ID: "emulator", Title: title, OK: checkOK(false), Blocking: true, Reason: fmt.Sprintf("内测包版本过旧(%s)", shown), - Advice: fmt.Sprintf("请把魔改 AVD 更新到 0.%d.0 或更新的版本,实例和游戏数据不受影响", root.MinModBuild), + Advice: fmt.Sprintf("请把 ModAVD 更新到 0.%d.0 或更新的版本,实例和游戏数据不受影响", root.MinModBuild), } } @@ -373,7 +373,7 @@ func diskItem(drive string, free uint64, err error) CheckItem { return CheckItem{ ID: "disk", Title: "磁盘", OK: checkOK(false), Blocking: true, Reason: fmt.Sprintf("%s,低于开机所需的 %d GB:数据盘随游戏写入增长,盘写满时实例数据会损坏", text, minFreeDiskGBToBoot), - Advice: fmt.Sprintf("清理 %s 的空间,或把魔改 AVD 根目录放到空间更大的盘", drive), + Advice: fmt.Sprintf("清理 %s 的空间,或把 ModAVD 根目录放到空间更大的盘", drive), } } @@ -443,11 +443,11 @@ func accelItem(res accelResult, summary string) CheckItem { backend, advice := "Windows 虚拟机监控程序平台", accelAdvice if runtime.GOOS == "darwin" { backend = "Hypervisor.framework" - advice = "请在 Apple Silicon Mac 本机运行 macos-arm64 版魔改 AVD,确认模拟器带 com.apple.security.hypervisor 签名权限;用 emulator -accel-check 检查 HVF" + advice = "请在 Apple Silicon Mac 本机运行 macos-arm64 版 ModAVD,确认模拟器带 com.apple.security.hypervisor 签名权限;用 emulator -accel-check 检查 HVF" } return CheckItem{ ID: "acceleration", Title: "硬件虚拟化", OK: checkOK(false), Blocking: true, - Reason: fmt.Sprintf("硬件虚拟化(%s)不可用,魔改 AVD 无法启动(检查结果:%s)", backend, summary), + Reason: fmt.Sprintf("硬件虚拟化(%s)不可用,ModAVD 无法启动(检查结果:%s)", backend, summary), Advice: advice, } } @@ -561,7 +561,7 @@ func accelOKText(summary string) string { func platformPackageAdvice() string { if runtime.GOOS == "darwin" { - return "请把魔改 AVD 的 macos-arm64 内测包解压到这个目录(解压后应有 sdk/emulator)" + return "请把 ModAVD 的 macos-arm64 内测包解压到这个目录(解压后应有 sdk/emulator)" } return testPackageAdvice } diff --git a/internal/emu/check_darwin.go b/internal/emu/check_darwin.go index 1d4f7cb..b66c965 100644 --- a/internal/emu/check_darwin.go +++ b/internal/emu/check_darwin.go @@ -16,7 +16,7 @@ import ( // A directory named arm64-v8a must not silently make an x86 image compatible. func (m *Manager) platformCheckItems() []CheckItem { it := CheckItem{ID: "guest-architecture", Title: "客体架构", OK: checkOK(false), Blocking: true, - Advice: "请使用 macos-arm64 版魔改 AVD 和对应的 Apple Silicon 系统镜像"} + Advice: "请使用 macos-arm64 版 ModAVD 和对应的 Apple Silicon 系统镜像"} p := root.CurrentPlatform() if !p.Supported() || p.GuestABI != "arm64-v8a" || p.GuestArch != "arm64" { it.Reason = "当前 macOS 管理器仅支持 Apple Silicon 和 arm64-v8a 客体" diff --git a/internal/emu/check_test.go b/internal/emu/check_test.go index 08fedfb..aecfc02 100644 --- a/internal/emu/check_test.go +++ b/internal/emu/check_test.go @@ -131,11 +131,11 @@ func TestComponentsItem(t *testing.T) { func TestEmulatorItem(t *testing.T) { it := emulatorItem(emulatorFacts{}) - if it.OK == nil || *it.OK || it.Reason != "这个目录里还没有魔改 AVD 内测包" || it.Advice != testPackageAdvice { + if it.OK == nil || *it.OK || it.Reason != "这个目录里还没有 ModAVD 内测包" || it.Advice != testPackageAdvice { t.Fatalf("absent = %+v", it) } it = emulatorItem(emulatorFacts{Present: true, Version: "37.1.11"}) - if it.OK == nil || *it.OK || it.Reason != "这里的模拟器(37.1.11)不是魔改 AVD 内测包里的版本,只支持内测包" { + if it.OK == nil || *it.OK || it.Reason != "这里的模拟器(37.1.11)不是 ModAVD 内测包里的版本,只支持内测包" { t.Fatalf("google build = %+v", it) } it = emulatorItem(emulatorFacts{Present: true}) @@ -240,7 +240,7 @@ func TestPrecheckSummary(t *testing.T) { {Title: "硬件虚拟化", OK: nil, Reason: "没装"}, {Title: "显卡 Vulkan", OK: checkOK(false), Reason: "没有"}, }) - want := `魔改 AVD 开机前检查:目录路径通过(D:\r);硬件虚拟化未查(没装);显卡 Vulkan未通过(没有)` + want := `ModAVD 开机前检查:目录路径通过(D:\r);硬件虚拟化未查(没装);显卡 Vulkan未通过(没有)` if got != want { t.Fatalf("summary\n got %s\nwant %s", got, want) } diff --git a/internal/emu/createinit.go b/internal/emu/createinit.go index 097e83c..7976f55 100644 --- a/internal/emu/createinit.go +++ b/internal/emu/createinit.go @@ -112,7 +112,7 @@ func (m *Manager) notCreated(i int, what string) error { state, message, logFile := m.creation(i) switch state { case creationCreating: - return errs.WithDetails(errs.Newf(errs.Busy, "魔改 AVD 实例 %d 正在新建(后台开机做初始化),%s", i, what). + return errs.WithDetails(errs.Newf(errs.Busy, "ModAVD 实例 %d 正在新建(后台开机做初始化),%s", i, what). WithAdvice("等它做完;进度用 modavd status 查看"), map[string]string{errs.Reason: "locked", errs.Lock: "create"}) case creationFailed: advice := fmt.Sprintf("用 modavd create --resume %d 重新初始化,或者 modavd delete %d --yes 删掉", i, i) @@ -123,7 +123,7 @@ func (m *Manager) notCreated(i int, what string) error { message = "初始化没做完" } // the reason last: a setup error has its own brackets - return errs.Newf(errs.NotReady, "魔改 AVD 实例 %d 新建时初始化失败,%s:%s", i, what, message).WithAdvice(advice) + return errs.Newf(errs.NotReady, "ModAVD 实例 %d 新建时初始化失败,%s:%s", i, what, message).WithAdvice(advice) } return nil } @@ -425,7 +425,7 @@ func (m *Manager) setupNew(ctx context.Context, i int, cfg *avd.Ini, req CreateR if logFile != "" { advice += ";日志见 " + logFile } - return nil, &errs.Error{Code: e.Code, Message: fmt.Sprintf("魔改 AVD 实例 %d 新建失败:%s", i, e.Message), + return nil, &errs.Error{Code: e.Code, Message: fmt.Sprintf("ModAVD 实例 %d 新建失败:%s", i, e.Message), Advice: advice, Cause: err} } prog.stage("done", fmt.Sprintf("实例 %d 新建完成,已关机;第一次开机不用再做初始化", i)) @@ -450,7 +450,7 @@ func (m *Manager) stopCreateLeftover(ctx context.Context, i int) error { defer cancel() if err := createStop(m, sctx, i); err != nil { e := errs.As(err) - return errs.Wrap(e.Code, err, fmt.Sprintf("魔改 AVD 实例 %d 上次新建时开的模拟器没能正常关掉: %s", i, e.Message)). + return errs.Wrap(e.Code, err, fmt.Sprintf("ModAVD 实例 %d 上次新建时开的模拟器没能正常关掉: %s", i, e.Message)). WithAdvice(fmt.Sprintf("用 modavd stop %d 关掉它,再重试", i)) } return nil diff --git a/internal/emu/crud.go b/internal/emu/crud.go index 38b12d2..37cba15 100644 --- a/internal/emu/crud.go +++ b/internal/emu/crud.go @@ -104,7 +104,7 @@ func (m *Manager) Create(ctx context.Context, req CreateRequest) (_ *InstanceInf lock.Unlock() return nil, err } - m.Log.Infof("已新建魔改 AVD 实例 %d(内存 %d MB / %d 核 / 数据盘 %d GB / 帧率 %d)", i, memory, cpu, dataGB, fps) + m.Log.Infof("已新建 ModAVD 实例 %d(内存 %d MB / %d 核 / 数据盘 %d GB / 帧率 %d)", i, memory, cpu, dataGB, fps) if req.NoBridge { // recorded, so no start installs it (bridge.go) if err := m.setBridgeWanted(i, false); err != nil { @@ -189,7 +189,7 @@ func (m *Manager) resumeCreate(ctx context.Context, req CreateRequest) (*Instanc // with the lock in hand, a recorded "creating" is one that was killed (creation() would see our own lock) if state := m.creationRecorded(i); state != creationFailed && state != creationCreating { lock.Unlock() - return nil, errs.Newf(errs.Unsupported, "魔改 AVD 实例 %d 不是新建失败的实例,没有要重做的初始化", i). + return nil, errs.Newf(errs.Unsupported, "ModAVD 实例 %d 不是新建失败的实例,没有要重做的初始化", i). WithAdvice(fmt.Sprintf("直接 modavd start %d", i)) } return m.setupNew(ctx, i, in.Config, req, lock) @@ -233,7 +233,7 @@ func (m *Manager) Update(ctx context.Context, i int, req UpdateRequest) (*Update warnings = col.Messages() applied["diagnostics"] = *req.Diagnostics } - m.Log.Infof("已写入魔改 AVD 实例 %d 的设置: %s", i, formatApplied(applied)) + m.Log.Infof("已写入 ModAVD 实例 %d 的设置: %s", i, formatApplied(applied)) in, err := m.instance(i) if err != nil { return nil, err @@ -246,7 +246,7 @@ func (m *Manager) Update(ctx context.Context, i int, req UpdateRequest) (*Update if ok { p = &q if nextBoot { - m.Log.Infof("魔改 AVD 实例 %d 正在运行,硬件改动下次开机生效", i) + m.Log.Infof("ModAVD 实例 %d 正在运行,硬件改动下次开机生效", i) } } return &UpdateResult{Instance: m.instanceInfo(ctx, in, p, nil), Applied: applied, AppliesNextBoot: p != nil && nextBoot, @@ -312,10 +312,10 @@ func (m *Manager) Delete(ctx context.Context, i int) (*DeleteResult, error) { return nil, err } else if running { unlock() - return nil, errs.WithDetails(errs.Newf(errs.Busy, "魔改 AVD 实例 %d 未关闭,无法删除", i), map[string]string{errs.Reason: "running"}) + return nil, errs.WithDetails(errs.Newf(errs.Busy, "ModAVD 实例 %d 未关闭,无法删除", i), map[string]string{errs.Reason: "running"}) } if len(leftovers) > 0 { - m.Log.Warnf("魔改 AVD 实例 %d 不完整(只剩:%s),可能是上次删除或新建到一半,把这些残留删掉", i, + m.Log.Warnf("ModAVD 实例 %d 不完整(只剩:%s),可能是上次删除或新建到一半,把这些残留删掉", i, strings.Join(leftovers, "、")) } if err := m.prepareDiagnosticDelete(ctx, i); err != nil { @@ -329,16 +329,16 @@ func (m *Manager) Delete(ctx context.Context, i int) (*DeleteResult, error) { // Confirm it is gone: a later create must not find a half-deleted instance under this index. if left := instanceFilesOnDisk(m.Root, i); len(left) > 0 { unlock() - return nil, errs.Newf(errs.Internal, "魔改 AVD 实例 %d 没有删干净,还剩:%s", i, strings.Join(left, "、")). + return nil, errs.Newf(errs.Internal, "ModAVD 实例 %d 没有删干净,还剩:%s", i, strings.Join(left, "、")). WithAdvice(fmt.Sprintf("关掉占用这些文件的程序后再运行一次 modavd delete %d --yes,会接着删", i)) } // The lock files can only go once nobody holds them (an open file cannot be deleted). unlock() m.removeLockFiles(i) if len(leftovers) > 0 { - m.Log.Infof("已清掉魔改 AVD 实例 %d 的残留", i) + m.Log.Infof("已清掉 ModAVD 实例 %d 的残留", i) } else { - m.Log.Infof("已删除魔改 AVD 实例 %d", i) + m.Log.Infof("已删除 ModAVD 实例 %d", i) } return &DeleteResult{Index: i, Name: in.Name, Path: in.Dir}, nil } @@ -393,14 +393,14 @@ func (m *Manager) prepareDiagnosticDelete(ctx context.Context, i int) error { return err } -// tryInstanceLock takes lock kind of instance i now or fails with errs.Busy ("魔改 AVD 实例 0 正在启动,无法删除"). +// tryInstanceLock takes lock kind of instance i now or fails with errs.Busy ("ModAVD 实例 0 正在启动,无法删除"). func (m *Manager) tryInstanceLock(i int, kind, what string) (*host.FileLock, error) { l, ok, err := m.tryOperationLock(i, kind) if err != nil { return nil, err } if !ok { - return nil, errs.WithDetails(errs.Newf(errs.Busy, "魔改 AVD 实例 %d %s,无法删除", i, what), map[string]string{errs.Reason: "locked", errs.Lock: kind}) + return nil, errs.WithDetails(errs.Newf(errs.Busy, "ModAVD 实例 %d %s,无法删除", i, what), map[string]string{errs.Reason: "locked", errs.Lock: kind}) } return l, nil } diff --git a/internal/emu/crud_test.go b/internal/emu/crud_test.go index 347a539..ced75cc 100644 --- a/internal/emu/crud_test.go +++ b/internal/emu/crud_test.go @@ -76,7 +76,7 @@ func TestDeleteHalfInstances(t *testing.T) { t.Fatalf("explicit create on leftovers: %v", err) } deleted("directory without config.ini", 0) - if !strings.Contains(strings.Join(logs.Messages(), "\n"), "魔改 AVD 实例 0 不完整(只剩:") { + if !strings.Contains(strings.Join(logs.Messages(), "\n"), "ModAVD 实例 0 不完整(只剩:") { t.Errorf("leftovers not reported: %q", logs.Messages()) } create(0) // the index is usable again diff --git a/internal/emu/disk.go b/internal/emu/disk.go index 59eb7a0..4e8511f 100644 --- a/internal/emu/disk.go +++ b/internal/emu/disk.go @@ -96,14 +96,14 @@ func (m *Manager) DiskTrim(ctx context.Context, i int) (*DiskTrimResult, error) return nil, err } else if !running { return nil, errs.Newf(errs.Unsupported, - "魔改 AVD 实例 %d 没有在运行,请先开机再回收磁盘空间", i) + "ModAVD 实例 %d 没有在运行,请先开机再回收磁盘空间", i) } if !m.bootCompleted(ctx, i, statusAdbTimeout, true) { if err := ctxErr(ctx); err != nil { return nil, err } return nil, errs.Newf(errs.Unsupported, - "魔改 AVD 实例 %d 还没开机完成,请开机后再回收磁盘空间", i) + "ModAVD 实例 %d 还没开机完成,请开机后再回收磁盘空间", i) } // Gate on the emulator actually advertising discard on /data: an old build @@ -115,7 +115,7 @@ func (m *Manager) DiskTrim(ctx context.Context, i int) (*DiskTrimResult, error) if !ok || maxBytes <= 0 { return nil, errs.Newf(errs.Unsupported, "这个模拟器版本不支持回收磁盘空间(客体数据盘没有 discard)"). - WithAdvice("请把魔改 AVD 更新到带磁盘回收的版本,实例和游戏数据不受影响") + WithAdvice("请把 ModAVD 更新到带磁盘回收的版本,实例和游戏数据不受影响") } // vold idle maintenance runs fstrim on the mounted file systems. (The exact @@ -463,9 +463,9 @@ func (m *Manager) lockInstanceForCompact(i int) (func(), error) { if err := m.compactBusy(i); err != nil { return nil, err } - return nil, errs.WithDetails(errs.Newf(errs.Busy, "魔改 AVD 实例 %d 的磁盘状态正在读取,请稍后再整理", i), map[string]string{errs.Reason: "locked", errs.Lock: "disk"}) + return nil, errs.WithDetails(errs.Newf(errs.Busy, "ModAVD 实例 %d 的磁盘状态正在读取,请稍后再整理", i), map[string]string{errs.Reason: "locked", errs.Lock: "disk"}) } - return nil, errs.WithDetails(errs.Newf(errs.Busy, "魔改 AVD 实例 %d %s,无法整理磁盘", i, kw.what), map[string]string{errs.Reason: "locked", errs.Lock: kw.kind}) + return nil, errs.WithDetails(errs.Newf(errs.Busy, "ModAVD 实例 %d %s,无法整理磁盘", i, kw.what), map[string]string{errs.Reason: "locked", errs.Lock: kw.kind}) } locks = append(locks, l) } @@ -714,7 +714,7 @@ func (m *Manager) DiskCompact(ctx context.Context, i int) (*DiskCompactResult, e if _, running, err := m.qemuOf(i); err != nil { return nil, err } else if running { - return nil, errs.WithDetails(errs.Newf(errs.Busy, "魔改 AVD 实例 %d 未关闭,无法整理磁盘", i). + return nil, errs.WithDetails(errs.Newf(errs.Busy, "ModAVD 实例 %d 未关闭,无法整理磁盘", i). WithAdvice(fmt.Sprintf("先 modavd stop %d,关机后再整理", i)), map[string]string{errs.Reason: "running"}) } if err := ctxErr(ctx); err != nil { @@ -770,7 +770,7 @@ func (m *Manager) DiskCompact(ctx context.Context, i int) (*DiskCompactResult, e return nil, err } if estimate != nil && *estimate < threshold { - m.Log.Infof("魔改 AVD 实例 %d 预计可回收 %d 字节,低于 %d 字节,跳过磁盘重写", i, *estimate, threshold) + m.Log.Infof("ModAVD 实例 %d 预计可回收 %d 字节,低于 %d 字节,跳过磁盘重写", i, *estimate, threshold) return compactResult(i, overlay, before, before, estimate, threshold, true), nil } // Without an allocation count, reserve for the complete virtual image and @@ -834,6 +834,6 @@ func (m *Manager) DiskCompact(ctx context.Context, i int) (*DiskCompactResult, e return nil, err } - m.Log.Infof("魔改 AVD 实例 %d 整理磁盘完成:占用 %s → %s", i, gib(before), gib(after)) + m.Log.Infof("ModAVD 实例 %d 整理磁盘完成:占用 %s → %s", i, gib(before), gib(after)) return compactResult(i, overlay, before, after, estimate, threshold, false), nil } diff --git a/internal/emu/disk_lock.go b/internal/emu/disk_lock.go index a3755f3..9240d5f 100644 --- a/internal/emu/disk_lock.go +++ b/internal/emu/disk_lock.go @@ -14,7 +14,7 @@ func (m *Manager) compactBusy(i int) error { return errs.Wrap(errs.Internal, err, "实例磁盘锁文件打不开: "+m.lockPath(i, "disk")) } if held { - return errs.WithDetails(errs.Newf(errs.Busy, "魔改 AVD 实例 %d 正在整理磁盘,请等整理结束后重试", i), map[string]string{errs.Reason: "locked", errs.Lock: "disk"}) + return errs.WithDetails(errs.Newf(errs.Busy, "ModAVD 实例 %d 正在整理磁盘,请等整理结束后重试", i), map[string]string{errs.Reason: "locked", errs.Lock: "disk"}) } return nil } diff --git a/internal/emu/firstboot.go b/internal/emu/firstboot.go index 988045b..c52211e 100644 --- a/internal/emu/firstboot.go +++ b/internal/emu/firstboot.go @@ -79,7 +79,7 @@ var debloatPackages = []string{ // Bluetooth off, no immersive-mode hint, phone apps disabled, the light launcher, the renderer. A failed item leaves // initialized=false and the next boot tries again. func (m *Manager) firstBootInit(ctx context.Context, i int) { - m.Log.Infof("魔改 AVD 实例 %d 首次开机,正在初始化", i) + m.Log.Infof("ModAVD 实例 %d 首次开机,正在初始化", i) var failures []string // Wi-Fi is not turned off here: every boot turns it on with the fastpath (setupNetwork) @@ -105,7 +105,7 @@ func (m *Manager) firstBootInit(ctx context.Context, i int) { } software := strings.Contains(strings.ToLower(renderer), "swiftshader") if software { - m.Log.Warnf("魔改 AVD 实例 %d 正在用软件渲染(%s):没有可用的显卡驱动,游戏会占满 CPU,请更新显卡驱动", i, renderer) + m.Log.Warnf("ModAVD 实例 %d 正在用软件渲染(%s):没有可用的显卡驱动,游戏会占满 CPU,请更新显卡驱动", i, renderer) } if ctx.Err() != nil { // the commands above were cut short: do not record a half run, the next boot does it again @@ -113,12 +113,12 @@ func (m *Manager) firstBootInit(ctx context.Context, i int) { } if err := m.writeInitMeta(i, len(failures) == 0, launcher, renderer, software, failures); err != nil { - m.Log.Warnf("魔改 AVD 实例 %d 初始化结果没写进 mas-avd.json,下次开机重做: %v", i, err) + m.Log.Warnf("ModAVD 实例 %d 初始化结果没写进 mas-avd.json,下次开机重做: %v", i, err) } if len(failures) > 0 { - m.Log.Warnf("魔改 AVD 实例 %d 初始化有失败项,下次开机重试: %s", i, pyList(failures)) + m.Log.Warnf("ModAVD 实例 %d 初始化有失败项,下次开机重试: %s", i, pyList(failures)) } else { - m.Log.Infof("魔改 AVD 实例 %d 初始化完成(桌面: %s)", i, launcher) + m.Log.Infof("ModAVD 实例 %d 初始化完成(桌面: %s)", i, launcher) } } diff --git a/internal/emu/install.go b/internal/emu/install.go index 71bfd73..eb7046a 100644 --- a/internal/emu/install.go +++ b/internal/emu/install.go @@ -59,10 +59,10 @@ func (m *Manager) InstallAPK(ctx context.Context, i int, apkPath string) (*Insta if err := ctxErr(ctx); err != nil { return nil, err } - return nil, errs.Newf(errs.Unsupported, "魔改 AVD 实例 %d 没有开机,请先开机再安装 APK", i) + return nil, errs.Newf(errs.Unsupported, "ModAVD 实例 %d 没有开机,请先开机再安装 APK", i) } - m.Log.Infof("魔改 AVD 实例 %d 安装 APK: %s", i, path) + m.Log.Infof("ModAVD 实例 %d 安装 APK: %s", i, path) res := m.ADB.Run(ctx, adb.RunOptions{Serial: m.Root.Ports().Serial(i), Timeout: apkInstallTimeout, Reregister: true}, "install", "-r", path) // The guest is done with the install: a waiting start may restart zygote now (reading the manifest below is local). @@ -72,14 +72,14 @@ func (m *Manager) InstallAPK(ctx context.Context, i int, apkPath string) (*Insta } last := installResultLine(res.Out) if res.Code != 0 || !strings.HasPrefix(last, "Success") { - m.Log.Warnf("魔改 AVD 实例 %d 安装 %s 失败: %s", i, name, res.Out) + m.Log.Warnf("ModAVD 实例 %d 安装 %s 失败: %s", i, name, res.Out) why := last if why == "" { why = "adb 返回 " + strconv.Itoa(res.Code) } return nil, errs.Newf(errs.Internal, "安装 %s 失败:%s", name, why) } - m.Log.Infof("魔改 AVD 实例 %d 已安装 %s", i, name) + m.Log.Infof("ModAVD 实例 %d 已安装 %s", i, name) out := &InstallResult{Index: i, APK: path, Output: last} if man, err := apk.ReadManifest(path); err == nil && man != nil { diff --git a/internal/emu/launch.go b/internal/emu/launch.go index b4482a8..0a54c53 100644 --- a/internal/emu/launch.go +++ b/internal/emu/launch.go @@ -120,10 +120,10 @@ func (m *Manager) launchPlanFor(ctx context.Context, inst *avd.Instance, memoryM port := m.Root.Ports().Console(i) busy, err := host.BusyPorts([]int{port, port + 1, port + 2}) if err != nil { - return nil, errs.Wrap(errs.Internal, err, fmt.Sprintf("魔改 AVD 实例 %d 读不出系统的 TCP 监听表: %v", i, err)) + return nil, errs.Wrap(errs.Internal, err, fmt.Sprintf("ModAVD 实例 %d 读不出系统的 TCP 监听表: %v", i, err)) } if len(busy) > 0 { - return nil, errs.WithDetails(errs.Newf(errs.Busy, "魔改 AVD 实例 %d 要用的端口 %s 已被占用,请先关闭占用它们的程序", + return nil, errs.WithDetails(errs.Newf(errs.Busy, "ModAVD 实例 %d 要用的端口 %s 已被占用,请先关闭占用它们的程序", i, joinInts(busy, ", ")), map[string]string{errs.Reason: "port_in_use"}) } @@ -166,7 +166,7 @@ func (m *Manager) launchPlanFor(ctx context.Context, inst *avd.Instance, memoryM if n, ok := inst.CPU(); ok { cpu = strconv.Itoa(n) } - m.Log.Infof("启动魔改 AVD 实例 %d(%s,%dp %d Hz,%d MB / %s 核,气球开,不带声卡,ANDROID_EMU_VK_HIDE_REBAR=%s): emulator %s", + m.Log.Infof("启动 ModAVD 实例 %d(%s,%dp %d Hz,%d MB / %s 核,气球开,不带声卡,ANDROID_EMU_VK_HIDE_REBAR=%s): emulator %s", i, mode, inst.Resolution(), inst.FPS(), memoryMB, cpu, hideRebar, strings.Join(args, " ")) return &launchPlan{args: args, logPath: logPath, memoryMB: memoryMB}, nil } @@ -212,7 +212,7 @@ func otherRootQemu(q host.Process, cmdline []string, i, console int, ours func(h // otherRootBusy is the error of a start whose ports the same-numbered instance of another root holds. func otherRootBusy(i int, p host.Process, where string) *errs.Error { - return errs.WithDetails(errs.Newf(errs.Busy, "魔改 AVD 实例 %d 的端口被另一个根目录的同编号实例占用(pid %d,%s)", i, p.PID, where). + return errs.WithDetails(errs.Newf(errs.Busy, "ModAVD 实例 %d 的端口被另一个根目录的同编号实例占用(pid %d,%s)", i, p.PID, where). WithAdvice("先在那个根目录把它关掉再启动"), map[string]string{errs.Reason: "port_other_root"}) } @@ -272,7 +272,7 @@ func (m *Manager) startEmulator(i int, plan *launchPlan) (host.Process, error) { }) if err != nil { return host.Process{}, errs.Wrap(errs.LaunchFailed, err, - fmt.Sprintf("魔改 AVD 实例 %d 启动失败(%s 没能运行): %v", i, root.CurrentPlatform().Emulator, err)) + fmt.Sprintf("ModAVD 实例 %d 启动失败(%s 没能运行): %v", i, root.CurrentPlatform().Emulator, err)) } return p, nil } diff --git a/internal/emu/launch_test.go b/internal/emu/launch_test.go index 8bb65c0..d530af2 100644 --- a/internal/emu/launch_test.go +++ b/internal/emu/launch_test.go @@ -194,7 +194,7 @@ func TestOtherRootBusy(t *testing.T) { if errs.DetailsOf(err)[errs.Reason] != "port_other_root" { t.Errorf("details: %v", errs.DetailsOf(err)) } - if err.Code != errs.Busy || err.Message != `魔改 AVD 实例 3 的端口被另一个根目录的同编号实例占用(pid 4242,D:\ModAVD\avd\mas_3.avd)` || + if err.Code != errs.Busy || err.Message != `ModAVD 实例 3 的端口被另一个根目录的同编号实例占用(pid 4242,D:\ModAVD\avd\mas_3.avd)` || err.Advice == "" { t.Errorf("otherRootBusy = %+v", err) } diff --git a/internal/emu/playstore.go b/internal/emu/playstore.go index 3c23b69..d89f398 100644 --- a/internal/emu/playstore.go +++ b/internal/emu/playstore.go @@ -368,7 +368,7 @@ func (m *Manager) playStoreLock(i int) (*host.FileLock, error) { return nil, err } if !ok { - return nil, errs.WithDetails(errs.Newf(errs.Busy, "魔改 AVD 实例 %d 正在装卸执行桥、Google Play 商店或改 GLES 3.2 开关,稍后再试", i), + return nil, errs.WithDetails(errs.Newf(errs.Busy, "ModAVD 实例 %d 正在装卸执行桥、Google Play 商店或改 GLES 3.2 开关,稍后再试", i), map[string]string{errs.Reason: "locked", errs.Lock: "bridge"}) } return lock, nil diff --git a/internal/emu/start.go b/internal/emu/start.go index a00947e..4fe9ffa 100644 --- a/internal/emu/start.go +++ b/internal/emu/start.go @@ -224,7 +224,7 @@ func (m *Manager) start(ctx context.Context, inst *avd.Instance, opt StartOption } } if running { - m.Log.Infof("魔改 AVD 实例 %d 已在运行(pid %d)", i, p.PID) + m.Log.Infof("ModAVD 实例 %d 已在运行(pid %d)", i, p.PID) prog.emit("launch", fmt.Sprintf("实例 %d 已在运行(pid %d),不重新开机", i, p.PID), progressLaunch) adopted, adoptedAt = &p, time.Now() mk, ok := m.readSetupMarker(i) @@ -317,7 +317,7 @@ func (m *Manager) start(ctx context.Context, inst *avd.Instance, opt StartOption if relaunchAfterAdoptedGone(round, opt.watchQemu != nil, err, time.Since(adoptedAt), stopSeen) { // Most likely a guest that was powering off and no longer answered adb, so guestShuttingDown could not // tell: boot the instance as asked. Its setup marker, if any, names a boot that is over now. - m.Log.Infof("魔改 AVD 实例 %d 接管的模拟器(pid %d)没等安卓开机完成就退出了(多半是正在关机),重新开机", + m.Log.Infof("ModAVD 实例 %d 接管的模拟器(pid %d)没等安卓开机完成就退出了(多半是正在关机),重新开机", i, adopted.PID) continue } @@ -373,7 +373,7 @@ func (m *Manager) start(ctx context.Context, inst *avd.Instance, opt StartOption m.removeSetupMarker(i) } if gone { - return nil, errs.Newf(errs.LaunchFailed, "魔改 AVD 实例 %d 在开机后设置期间退出了(模拟器 pid %d):%s", i, + return nil, errs.Newf(errs.LaunchFailed, "ModAVD 实例 %d 在开机后设置期间退出了(模拟器 pid %d):%s", i, qemu.PID, orText(logTail(res.LogFile, 8), "日志见 "+m.Root.LogsDir())) } // Callers write to /sdcard right after start (10-31 measurements): it is not there yet at sys.boot_completed, @@ -468,7 +468,7 @@ func (m *Manager) waitBoot(ctx context.Context, i int, timeout time.Duration, em return host.Process{}, err } if !time.Now().Before(deadline) { - return host.Process{}, errs.Newf(errs.Timeout, "魔改 AVD 实例 %d 启动超时(%.0f 秒内安卓没有启动完成),日志见 %s", + return host.Process{}, errs.Newf(errs.Timeout, "ModAVD 实例 %d 启动超时(%.0f 秒内安卓没有启动完成),日志见 %s", i, timeout.Seconds(), m.Root.LogsDir()) } if !found && emulator != nil && !emulator.Alive() { @@ -476,7 +476,7 @@ func (m *Manager) waitBoot(ctx context.Context, i int, timeout time.Duration, em if c, ok := emulator.ExitCode(); ok { code = strconv.FormatUint(uint64(c), 10) } - return host.Process{}, errs.Newf(errs.LaunchFailed, "魔改 AVD 实例 %d 启动失败(emulator.exe 退出码 %s):%s", + return host.Process{}, errs.Newf(errs.LaunchFailed, "ModAVD 实例 %d 启动失败(emulator.exe 退出码 %s):%s", i, code, logTail(logPath, 8)) } if adopted != nil && stopSeen != nil && !*stopSeen && m.lockHeld(i, "stop") { @@ -485,7 +485,7 @@ func (m *Manager) waitBoot(ctx context.Context, i int, timeout time.Duration, em // both the process snapshot and the PID + creation time check must agree, so a failed snapshot is no exit if !found && adopted != nil && !adopted.Alive() { return host.Process{}, errs.Wrap(errs.LaunchFailed, errAdoptedGone, - fmt.Sprintf("魔改 AVD 实例 %d 的模拟器(pid %d)在等安卓开机时退出了", i, adopted.PID)) + fmt.Sprintf("ModAVD 实例 %d 的模拟器(pid %d)在等安卓开机时退出了", i, adopted.PID)) } if now := time.Now(); !now.Before(nextReport) { elapsed := now.Sub(started) @@ -551,13 +551,13 @@ func poweringOff(v string) bool { // scans for the instance's qemu again: found when someone launched it meanwhile (the start adopts that one). Busy when // p is still there at the end. func (m *Manager) waitShutdown(ctx context.Context, i int, p host.Process, prog *progressor) (host.Process, bool, error) { - m.Log.Infof("魔改 AVD 实例 %d 正在关机(模拟器 pid %d 还没退出),等它关完再开机", i, p.PID) + m.Log.Infof("ModAVD 实例 %d 正在关机(模拟器 pid %d 还没退出),等它关完再开机", i, p.PID) prog.emit("launch", fmt.Sprintf("实例 %d 正在关机,等它关完再开机", i), progressLaunch/2) if !waitQemuExit(ctx, p, shutdownExitWait) { if err := ctxErr(ctx); err != nil { return host.Process{}, false, err } - return host.Process{}, false, errs.WithDetails(errs.Newf(errs.Busy, "魔改 AVD 实例 %d 正在关机,等了 %.0f 秒模拟器(pid %d)还没退出", i, + return host.Process{}, false, errs.WithDetails(errs.Newf(errs.Busy, "ModAVD 实例 %d 正在关机,等了 %.0f 秒模拟器(pid %d)还没退出", i, shutdownExitWait.Seconds(), p.PID).WithAdvice(fmt.Sprintf("稍后再开机;一直关不掉的话先 modavd stop %d", i)), map[string]string{errs.Reason: "stopping"}) } return m.findQemu(i) diff --git a/internal/emu/stop.go b/internal/emu/stop.go index 01534a6..933ee5c 100644 --- a/internal/emu/stop.go +++ b/internal/emu/stop.go @@ -108,7 +108,7 @@ func (m *Manager) Stop(ctx context.Context, i int, opt StopOptions) (*StopResult state, _, _ := mm.creation(i) creating := state == creationCreating && !opt.creating if creating && !opt.CancelCreate { - return nil, errs.WithDetails(errs.Newf(errs.Busy, "魔改 AVD 实例 %d 正在新建(后台开机做初始化),不能关机", i). + return nil, errs.WithDetails(errs.Newf(errs.Busy, "ModAVD 实例 %d 正在新建(后台开机做初始化),不能关机", i). WithAdvice(fmt.Sprintf("等新建做完;进度用 modavd status 查看;确实要打断请用 modavd stop %d --cancel-create", i)), map[string]string{errs.Reason: "locked", errs.Lock: "create"}) } if creating { @@ -130,7 +130,7 @@ func (m *Manager) Stop(ctx context.Context, i int, opt StopOptions) (*StopResult // already_offline would be a success the start then overrides by booting the instance. Wait a little for its // qemu, still holding the stop lock: a start that has not got past its stop-lock check yet then cannot launch // before this stop is over, and no other stop can get in between (see the header comment). - mm.Log.Infof("魔改 AVD 实例 %d 正在开机,等模拟器起来再关(最多 %.0f 秒)", i, startingQemuWait.Seconds()) + mm.Log.Infof("ModAVD 实例 %d 正在开机,等模拟器起来再关(最多 %.0f 秒)", i, startingQemuWait.Seconds()) var found, starting bool p, found, starting, err = waitStartingQemu(ctx, startingQemuWait, startingQemuPoll, func() (host.Process, bool, error) { return mm.qemuOf(i) }, func() bool { return mm.lockHeld(i, "start") }) @@ -138,7 +138,7 @@ func (m *Manager) Stop(ctx context.Context, i int, opt StopOptions) (*StopResult return nil, err } if !found && starting { - return nil, errs.WithDetails(errs.Newf(errs.Busy, "魔改 AVD 实例 %d 正在开机,模拟器还没起来,稍后再关", i). + return nil, errs.WithDetails(errs.Newf(errs.Busy, "ModAVD 实例 %d 正在开机,模拟器还没起来,稍后再关", i). WithAdvice("开机前的检查(硬件加速、Vulkan 等)可能要一两分钟"), map[string]string{errs.Reason: "starting"}) } ok = found @@ -147,7 +147,7 @@ func (m *Manager) Stop(ctx context.Context, i int, opt StopOptions) (*StopResult // path, sync included, even if that runs past the budget. launching = found && justLaunched(p, started, mm.booting(i)) if found && !launching { - mm.Log.Warnf("魔改 AVD 实例 %d 等开机时找到的模拟器不是刚拉起的(pid %d),按正常关机处理", i, p.PID) + mm.Log.Warnf("ModAVD 实例 %d 等开机时找到的模拟器不是刚拉起的(pid %d),按正常关机处理", i, p.PID) } } if !ok { @@ -278,12 +278,12 @@ func runStop(ctx context.Context, log *logx.Logger, i int, force bool, started t if err := ops.forceKill(forceKillWait); err != nil { return "force", synced, err } - log.Infof("魔改 AVD 实例 %d 已强制关闭", i) + log.Infof("ModAVD 实例 %d 已强制关闭", i) return "force", synced, nil } if problem != "" { - log.Warnf("魔改 AVD 实例 %d 私有 adb 用不了,不能正常关机也不能 sync,直接用控制台关: %s", i, problem) + log.Warnf("ModAVD 实例 %d 私有 adb 用不了,不能正常关机也不能 sync,直接用控制台关: %s", i, problem) return endQemu(ctx, log, i, "console_kill", false, consoleKillTimeout+closeTimeout, forceKillWait, ops) } // The foreground app goes home first and gets homeWait; the sync below takes what it wrote along (see the header @@ -298,13 +298,13 @@ func runStop(ctx context.Context, log *logx.Logger, i int, force bool, started t } reason := ops.graceful(gracefulWindow(time.Since(started))) if reason == "" { - log.Infof("魔改 AVD 实例 %d 正常关机完成(%.1f s)", i, time.Since(started).Seconds()) + log.Infof("ModAVD 实例 %d 正常关机完成(%.1f s)", i, time.Since(started).Seconds()) return "graceful", true, nil } if err := stopCanceled(ctx, i); err != nil { return "graceful", false, err } - log.Warnf("魔改 AVD 实例 %d 正常关机没成(%s),退回 sync + 控制台 kill", i, reason) + log.Warnf("ModAVD 实例 %d 正常关机没成(%s),退回 sync + 控制台 kill", i, reason) synced := syncBeforeKill(log, i, "", fallbackSyncTimeout, ops.sync) return endQemu(ctx, log, i, "sync_kill", presynced || synced, fallbackKillTimeout(time.Since(started)), fallbackForceKillWait, ops) @@ -315,13 +315,13 @@ func runStop(ctx context.Context, log *logx.Logger, i int, force bool, started t func sendHome(ctx context.Context, log *logx.Logger, i int, home func(time.Duration) (bool, string)) error { sent, failure := home(homeTimeout) if failure != "" { - log.Warnf("魔改 AVD 实例 %d 关机前按 HOME 失败,照常关机: %s", i, failure) + log.Warnf("ModAVD 实例 %d 关机前按 HOME 失败,照常关机: %s", i, failure) return nil } if !sent { return nil } - log.Infof("魔改 AVD 实例 %d 前台的应用已退到后台,等 %.0f 秒让它保存再关机", i, homeWait.Seconds()) + log.Infof("ModAVD 实例 %d 前台的应用已退到后台,等 %.0f 秒让它保存再关机", i, homeWait.Seconds()) select { case <-ctx.Done(): return stopCanceled(ctx, i) @@ -336,9 +336,9 @@ func syncBeforeShutdown(log *logx.Logger, i int, sync func(time.Duration) (bool, started := time.Now() ok, output := sync(shutdownSyncTimeout) if ok { - log.Debugf("魔改 AVD 实例 %d 发关机命令前 sync 完成(%.0f ms)", i, float64(time.Since(started).Microseconds())/1000) + log.Debugf("ModAVD 实例 %d 发关机命令前 sync 完成(%.0f ms)", i, float64(time.Since(started).Microseconds())/1000) } else { - log.Warnf("魔改 AVD 实例 %d 发关机命令前 sync 失败,照常关机: %s", i, output) + log.Warnf("ModAVD 实例 %d 发关机命令前 sync 失败,照常关机: %s", i, output) } return ok } @@ -348,7 +348,7 @@ func syncBeforeShutdown(log *logx.Logger, i int, sync func(time.Duration) (bool, // name, not console_kill: that one means the private adb of a booted guest was unusable and data may be lost; here // there is no guest data yet), never synced. func runLaunchingStop(ctx context.Context, log *logx.Logger, i int, killTimeout time.Duration, ops stopOps) (string, bool, error) { - log.Infof("魔改 AVD 实例 %d 的模拟器刚起来,安卓还没开机,不做正常关机和 sync,直接从控制台关", i) + log.Infof("ModAVD 实例 %d 的模拟器刚起来,安卓还没开机,不做正常关机和 sync,直接从控制台关", i) return endQemu(ctx, log, i, "launching_kill", false, killTimeout, forceKillWait, ops) } @@ -366,13 +366,13 @@ func endQemu(ctx context.Context, log *logx.Logger, i int, method string, synced if err := stopCanceled(ctx, i); err != nil { return method, synced, err } - log.Warnf("魔改 AVD 实例 %d 未在 %.0f 秒内退出,强制结束", i, killTimeout.Seconds()) + log.Warnf("ModAVD 实例 %d 未在 %.0f 秒内退出,强制结束", i, killTimeout.Seconds()) method += "+terminate" if err := ops.forceKill(forceWait); err != nil { return method, synced, err } } - log.Infof("魔改 AVD 实例 %d 已关闭", i) + log.Infof("ModAVD 实例 %d 已关闭", i) return method, synced, nil } @@ -385,9 +385,9 @@ func syncBeforeKill(log *logx.Logger, i int, problem string, timeout time.Durati ok, output = sync(timeout) } if ok { - log.Infof("魔改 AVD 实例 %d 关机前 sync 完成(%.0f ms)", i, float64(time.Since(started).Microseconds())/1000) + log.Infof("ModAVD 实例 %d 关机前 sync 完成(%.0f ms)", i, float64(time.Since(started).Microseconds())/1000) } else { - log.Warnf("魔改 AVD 实例 %d 关机前 sync 失败,照常关机: %s", i, output) + log.Warnf("ModAVD 实例 %d 关机前 sync 失败,照常关机: %s", i, output) } return ok } @@ -508,7 +508,7 @@ func (q qemuKill) run(ctx context.Context, log *logx.Logger, i int, pid uint32, } log.Debugf("结束实例 %d 的 qemu(pid %d)时 Windows 答复: %v(它已经在退出)", i, pid, killErr) } - log.Warnf("魔改 AVD 实例 %d 的 qemu(pid %d)已强制结束,还在退出(等了 %.0f 秒);稍后用 modavd status %d 确认它已退出", + log.Warnf("ModAVD 实例 %d 的 qemu(pid %d)已强制结束,还在退出(等了 %.0f 秒);稍后用 modavd status %d 确认它已退出", i, pid, wait.Seconds(), i) return nil } @@ -524,7 +524,7 @@ func terminateRefused(p host.Process) bool { // qemuNotEnded is the error of a stop after which qemu pid still runs because Windows refused to terminate it // (killErr). func qemuNotEnded(i int, pid uint32, killErr error) error { - return errs.Wrap(errs.Internal, killErr, fmt.Sprintf("魔改 AVD 实例 %d 的 qemu(pid %d)没能结束:%v", i, pid, killErr)). + return errs.Wrap(errs.Internal, killErr, fmt.Sprintf("ModAVD 实例 %d 的 qemu(pid %d)没能结束:%v", i, pid, killErr)). WithAdvice("它可能是以管理员身份启动的(例如 AUTO-MAS 以管理员身份运行时);用管理员权限再关一次,或在任务管理器里结束它") } diff --git a/internal/emu/stop_test.go b/internal/emu/stop_test.go index 1cdfbc5..562633d 100644 --- a/internal/emu/stop_test.go +++ b/internal/emu/stop_test.go @@ -173,7 +173,7 @@ func TestRunStopSendsAppHome(t *testing.T) { f = &stopFake{homeFailure: "返回码 1: error: closed", syncOK: true} method, _, err, warns = runStopFake(t, context.Background(), false, f) if err != nil || method != "graceful" || len(warns) != 1 || - warns[0] != "魔改 AVD 实例 3 关机前按 HOME 失败,照常关机: 返回码 1: error: closed" || + warns[0] != "ModAVD 实例 3 关机前按 HOME 失败,照常关机: 返回码 1: error: closed" || f.at["sync"].Sub(f.at["home"]) >= homeWait { t.Fatalf("failed: %s %v %q", method, err, warns) } @@ -196,7 +196,7 @@ func TestRunStopSyncBeforeShutdownFails(t *testing.T) { if got := strings.Join(f.calls, ","); got != "prepare,home,sync,graceful" { t.Fatalf("calls = %s", got) } - if len(warns) != 1 || warns[0] != "魔改 AVD 实例 3 发关机命令前 sync 失败,照常关机: error: closed" { + if len(warns) != 1 || warns[0] != "ModAVD 实例 3 发关机命令前 sync 失败,照常关机: error: closed" { t.Fatalf("warnings = %q", warns) } } @@ -218,7 +218,7 @@ func TestRunStopFallbackSyncKill(t *testing.T) { if want := stopBudget - gracefulDeadline - fallbackForceKillWait; f.killTimeout > want || f.killTimeout < want-time.Second { t.Fatalf("kill timeout %v, want about %v", f.killTimeout, want) } - if len(warns) != 1 || warns[0] != "魔改 AVD 实例 3 正常关机没成(24 秒内没有自己退出),退回 sync + 控制台 kill" { + if len(warns) != 1 || warns[0] != "ModAVD 实例 3 正常关机没成(24 秒内没有自己退出),退回 sync + 控制台 kill" { t.Fatalf("warnings = %q", warns) } } @@ -260,7 +260,7 @@ func TestRunStopFallbackTerminate(t *testing.T) { if len(warns) != 5 || !strings.Contains(warns[0], "发关机命令前 sync 失败,照常关机: error: closed") || !strings.Contains(warns[2], "关机前 sync 失败,照常关机: error: closed") || warns[3] != "实例 3 控制台 kill 失败,改为强制结束: 连不上控制台 20030" || - warns[4] != "魔改 AVD 实例 3 未在 3 秒内退出,强制结束" { + warns[4] != "ModAVD 实例 3 未在 3 秒内退出,强制结束" { t.Fatalf("warnings = %q", warns) } } @@ -400,7 +400,7 @@ func TestRunStopConsoleOnly(t *testing.T) { if f.killTimeout != consoleKillTimeout+closeTimeout || f.forceKillFor != forceKillWait { t.Fatalf("timeouts kill %v force %v", f.killTimeout, f.forceKillFor) } - if !strings.HasPrefix(warns[0], "魔改 AVD 实例 3 私有 adb 用不了,不能正常关机也不能 sync,直接用控制台关: 私有 adb server") { + if !strings.HasPrefix(warns[0], "ModAVD 实例 3 私有 adb 用不了,不能正常关机也不能 sync,直接用控制台关: 私有 adb server") { t.Fatalf("warnings = %q", warns) } f = &stopFake{problem: "x"} @@ -496,7 +496,7 @@ func TestQemuNotEnded(t *testing.T) { cause := errors.New("Access is denied.") err := qemuNotEnded(3, 4242, cause) if errs.CodeOf(err) != errs.Internal || errs.ExitCode(err) != 1 || !errors.Is(err, cause) || - !strings.HasPrefix(err.Error(), "魔改 AVD 实例 3 的 qemu(pid 4242)没能结束:Access is denied.。") || + !strings.HasPrefix(err.Error(), "ModAVD 实例 3 的 qemu(pid 4242)没能结束:Access is denied.。") || !strings.Contains(err.Error(), "管理员") { t.Fatalf("denied: %v (%s)", err, errs.CodeOf(err)) } @@ -538,7 +538,7 @@ func (k *killScript) run(t *testing.T, ctx context.Context, wait time.Duration) func TestQemuKillRun(t *testing.T) { ctx := context.Background() denied := errors.New("结束qemu-system-x86_64.exe(PID 4242)失败: Access is denied.") - stillExiting := "魔改 AVD 实例 3 的 qemu(pid 4242)已强制结束,还在退出(等了 2 秒);稍后用 modavd status 3 确认它已退出" + stillExiting := "ModAVD 实例 3 的 qemu(pid 4242)已强制结束,还在退出(等了 2 秒);稍后用 modavd status 3 确认它已退出" cases := []struct { name string script killScript diff --git a/internal/emu/window.go b/internal/emu/window.go index a243da4..68fc5d7 100644 --- a/internal/emu/window.go +++ b/internal/emu/window.go @@ -36,10 +36,10 @@ func windowConflict(i int, opt StartOptions, windowed bool) error { const asIs = "(不指定 --window / --headless 就照原样接管)" switch { case opt.Window && !windowed: - return errs.WithDetails(errs.Newf(errs.Busy, "魔改 AVD 实例 %d 正以无头方式运行,运行中不能换成带窗口", i). + return errs.WithDetails(errs.Newf(errs.Busy, "ModAVD 实例 %d 正以无头方式运行,运行中不能换成带窗口", i). WithAdvice(fmt.Sprintf("先关机再换:modavd stop %d,再 modavd start %d --window%s", i, i, asIs)), map[string]string{errs.Reason: "window_mismatch"}) case opt.Headless && windowed: - return errs.WithDetails(errs.Newf(errs.Busy, "魔改 AVD 实例 %d 正带窗口运行,运行中不能换成无头", i). + return errs.WithDetails(errs.Newf(errs.Busy, "ModAVD 实例 %d 正带窗口运行,运行中不能换成无头", i). WithAdvice(fmt.Sprintf("先关机再换:modavd stop %d,再 modavd start %d --headless%s", i, i, asIs)), map[string]string{errs.Reason: "window_mismatch"}) } return nil @@ -79,15 +79,15 @@ func (m *Manager) SetWindowVisible(ctx context.Context, i int, visible bool) (*W if errs.CodeOf(err) == errs.Unsupported { return nil, err } - m.Log.Warnf("魔改 AVD 实例 %d %s窗口失败: %v", i, verb, err) + m.Log.Warnf("ModAVD 实例 %d %s窗口失败: %v", i, verb, err) return res, nil } res.Windows = n switch { case n > 0: - m.Log.Infof("魔改 AVD 实例 %d 已%s窗口", i, verb) + m.Log.Infof("ModAVD 实例 %d 已%s窗口", i, verb) case visible: - m.Log.Infof("魔改 AVD 实例 %d 是无头开机的,没有窗口可显示;要窗口请关机后带窗口重新启动", i) + m.Log.Infof("ModAVD 实例 %d 是无头开机的,没有窗口可显示;要窗口请关机后带窗口重新启动", i) } return res, nil } diff --git a/internal/jsonord/testdata/gen_pycases.py b/internal/jsonord/testdata/gen_pycases.py index 884ed22..7df2dec 100644 --- a/internal/jsonord/testdata/gen_pycases.py +++ b/internal/jsonord/testdata/gen_pycases.py @@ -15,7 +15,7 @@ "[]", '{"a": {}, "b": [], "c": [{}, []], "d": {"e": {"f": []}}}', '[[], {}, [[]], [{}], {"x": []}]', - '{"名称": "魔改 AVD ✓ 😀", "x": "\\u00e9\\ud83d\\ude00", "": "empty key"}', + '{"名称": "模拟器 ✓ 😀", "x": "\\u00e9\\ud83d\\ude00", "": "empty key"}', '"\\u0000\\u0001\\u001f\\u007f\\b\\f\\n\\r\\t \\u0080 \\u00a0 \\u2028 \\u2029 \\ufffd \\ufeff"', '"a\\"b\\\\c\\/d"', '{"q": "say \\"hi\\"", "p": "C:\\\\sdk-src\\\\sdk-mas35\\\\", "u": "\\u4e2d\\u6587"}', diff --git a/internal/jsonord/testdata/pycases.json b/internal/jsonord/testdata/pycases.json index 4d3f4b9..ff2e08d 100644 --- a/internal/jsonord/testdata/pycases.json +++ b/internal/jsonord/testdata/pycases.json @@ -17,8 +17,8 @@ "out": "[\n [],\n {},\n [\n []\n ],\n [\n {}\n ],\n {\n \"x\": []\n }\n]" }, { -"in": "eyLlkI3np7AiOiAi6a2U5pS5IEFWRCDinJMg8J+YgCIsICJ4IjogIlx1MDBlOVx1ZDgzZFx1ZGUwMCIsICIiOiAiZW1wdHkga2V5In0=", -"out": "{\n \"\u540d\u79f0\": \"\u9b54\u6539 AVD \u2713 \ud83d\ude00\",\n \"x\": \"\u00e9\ud83d\ude00\",\n \"\": \"empty key\"\n}" +"in": "eyLlkI3np7AiOiAi5qih5ouf5ZmoIOKckyDwn5iAIiwgIngiOiAiXHUwMGU5XHVkODNkXHVkZTAwIiwgIiI6ICJlbXB0eSBrZXkifQ==", +"out": "{\n \"\u540d\u79f0\": \"\u6a21\u62df\u5668 \u2713 \ud83d\ude00\",\n \"x\": \"\u00e9\ud83d\ude00\",\n \"\": \"empty key\"\n}" }, { "in": "Ilx1MDAwMFx1MDAwMVx1MDAxZlx1MDA3ZlxiXGZcblxyXHQgXHUwMDgwIFx1MDBhMCBcdTIwMjggXHUyMDI5IFx1ZmZmZCBcdWZlZmYi", diff --git a/internal/mcp/mcp_test.go b/internal/mcp/mcp_test.go index bda2438..d809553 100644 --- a/internal/mcp/mcp_test.go +++ b/internal/mcp/mcp_test.go @@ -102,7 +102,7 @@ func (f *fake) List(ctx context.Context) (*emu.ListResult, error) { func (f *fake) Info(ctx context.Context, i int) (*emu.InstanceInfo, error) { f.record("info %d", i) if i == 9 { - return nil, errs.Newf(errs.NotFound, "魔改 AVD 实例 %d 不存在", i).WithAdvice("先用 list_instances 看有哪些实例") + return nil, errs.Newf(errs.NotFound, "ModAVD 实例 %d 不存在", i).WithAdvice("先用 list_instances 看有哪些实例") } in := sampleInstance(i) in.Diagnostics = f.diagnostics @@ -877,7 +877,7 @@ func TestToolErrors(t *testing.T) { {"get_instance", map[string]any{"index": 3.5}, errs.Usage, "参数 index 必须是整数"}, {"get_instance", map[string]any{"index": 3, "root": `D:\ModAVD`}, errs.Usage, "不认识的参数: root"}, {"list_instances", map[string]any{"all": true}, errs.Usage, "list_instances 不接受参数"}, - {"get_instance", map[string]any{"index": 9}, errs.NotFound, "魔改 AVD 实例 9 不存在。先用 list_instances 看有哪些实例"}, + {"get_instance", map[string]any{"index": 9}, errs.NotFound, "ModAVD 实例 9 不存在。先用 list_instances 看有哪些实例"}, {"delete_instance", map[string]any{"index": 2, "confirm": false}, errs.Usage, "confirm 设为 true"}, {"delete_instance", map[string]any{"index": 2}, errs.Usage, "缺少参数 confirm"}, {"update_instance", map[string]any{"index": 2}, errs.Usage, "至少给一项"}, diff --git a/internal/report/collect.go b/internal/report/collect.go index d7e84e8..1f69f42 100644 --- a/internal/report/collect.go +++ b/internal/report/collect.go @@ -43,7 +43,7 @@ var ( const ( nativeTimeout = 20 * time.Second // Invoke-Native -TimeoutSec default accelTimeout = 30 * time.Second - collectZipStart = "魔改AVD问题信息-" + collectZipStart = "ModAVD-问题信息-" ) // CollectOptions for Collect; the first three are the script's -OutDir, -StageDir and -KeepStage. @@ -238,9 +238,9 @@ func collect(ctx context.Context, rootDir string, h Host, opt CollectOptions) (r }() c := &collector{ctx: ctx, root: rootDir, h: h, opt: opt, stage: stage, start: start, adbPort: root.DefaultAdbServerPort} - c.progress("魔改 AVD 问题信息收集") + c.progress("ModAVD 问题信息收集") c.progress("ModAVD 目录:" + rootDir) - c.L("魔改 AVD 问题信息") + c.L("ModAVD 问题信息") c.L(PrivacyNote) c.L("生成时间:" + start.Format("2006-01-02 15:04:05 -07:00")) // the script names the PowerShell that ran it here diff --git a/internal/report/config.go b/internal/report/config.go index 0592e90..5a15919 100644 --- a/internal/report/config.go +++ b/internal/report/config.go @@ -49,7 +49,7 @@ var notGames = []string{"de.jrpie.android.launcher"} var configTail = []string{"怎么用的(自己玩 / AUTO-MAS 及版本 / MAA、M9A 等脚本):", "效果(能跑 / 有问题,问题是…):"} const ( - configTitle = "【魔改 AVD 试用配置】" + configTitle = "【ModAVD 试用配置】" configNotOpen = "游戏包:没有实例开着,读不到。开着实例时再生成一次,就会列出来" emuCheckWait = 20 * time.Second clipboardOK = "已复制到剪贴板:粘贴到群里,再把最后两行补上就行。" diff --git a/internal/report/parity_windows_test.go b/internal/report/parity_windows_test.go index 53082a7..146b1c2 100644 --- a/internal/report/parity_windows_test.go +++ b/internal/report/parity_windows_test.go @@ -161,15 +161,18 @@ func modavdPrivacyHead() string { return head } -// notAllMAS: what the scripts said as if every user had AUTO-MAS, and what modavd says instead (many use ModAVD -// without it). Applied in order, to the scripts' lines. -var notAllMAS = []struct{ script, modavd string }{ +// reworded: what the scripts said that modavd says differently on purpose, applied in order to the scripts' lines: +// what they said as if every user had AUTO-MAS (many use ModAVD without it), and the old Chinese name for ModAVD +// (it is ModAVD in every language). +var reworded = []struct{ script, modavd string }{ {"提示:没找到 AUTO-MAS 安装目录,反馈时请附上 AUTO-MAS 的 debug 文件夹里的日志。", "提示:" + MasMissingNote}, {"没找到 AUTO-MAS 安装目录,反馈时请附上 AUTO-MAS 的 debug 文件夹里的日志", "没找到 AUTO-MAS 安装目录(不用 AUTO-MAS 的不用管)"}, {"(多半是 AUTO-MAS 以管理员运行)", "(多半是模拟器以管理员身份运行)"}, {"实例配置、AUTO-MAS 日志(mas 文件夹);", "实例配置;找到 AUTO-MAS 时还有它的日志(mas 文件夹);"}, {"在 AUTO-MAS 里开着实例时再双击运行一次", "开着实例时再生成一次"}, {"再把最后三行补上就行。", "再把最后两行补上就行。"}, + {"魔改AVD问题信息-", "ModAVD-问题信息-"}, + {"魔改 AVD", "ModAVD"}, } // modavdLine is what modavd writes on purpose instead of a line of collect-info.ps1's summary.txt: @@ -177,7 +180,7 @@ var notAllMAS = []struct{ script, modavd string }{ // - the adb.exe the live section runs: modavd speaks the adb host protocol itself (no adb.exe, never a server of // its own), to the server that listens on the port; // - the first line of the privacy note: who does not upload is the manager or the CLI, not a script; -// - notAllMAS. +// - reworded. func (f *fixture) modavdLine(line string) string { if line == "PowerShell:{{PSVERSION}}" { return "modavd:" + buildinfo.Version + "(" + runtime.Version() + ")" @@ -185,7 +188,7 @@ func (f *fixture) modavdLine(line string) string { if line == scriptPrivacyHead { return modavdPrivacyHead() } - for _, r := range notAllMAS { + for _, r := range reworded { line = strings.Replace(line, r.script, r.modavd, 1) } if strings.HasPrefix(line, "adb:") && strings.Contains(line, " -P "+strconv.Itoa(f.adbPort)+"(") { @@ -383,13 +386,13 @@ func TestCollectMatchesScript(t *testing.T) { // the end of the console output: zip path, the privacy note word for word but for modavdLine's console, _ := f.golden(t, name, "collect-console.txt") - if !containsLine(lines(console), "文件:"+res.ZipPath) { - t.Errorf("zip %s, the script printed:\n%s", res.ZipPath, console) - } var consoleLines []string for _, l := range lines(console) { consoleLines = append(consoleLines, f.modavdLine(l)) } + if !containsLine(consoleLines, "文件:"+res.ZipPath) { + t.Errorf("zip %s, the script printed:\n%s", res.ZipPath, console) + } if !strings.Contains(strings.Join(consoleLines, "\r\n"), PrivacyNote) || res.PrivacyNote != PrivacyNote { t.Error("the privacy note is not the one collect-info.ps1 prints, but for modavdLine's") } diff --git a/internal/root/root.go b/internal/root/root.go index 3b8e21c..3ffd991 100644 --- a/internal/root/root.go +++ b/internal/root/root.go @@ -254,10 +254,10 @@ func Resolve(flag string) (*Root, error) { func resolve(flag, env, exe string) (*Root, error) { if s := cleanArg(flag); s != "" { - return openDir(s, "--root 指定的") + return openDir(s, "--root 指定的 ") } if s := cleanArg(env); s != "" { - return openDir(s, "环境变量 "+EnvRoot+" 指定的") + return openDir(s, "环境变量 "+EnvRoot+" 指定的 ") } if exe != "" { dir := filepath.Dir(exe) @@ -267,7 +267,7 @@ func resolve(flag, env, exe string) (*Root, error) { } } } - return nil, errs.New(errs.Usage, "找不到魔改 AVD 根目录").WithAdvice( + return nil, errs.New(errs.Usage, "找不到 ModAVD 根目录").WithAdvice( "用 --root 指定根目录(里面有 sdk 文件夹和 mas-avd.json),或设置环境变量 " + EnvRoot + ";modavd.exe 放在根目录或根目录的 tools 文件夹里时会自动找到") } @@ -287,14 +287,14 @@ func looksLikeRoot(dir string) bool { func openDir(dir, what string) (*Root, error) { abs, err := filepath.Abs(dir) if err != nil { - return nil, errs.Wrap(errs.Usage, err, fmt.Sprintf("%s魔改 AVD 根目录写法不对: %s", what, dir)) + return nil, errs.Wrap(errs.Usage, err, fmt.Sprintf("%sModAVD 根目录写法不对: %s", what, dir)) } fi, err := os.Stat(abs) if err != nil { - return nil, errs.Wrap(errs.NotFound, err, fmt.Sprintf("%s魔改 AVD 根目录不存在: %s", what, abs)) + return nil, errs.Wrap(errs.NotFound, err, fmt.Sprintf("%sModAVD 根目录不存在: %s", what, abs)) } if !fi.IsDir() { - return nil, errs.Newf(errs.NotFound, "%s魔改 AVD 根目录不是文件夹: %s", what, abs) + return nil, errs.Newf(errs.NotFound, "%sModAVD 根目录不是文件夹: %s", what, abs) } return &Root{Dir: abs}, nil } @@ -345,7 +345,7 @@ func (r *Root) QemuImgExe() (string, error) { exe := filepath.Join(r.RuntimeSDK(), "emulator", "qemu-img.exe") if fi, err := os.Stat(exe); err != nil || fi.IsDir() { return exe, errs.Newf(errs.NotReady, "找不到 qemu-img: %s", exe). - WithAdvice("魔改 AVD 的模拟器组件不完整,请更新组件后再试") + WithAdvice("ModAVD 的模拟器组件不完整,请更新组件后再试") } return exe, nil } @@ -677,7 +677,7 @@ func (r *Root) LockInstanceConfig(i int) (*InstanceLock, error) { return nil, errs.Wrap(errs.Internal, err, fmt.Sprintf("实例 %s 的锁文件打不开: %s(%v)", AvdName(i), path, err)) } if !ok { - return nil, errs.WithDetails(errs.Newf(errs.Busy, "魔改 AVD 实例 %d 正被另一个 modavd 改动(新建、改设置或删除),等了 %.0f 秒仍没改完", + return nil, errs.WithDetails(errs.Newf(errs.Busy, "ModAVD 实例 %d 正被另一个 modavd 改动(新建、改设置或删除),等了 %.0f 秒仍没改完", i, configLockWait.Seconds()), map[string]string{errs.Reason: "locked", errs.Lock: "config"}) } return &InstanceLock{l: l}, nil @@ -782,7 +782,7 @@ const ( const ( FetchComponentsAdvice = "在管理器里点「补全组件」,或运行 tools\\modavd.exe components fetch;它会先显示《Android 软件开发套件许可协议》,输入 y 同意后" + "从官方渠道下载 adb 和系统镜像(约 1.5 GB,中断了再运行会接着下),完成后再检查一次" - PackageAdvice = "模拟器要用魔改 AVD 的发布包:从 https://github.com/ModAVD/ModAVD/releases 下载 " + + PackageAdvice = "模拟器要用 ModAVD 的发布包:从 https://github.com/ModAVD/ModAVD/releases 下载 " + "ModAVD-<版本>-win-x64.zip,整个解压到这个目录" ) diff --git a/internal/root/root_test.go b/internal/root/root_test.go index 6322084..bbea507 100644 --- a/internal/root/root_test.go +++ b/internal/root/root_test.go @@ -270,7 +270,7 @@ func TestResolve(t *testing.T) { _, err := resolve(filepath.Join(base, "missing"), "", "") wantCode(t, err, errs.NotFound) - if !strings.Contains(err.Error(), "--root 指定的魔改 AVD 根目录不存在") { + if !strings.Contains(err.Error(), "--root 指定的 ModAVD 根目录不存在") { t.Fatalf("message: %v", err) } _, err = resolve("", filepath.Join(base, "missing"), "") @@ -389,7 +389,7 @@ func TestUpdateMetadataFormatAndAbort(t *testing.T) { writeFile(t, r.MetadataPath(), []byte(sampleMetadata)) err := r.UpdateMetadata(func(o *jsonord.Obj) error { o.Set("adbServerPort", jsonord.NewInt(20089)) - o.Set("名称", jsonord.NewString("魔改 \"AVD\"")) + o.Set("名称", jsonord.NewString("模拟器 \"AVD\"")) return nil }) if err != nil { @@ -397,7 +397,7 @@ func TestUpdateMetadataFormatAndAbort(t *testing.T) { } want := "{\r\n \"components\": {\r\n \"emulator\": \"37.2.10\"\r\n },\r\n \"zeta\": [\r\n 1000.0,\r\n 0,\r\n" + " {}\r\n ],\r\n \"instances\": {\r\n \"0\": {\r\n \"memoryMb\": 6144,\r\n \"initialized\": true\r\n" + - " }\r\n },\r\n \"sdkRoot\": \"\",\r\n \"adbServerPort\": 20089,\r\n \"名称\": \"魔改 \\\"AVD\\\"\"\r\n}" + " }\r\n },\r\n \"sdkRoot\": \"\",\r\n \"adbServerPort\": 20089,\r\n \"名称\": \"模拟器 \\\"AVD\\\"\"\r\n}" if got := string(readFile(t, r.MetadataPath())); got != want { t.Fatalf("got %q\nwant %q", got, want) } diff --git a/internal/ui/fake_test.go b/internal/ui/fake_test.go index fa2a986..e801259 100644 --- a/internal/ui/fake_test.go +++ b/internal/ui/fake_test.go @@ -137,7 +137,7 @@ func (b fakeBackend) Info(ctx context.Context, i int) (*emu.InstanceInfo, error) } in, ok := b.f.instances[i] if !ok { - return nil, errs.Newf(errs.NotFound, "魔改 AVD 实例 %d 不存在", i) + return nil, errs.Newf(errs.NotFound, "ModAVD 实例 %d 不存在", i) } return &in, nil } @@ -174,7 +174,7 @@ func (b fakeBackend) Update(ctx context.Context, i int, req emu.UpdateRequest) ( b.f.mu.Unlock() in, ok := b.f.get(i) if !ok { - return nil, errs.Newf(errs.NotFound, "魔改 AVD 实例 %d 不存在", i) + return nil, errs.Newf(errs.NotFound, "ModAVD 实例 %d 不存在", i) } applied := map[string]any{} if req.FPS != nil { @@ -189,7 +189,7 @@ func (b fakeBackend) Update(ctx context.Context, i int, req emu.UpdateRequest) ( func (b fakeBackend) PreviewDiagnostics(ctx context.Context, i int) (*emu.DiagnosticsPreview, error) { if _, ok := b.f.get(i); !ok { - return nil, errs.Newf(errs.NotFound, "魔改 AVD 实例 %d 不存在", i) + return nil, errs.Newf(errs.NotFound, "ModAVD 实例 %d 不存在", i) } return &emu.DiagnosticsPreview{Index: i, DiagnosticsCleanup: emu.DiagnosticsCleanup{Files: 2, Bytes: 1024}}, nil } @@ -198,7 +198,7 @@ func (b fakeBackend) Delete(ctx context.Context, i int) (*emu.DeleteResult, erro b.f.mu.Lock() defer b.f.mu.Unlock() if _, ok := b.f.instances[i]; !ok { - return nil, errs.Newf(errs.NotFound, "魔改 AVD 实例 %d 不存在", i) + return nil, errs.Newf(errs.NotFound, "ModAVD 实例 %d 不存在", i) } delete(b.f.instances, i) b.f.deleted = append(b.f.deleted, i) @@ -211,7 +211,7 @@ func (b fakeBackend) Start(ctx context.Context, i int, opt emu.StartOptions) (*e gate := b.f.startGate b.f.mu.Unlock() if _, ok := b.f.get(i); !ok { - return nil, errs.Newf(errs.NotFound, "魔改 AVD 实例 %d 不存在", i) + return nil, errs.Newf(errs.NotFound, "ModAVD 实例 %d 不存在", i) } opt.Progress(emu.Progress{Step: "launch", Message: "实例已拉起", Done: 50, Total: 1000}) b.log.Warnf("测试警告 %d", i) @@ -267,7 +267,7 @@ func (b fakeBackend) AppProxy(ctx context.Context, i int) (*emu.AppProxyResult, defer b.f.mu.Unlock() b.f.proxyAsked = append(b.f.proxyAsked, i) if _, ok := b.f.instances[i]; !ok { - return nil, errs.Newf(errs.NotFound, "魔改 AVD 实例 %d 不存在", i) + return nil, errs.Newf(errs.NotFound, "ModAVD 实例 %d 不存在", i) } return b.f.proxyOf(i), nil } diff --git a/internal/ui/proxy_test.go b/internal/ui/proxy_test.go index c6b6c69..05261b5 100644 --- a/internal/ui/proxy_test.go +++ b/internal/ui/proxy_test.go @@ -253,7 +253,7 @@ func TestProxyPackages(t *testing.T) { } // emu says it does not run (no recent list): the same 409 h.f.mu.Lock() - h.f.shellErr = errs.New(errs.Unsupported, "魔改 AVD 实例 3 没有在运行") + h.f.shellErr = errs.New(errs.Unsupported, "ModAVD 实例 3 没有在运行") h.f.mu.Unlock() h.s.hub.dropCached() expectError(t, h.do("GET", "/api/instances/3/packages", nil), 409, errs.Busy) diff --git a/internal/ui/ui.go b/internal/ui/ui.go index 196719f..3236f1d 100644 --- a/internal/ui/ui.go +++ b/internal/ui/ui.go @@ -117,7 +117,7 @@ type server struct { func newServer(opt Options) (*server, error) { if opt.Root == nil { - return nil, errs.New(errs.Usage, "没有指定魔改 AVD 根目录") + return nil, errs.New(errs.Usage, "没有指定 ModAVD 根目录") } lg := opt.Log if lg == nil { diff --git a/internal/ui/web/dev/mock.js b/internal/ui/web/dev/mock.js index cc5f9c1..4eb3e63 100644 --- a/internal/ui/web/dev/mock.js +++ b/internal/ui/web/dev/mock.js @@ -232,7 +232,7 @@ function checkResult() { } if (db.check === 'notready' && !db.componentsReady) Object.assign(items[1], { ok: false, reason: '这个目录里缺少:平台工具(adb)、系统镜像 Android 14 Google APIs x86_64', advice: '在管理器里点「补全组件」,或运行 tools\\modavd.exe components fetch;它会先显示《Android 软件开发套件许可协议》,输入 y 同意后从官方渠道下载 adb 和系统镜像(约 1.5 GB,中断了再运行会接着下),完成后再检查一次' }); if (db.check === 'notready') { - Object.assign(items[3], { ok: false, reason: '硬件虚拟化(Windows 虚拟机监控程序平台)不可用,魔改 AVD 无法启动(检查结果:WHPX is not installed)', advice: '先在 BIOS/UEFI 里打开 VT-x/SVM,再在「启用或关闭 Windows 功能」里勾选「Windows 虚拟机监控程序平台」,然后重启' }); + Object.assign(items[3], { ok: false, reason: '硬件虚拟化(Windows 虚拟机监控程序平台)不可用,ModAVD 无法启动(检查结果:WHPX is not installed)', advice: '先在 BIOS/UEFI 里打开 VT-x/SVM,再在「启用或关闭 Windows 功能」里勾选「Windows 虚拟机监控程序平台」,然后重启' }); Object.assign(items[4], { ok: null, reason: '查不了 Vulkan:探测程序 8 秒内没有结束' }); Object.assign(items[2], { reason: '内测包 0.35.0(37.2.10)' }); // the host IME is optional and stays missing, also after a fetch (it is not a downloaded component) @@ -278,7 +278,7 @@ function runImport(j, files) { const steps = []; for (const x of named) if (x.zip || x.slot >= 0) steps.push(['verifying', `校验 ${x.f.name}${x.zip ? '(SHA-1)' : `(${STORE_FILES[x.slot][0]})`}`, x.zip ? STORE_ZIP : STORE_FILES[x.slot][2]]); if (zip) steps.push(['extracting', `解压 ${zip.f.name}`, 3101687808]); - log('info', '魔改 AVD:用自己的文件补全 Google Play 商店', j.id); + log('info', 'ModAVD:用自己的文件补全 Google Play 商店', j.id); let k = 0; const timer = setInterval(() => { if (j.state !== 'running') { clearInterval(timer); return; } @@ -470,7 +470,7 @@ function runDiag(j, kind = j.kind, store = false) { // play_store: Google's Play image too, of which only the five files stay if (store) stages.push(['downloading', 'Google Play 商店(取自 Android 14 Google Play x86_64 镜像 r14)', 420, 1441, 25], ['downloading', 'Google Play 商店(取自 Android 14 Google Play x86_64 镜像 r14)', 1180, 1441, 27], ['extracting', 'Google Play 商店(取自 Android 14 Google Play x86_64 镜像 r14)', 2958, 2958, 0]); - if (kind === 'components') ['魔改 AVD:补全 Google 组件(adb、Android 14 系统镜像)', '已在管理器里同意许可协议。'].forEach((m) => log('info', m, j.id)); + if (kind === 'components') ['ModAVD:补全 Google 组件(adb、Android 14 系统镜像)', '已在管理器里同意许可协议。'].forEach((m) => log('info', m, j.id)); let n = 0; const timer = setInterval(() => { if (j.state !== 'running') { clearInterval(timer); return; } @@ -487,7 +487,7 @@ function runDiag(j, kind = j.kind, store = false) { db.componentsReady = true; if (store) db.store = { ready: true, source: 'download' }; finishJob(j, { root: ROOT, license: 'Android SDK License', license_source: 'Google 中国下载(mock)', components: componentList(), downloads: [] }); - } else finishJob(j, { zip_path: `${ROOT}\\logs\\魔改AVD问题信息-mock.zip`, zip_size: '1.2 MB', problems: [], mas_found: true, entries: ['summary.txt'], + } else finishJob(j, { zip_path: `${ROOT}\\logs\\ModAVD-问题信息-mock.zip`, zip_size: '1.2 MB', problems: [], mas_found: true, entries: ['summary.txt'], privacy_note: '隐私提示(mock):问题包只保存在本机,不会自动上传。\r\n- 可以公开:summary.txt 和日志。\r\n- 不要公开:crash 文件夹。' }); } }, 500); @@ -880,7 +880,7 @@ async function handle(url, init) { if (db.insts.has(i)) return errResp('already_exists', `实例 mas_${i} 已存在`); await sleep(500); const inst = mk(i, body.title, { mem: body.memory_mb, cpu: body.cpu, fps: body.fps, resolution: body.resolution || 1080, disk: body.data_partition_gb, initialized: false, scene: i }); - log('info', `已新建魔改 AVD 实例 ${i}(内存 ${inst.config.memory_mb} MB / ${inst.config.cpu} 核 / 数据盘 ${inst.config.data_partition_gb} GB / 帧率 ${inst.config.fps})`); + log('info', `已新建 ModAVD 实例 ${i}(内存 ${inst.config.memory_mb} MB / ${inst.config.cpu} 核 / 数据盘 ${inst.config.data_partition_gb} GB / 帧率 ${inst.config.fps})`); emit('instances', list()); return json(pub(inst), 201); } @@ -971,7 +971,7 @@ async function handle(url, init) { if (!m) return errResp('not_found', '没有这个接口:' + p); const i = Number(m[1]); const inst = db.insts.get(i); - if (!inst) return errResp('not_found', `魔改 AVD 实例 ${i} 不存在`, '先新建这个实例'); + if (!inst) return errResp('not_found', `ModAVD 实例 ${i} 不存在`, '先新建这个实例'); const act = m[2]; const busyJob = runningJobOf(i); @@ -994,7 +994,7 @@ async function handle(url, init) { } if (method === 'DELETE') { if (url.searchParams.get('confirm') !== '1') return errResp('usage', '删除要带 confirm=1'); - if (inst.running || busyJob) return errResp('busy', `魔改 AVD 实例 ${i} 未关闭,无法删除`, '先关机再删除'); + if (inst.running || busyJob) return errResp('busy', `ModAVD 实例 ${i} 未关闭,无法删除`, '先关机再删除'); await sleep(700); db.insts.delete(i); emit('instances', list()); @@ -1002,9 +1002,9 @@ async function handle(url, init) { } } if (act === 'start') { - if (busyJob) return errResp('busy', `魔改 AVD 实例 ${i} ${busyJob.kind === 'stop' ? '正在关机' : '正在开机或做开机后设置'}`, '等它做完再试'); + if (busyJob) return errResp('busy', `ModAVD 实例 ${i} ${busyJob.kind === 'stop' ? '正在关机' : '正在开机或做开机后设置'}`, '等它做完再试'); // the manager boots with the window only; one running headless is not adopted (no switch while it runs) - if (inst.running && !inst._.win) return errResp('busy', `魔改 AVD 实例 ${i} 正以无头方式运行,运行中不能换成带窗口`, `先关机再换:modavd stop ${i},再 modavd start ${i} --window`); + if (inst.running && !inst._.win) return errResp('busy', `ModAVD 实例 ${i} 正以无头方式运行,运行中不能换成带窗口`, `先关机再换:modavd stop ${i},再 modavd start ${i} --window`); if (inst.status === 'online') { const j = newJob('start', i); run(j, [[400, () => step(j, 'launch', `实例 ${i} 已在运行(pid ${inst.pid}),不重新开机`, 50)], [600, () => step(j, 'boot', `实例 ${i} 安卓已开机`, 610)], @@ -1016,7 +1016,7 @@ async function handle(url, init) { return json(j, 202); } if (act === 'stop') { - if (busyJob && busyJob.kind !== 'start') return errResp('busy', `魔改 AVD 实例 ${i} 正在${busyJob.kind === 'stop' ? '关机' : '安装 APK'}`, '等它做完再试'); + if (busyJob && busyJob.kind !== 'start') return errResp('busy', `ModAVD 实例 ${i} 正在${busyJob.kind === 'stop' ? '关机' : '安装 APK'}`, '等它做完再试'); const j = newJob('stop', i); if (!inst.running) { setTimeout(() => finishJob(j, { index: i, name: inst.name, method: 'already_offline', synced: false, seconds: 0.1, warnings: [] }), 300); @@ -1024,8 +1024,8 @@ async function handle(url, init) { return json(j, 202); } if (act === 'install') { - if (inst.status !== 'online') return errResp('busy', `魔改 AVD 实例 ${i} 没有开机`, '开机后再安装'); - if (busyJob) return errResp('busy', `魔改 AVD 实例 ${i} 正在做别的事`, '等它做完再试'); + if (inst.status !== 'online') return errResp('busy', `ModAVD 实例 ${i} 没有开机`, '开机后再安装'); + if (busyJob) return errResp('busy', `ModAVD 实例 ${i} 正在做别的事`, '等它做完再试'); const f = init.body instanceof FormData ? init.body.get('apk') : null; if (!f) return errResp('usage', '没有收到 APK 文件'); const j = newJob('install', i); @@ -1036,7 +1036,7 @@ async function handle(url, init) { if (act === 'playstore-install' || act === 'playstore-uninstall') { const install = act === 'playstore-install'; const reason = (code, message, advice, r) => fail(STATUS_OF[code], code, message, advice, { reason: r }); - if (busyJob || inst.status === 'creating') return errResp('busy', `魔改 AVD 实例 ${i} 正在做别的事`, '等它做完再试'); + if (busyJob || inst.status === 'creating') return errResp('busy', `ModAVD 实例 ${i} 正在做别的事`, '等它做完再试'); if (sdkJob()) return errResp('busy', `任务 ${sdkJob().kind === 'components' ? '补全组件' : '导入 Google Play 商店的文件'} 正在运行(任务 ${sdkJob().id}),等它做完再试`); if (install && !db.store.ready) { return reason('not_ready', `这个根目录还没有 Google Play 商店的五个文件,或者文件不全、已损坏(${ROOT}\\sdk\\playstore)`, @@ -1051,7 +1051,7 @@ async function handle(url, init) { } if (act === 'gles32-on' || act === 'gles32-off') { const on = act === 'gles32-on'; - if (busyJob || inst.status === 'creating') return errResp('busy', `魔改 AVD 实例 ${i} 正在做别的事`, '等它做完再试'); + if (busyJob || inst.status === 'creating') return errResp('busy', `ModAVD 实例 ${i} 正在做别的事`, '等它做完再试'); if (inst.bridge === 'off') { return fail(STATUS_OF.not_ready, 'not_ready', `实例 ${i} 没有 arm64 执行桥,不按可写系统镜像开机,改不了它报的 GLES 版本`, `先运行 modavd bridge ${i} install 装上执行桥,再开这个开关`, { reason: 'gles32_no_bridge' }); } @@ -1061,7 +1061,7 @@ async function handle(url, init) { } if (act === 'playstore-gsfid') { if (inst.status !== 'online') return errResp('busy', `实例 ${i} 没有开机`, '开机后才能取 GSF ID'); - if (busyJob) return errResp('busy', `魔改 AVD 实例 ${i} 正在做别的事`, '等它做完再试'); + if (busyJob) return errResp('busy', `ModAVD 实例 ${i} 正在做别的事`, '等它做完再试'); if (db.nogsf) { return fail(STATUS_OF.not_ready, 'not_ready', `实例 ${i} 还没有 GSF ID`, 'Google 服务框架联网登记后才有:开着网等一两分钟,再试一次', { reason: 'no_gsf_id' }); } @@ -1084,14 +1084,14 @@ async function handle(url, init) { } else if (act === 'disk-trim') { step(j, 'disk_trim', `实例 ${i} 正在触发磁盘回收`, 0); setTimeout(() => { - if (inst.status !== 'online') return failJob(j, 'unsupported', `魔改 AVD 实例 ${i} 没有在运行,请先开机再回收磁盘空间`, ''); + if (inst.status !== 'online') return failJob(j, 'unsupported', `ModAVD 实例 ${i} 没有在运行,请先开机再回收磁盘空间`, ''); d.alloc = Math.max(3 * GB, d.alloc - 1.5 * GB); finishJob(j, { index: i, discard_max_bytes: 2 * GB }); }, 1800); } else { step(j, 'disk_compact', `实例 ${i} 正在整理磁盘(重写数据盘文件,要几分钟)`, 0); setTimeout(() => { - if (inst.running) return failJob(j, 'busy', `魔改 AVD 实例 ${i} 未关闭,无法整理磁盘`, `先 modavd stop ${i},关机后再整理`); + if (inst.running) return failJob(j, 'busy', `ModAVD 实例 ${i} 未关闭,无法整理磁盘`, `先 modavd stop ${i},关机后再整理`); const before = d.onDisk; d.onDisk = Math.min(before, d.alloc + 0.1 * GB); finishJob(j, { index: i, overlay: `${inst.path}\\userdata-qemu.img.qcow2`, before_on_disk_bytes: Math.round(before), after_on_disk_bytes: Math.round(d.onDisk), freed_bytes: Math.round(before - d.onDisk) }); @@ -1100,7 +1100,7 @@ async function handle(url, init) { return json(j, 202); } if (act === 'input') { - if (inst.status !== 'online') return errResp('busy', `魔改 AVD 实例 ${i} 没有开机`); + if (inst.status !== 'online') return errResp('busy', `ModAVD 实例 ${i} 没有开机`); if (body.type === 'tap') { inst._.tap = { x: body.x, y: body.y, t: now() }; if (inst._.mode !== 'game') inst._.mode = 'game'; @@ -1111,7 +1111,7 @@ async function handle(url, init) { } if (act === 'screenshot') { window.__mockShots[i] = (window.__mockShots[i] || 0) + 1; - if (inst.status !== 'online') return errResp('busy', `魔改 AVD 实例 ${i} 没有开机`); + if (inst.status !== 'online') return errResp('busy', `ModAVD 实例 ${i} 没有开机`); if (db.shotfail) return errResp('internal', '截图失败:adb exec-out screencap 退出码 1', ''); const blob = await screenshot(inst); return new Response(blob, { status: 200, headers: { 'Content-Type': 'image/png', 'Cache-Control': 'no-store' } }); diff --git a/internal/update/pkg.go b/internal/update/pkg.go index 08075b7..bf35fb2 100644 --- a/internal/update/pkg.go +++ b/internal/update/pkg.go @@ -570,7 +570,7 @@ func checkEmulator(emu string, target Version) error { return packageError("包里模拟器的构建号(%s)和要装的 %s(构建号 %d)不一致", build, target.Display(), target.Build) } if !fileContains(filepath.Join(emu, "qemu", p.QemuDir, p.QEMUHeadless), []byte("free-page-reporting")) { - return packageError("包里的模拟器不是魔改 AVD 的自编版") + return packageError("包里的模拟器不是 ModAVD 的自编版") } return nil } diff --git a/internal/update/updater.go b/internal/update/updater.go index b931076..3e72b5d 100644 --- a/internal/update/updater.go +++ b/internal/update/updater.go @@ -125,7 +125,7 @@ func (u *Updater) notUpdatable() string { return "这个根目录在 mas-avd.json 里设了 sdkRoot(开发用的本地 SDK),不更新" } if !isFile(filepath.Join(u.l.emulator(), root.CurrentPlatform().Emulator)) { - return `这个根目录里没有 sdk\emulator,请先放好魔改 AVD` + return `这个根目录里没有 sdk\emulator,请先放好 ModAVD` } return "" }