提交新代码

This commit is contained in:
2026-06-11 03:57:37 +08:00
parent 09d2244dbe
commit 98a1e9d371
37 changed files with 29146 additions and 665 deletions
+168 -114
View File
@@ -2,150 +2,204 @@
## Overview
A Windows GUI tool suite (Python 3.6+ / tkinter) for flashing multi-language APKs onto Android-based vehicle infotainment systems. Built by 宜宾科宜科技有限公司.
Windows GUI tool suite (Python 3.6+ / tkinter) for flashing or pushing multi-language APKs to Android-based vehicle infotainment systems. Built by 宜宾科宜科技有限公司.
The suite contains **5 tool variants**, each targeting a different vehicle model. All share the same `ADKAPKGUI` class architecture with model-specific customizations. Authorization is VIN-based via a cloud API.
Most tools are single-file tkinter apps with the same rough architecture: GUI, VIN authorization, package extraction, ADB commands, logging, and worker threads live in one class. Preserve that style unless the user explicitly asks for a larger refactor.
| Tool file | Vehicle | Window title | Pack script |
|-----------|---------|-------------|-------------|
| `app.py` | 启源Q07 | 长安语言安装工具 | `pack_q07.bat` |
| `S05.py` | 深蓝S05 | 深蓝S05多语言安装 | `pack_s05.bat` |
| `X5plusTool.py` | X5plus | 适用于X5plus多语言安装 | `pack_x5plus.bat` |
| `app-install.py` | 长安逸动 (通用) | 长安语言刷入工具 | `pack_common.bat` |
| `app-yidong.py` | 长安逸动 | 长安逸动语言刷入工具 | `pack_yidong.bat` |
## Tool Variants
## Project structure
| Tool file | Vehicle / purpose | Window title | Pack script |
|-----------|-------------------|--------------|-------------|
| `Q07/app.py` | 启源Q07 | 长安语言安装工具 | `Q07/pack_q07.bat` |
| `S05/S05.py` | 深蓝S05 original | 深蓝S05多语言安装 | `S05/pack_s05.bat` |
| `S05/S05_fixed.py` | 深蓝S05 fixed/experimental copy | 长安语言安装工具 | `S05/pack_s05_fixed.bat` |
| `X5plus/X5plusTool.py` | X5plus | 适用于X5plus多语言安装 | `X5plus/pack_x5plus.bat` |
| `Yidong/app-install.py` | 长安逸动通用 | 长安语言刷入工具 | `Yidong/pack_common.bat` |
| `Yidong/app-yidong.py` | 长安逸动 | 长安逸动语言刷入工具 | `Yidong/pack_yidong.bat` |
| `UNIZ/UNIZ.py` | UNI-Z file pusher | UNI-Z语言文件推送工具 | `UNIZ/pack_uniz.bat` |
| `Mazda-EZ60/Mazda-EZ60.py` | Mazda-EZ60 OS 1.2 | Mazda-EZ60_OS-1.2适用 | `Mazda-EZ60/pack_mazda_ez60.bat` |
| `Q05-Lidar/Q05-Lidar_Installer.py` | Q05_Lidar permission/bootstrap + language installer | Q05_Lidar | `Q05-Lidar/pack_q05_lidar.bat` |
## Project Structure
```
├── app.py # 启源Q07 tool
├── S05.py # 深蓝S05 tool
├── X5plusTool.py # X5plus tool
├── app-install.py # 逸动通用 tool
├── app-yidong.py # 逸动 tool
├── pack_q07.bat # Q07 pack script
├── pack_s05.bat # S05 pack script
├── pack_x5plus.bat # X5plus pack script
├── pack_common.bat # 逸动通用 pack script
├── pack_yidong.bat # 逸动 pack script
── test_extract.py # Standalone test for package.bin extraction
├── app.ico # Application icon
├── package.bin # Encrypted ZIP (not in repo)
├── adb.exe # Bundled ADB
├── AdbWinApi.dll # ADB dependency
├── AdbWinUsbApi.dll # ADB dependency
└── .vscode/
└── settings.json
├── Q07/ # Q07 script, pack scripts, ignored build outputs
├── S05/ # S05 original and fixed copy
├── X5plus/ # X5plus tool
├── Yidong/ # common/yidong tools
├── UNIZ/ # UNI-Z file pusher
├── Mazda-EZ60/ # Mazda-EZ60 tool
├── A07/ # Qiyuan A07 tool
├── Q05-Lidar/ # Q05_Lidar tool plus resource.dat/tools
├── app.ico
├── package.bin # encrypted package, not committed; shared from root
── tools/ # shared adb/fastboot/7za dependencies for pack scripts
├── adb.exe
├── AdbWinApi.dll
├── AdbWinUsbApi.dll
├── fastboot.exe
└── 7za.exe # 7-Zip Extra 26.01, bundled by pack scripts
```
## Architecture
## Architecture Notes
### Single-file design
- Most tools use class `ADKAPKGUI`; `UNIZ/UNIZ.py` uses `UNIZLanguageGUI`.
- Worker actions run in `threading.Thread(..., daemon=True)`.
- Tkinter calls from workers must go through `run_on_ui_thread(...)`.
- Prefer `self.root.after(0, lambda: func(*args, **kwargs))` in `run_on_ui_thread`; direct `after(0, func, *args, **kwargs)` breaks when kwargs such as `text=` or `fg=` are passed.
- Background `messagebox.*` calls should be scheduled with `run_on_ui_thread`.
- Keep files UTF-8 with `# -*- coding: utf-8 -*-`.
Each tool is a single Python file under the `ADKAPKGUI` class. No MVC separation — the class handles GUI, business logic, ADB operations, network calls, and file extraction.
## ADB And Auth
### Threading model
- `run_adb_command(command)` handles normal ADB commands such as `adb devices`, `adb push`, and non-shell install calls.
- `run_adb_shell(shell_command)` exists in the 逸动-family tools and Mazda copy; it shells into the device and automatically sends password `adb36987`.
- All `adb shell` operations in `Yidong/app-install.py`, `Yidong/app-yidong.py`, and `Mazda-EZ60/Mazda-EZ60.py` should go through `run_adb_shell()`.
- `UNIZ/UNIZ.py` must not use `adb shell`; it only checks devices and pushes APKs to `/storage/emulated/0/Download/`.
- Standard auth flow uses:
- `auth-check?vin=...` for authorization.
- `package-key?vin=...` for `package.bin` extraction password.
- VIN keys:
- Q07/S05/X5plus: `ca_vin_info` or `VIN`.
- 逸动/Mazda: `settings get system ca.car.vin` via auto-password shell.
- UNI-Z: user manually enters VIN.
- **Main thread**: tkinter event loop (`root.mainloop()`)
- **Background threads**: All user-triggered operations spawn `threading.Thread(target=..., daemon=True)`
- **Thread-safety**: UI mutations via `self.run_on_ui_thread(func, ...)``self.root.after(0, func, ...)`. Internal `_impl` methods are the actual tkinter-touching implementations.
## Package Extraction
### ADB operations
- `package.bin` is extracted under `%LOCALAPPDATA%\.cache\system\.android\...`.
- Current cache directories:
- `Q07/app.py` -> `apps_cache_Q07`
- `S05/S05.py` / `S05/S05_fixed.py` -> `apps_cache_S05`
- `X5plus/X5plusTool.py` -> `apps_cache_X5plus`
- `Yidong/app-install.py` -> `apps_cache_common`
- `Yidong/app-yidong.py` -> `apps_cache_yidong`
- `UNIZ/UNIZ.py` -> `apps_cache_UNIZ`
- `Mazda-EZ60/Mazda-EZ60.py` -> `apps_cache_Mazda_EZ60`
- Shared binaries are managed under root `tools/`: `adb.exe`, `AdbWinApi.dll`, `AdbWinUsbApi.dll`, `fastboot.exe`, and `7za.exe`. Vehicle pack scripts in subfolders should copy from `%ROOT%\tools`, not from each vehicle folder.
- For progress display, detect support for `-bsp1` by checking for `-bs{o|e|p}` in 7za help output.
- If `Incorrect command line` appears, retry with the basic compatible command: `x package.bin -pPASSWORD -oDIR -y`.
- Decode 7za output with GBK first, then UTF-8 fallback.
- 7za progress must parse streamed output cumulatively. Do not read one byte and regex that single byte; percentages such as `42%` span multiple bytes and will otherwise jump from 0 to 100.
- User-facing resource extraction text should say `资源准备中` / `Preparing resources`, not `资源解压` / `Extracting package`, unless the UI is an explicit debug test.
- Cache cleanup should be best effort in three places when feasible: before a new extraction, during normal window close, and via `atexit` for ordinary process exit. A forced process kill cannot be guaranteed, so also clear stale caches at next extraction/startup.
- `run_adb_command(command)` — standard ADB commands; auto-substitutes `adb` with bundled `adb.exe` path when frozen
- `run_adb_shell(shell_command)` — only in app-install.py / app-yidong.py; shells into device with auto-password `adb36987`
## Shared UX And Safety Rules
ADB path is portable: `self.adb` resolves to `sys._MEIPASS/adb.exe` when frozen (PyInstaller bundle), or `'adb'` in development.
- Hosts update logic should replace conflicting entries for the managed domain. If the hosts file already contains the target domain with a different IP, delete that line and write the expected `IP domain` entry instead of appending duplicates.
- VIN authorization logs should be explicit for operator-facing flows: print the current VIN, print `data.vehicleName` when `auth-check` returns it, print authorization success, and print a clear unauthorized/failure log when denied.
- `package-key` requests should use the vehicle name returned by `auth-check` (`data.vehicleName`) whenever available. Do not hardcode a model name if the authorization API already returned the exact vehicle name for the VIN.
- Normal users should not see low-level sensitive process details such as `fastboot`, `init_boot`, boot keys, or image names during permission/bootstrap flows. Use black-box text such as `正在获取权限中`, `获取成功`, and `获取失败`; leave command details for debug mode only.
- Process logs should stay minimal in normal mode. Detailed ADB/7za/API command logs belong behind debug mode.
- All Tkinter UI updates and `messagebox.*` calls from workers must go through `run_on_ui_thread(...)`.
### Authentication flow
## Model-Specific Behavior
1. ADB detects device → reads VIN (`ca_vin_info` or `VIN`; 逸动 uses `ca.car.vin`)
2. VIN sent to `https://api.changan.softwindy.cn/api/authorizations/auth-check?vin=...`
3. Package password from `https://api.changan.softwindy.cn/api/authorizations/package-key?vin=...`
4. Password used to decrypt `package.bin`
### S05
### Package extraction
- Keep `S05/S05.py` as original unless explicitly asked.
- Use `S05/S05_fixed.py` for experimental/fixed S05 changes.
- Do not add `chmod`, `chown`, or `restorecon` to the S05 system-app push path unless explicitly requested; the target system inherits permissions.
- `S05/S05_fixed.py` includes debug extract test `Ctrl+Shift+E` and 7za progress support.
- `package.bin` is a password-protected ZIP (AES via pyzipper, fallback to zipfile)
- Extracted to `%LOCALAPPDATA%\.cache\system\.android\apps_cache_{variant}` (hidden via `attrib +h`)
- Each tool has its own cache folder to avoid conflicts:
- app.py → `apps_cache_Q07`
- S05.py → `apps_cache_S05`
- X5plusTool.py → `apps_cache_X5plus`
- app-install.py → `apps_cache_common`
- app-yidong.py → `apps_cache_common` (default)
- Extracted APKs in `app/` pushed to `/system/app/`, `priv-app/` to `/system/priv-app/`
### UNI-Z
### Device status monitoring
- Endpoint for visible passwords: `/api/authorizations/get-uni-z-pwd`.
- Display `factoryPwd` as factory mode password and `password` as debug password.
- If `authorized == false` or `password` is empty, show unauthorized state and do not proceed.
- `password` from `get-uni-z-pwd` is not the package extraction password.
- Before push, call `/api/authorizations/package-key?vin=...` to get the real `package.bin` password.
- Push only to `/storage/emulated/0/Download/`; no `adb shell`.
- Language selection: RU/FR/ES/EN. Only the selected language Settings APK is pushed; other language Settings APKs are skipped silently.
- Hidden debug mode: `Ctrl+Shift+D`, password `zxch5200`, logs full ADB/7za/API details.
Background daemon thread runs `adb devices` every 5 seconds to detect connect/disconnect events.
### Mazda-EZ60
## GUI layout (650x640 dark theme for most; 650x550 for 逸动)
- Based on `Yidong/app-install.py` / 逸动 flow.
- Uses auto-password shell (`adb36987`) for VIN reads, `pm install`, overlay enable, disable commands, settings, and reboot.
- Installs APKs from extracted `apps` via push to `/data/local/tmp` then `pm install -r -d`.
- `Mazda-EZ60/Mazda-EZ60.py` should show 7za extraction progress with stream parsing.
- Regardless of APK install failures, run post-install configuration after the install loop.
- Post-install overlays to enable:
- `com.tinnove.launcher.overlay`
- `com.tinnove.scenemode.overlay`
- `com.incall.dvr.overlay`
- Post-install packages to disable:
- `com.carinno.p1`
- `com.wtcl.electronicdirections`
- `com.ximalaya.ting.android.car`
- `com.tinnove.netease.music`
- `com.migu.miguplay.car`
- `cn.cmvideo.car.play`
- `com.tinnove.carshow`
- `com.tinnove.changba`
- `com.qiyi.video.iv`
- User cancelled the `Ctrl+Shift+E` direct extract test request for Mazda; do not add it unless asked again.
| Section | Contents |
|---------|----------|
| Title bar | Vehicle model + company subtitle |
| Password query | Hidden VIN→password lookup (S05, app-install only) |
| Button row 1 | 获取权限 (Q07/S05), 刷入语言包, 安装App, 语言设置 |
| Button row 2 | 时区设置, 安卓设置, 重启设备, 禁用升级 |
| Status bar | Connection dot, VIN, Auth status, Refresh button |
| Tips | Usage warnings |
| Progress | Extraction + push progress (hidden by default) |
| Log area | ScrolledText with tags (INFO/SUCCESS/ERROR/WARNING/CMD), 清空日志 button in title bar |
### Q05_Lidar
## Key features
- This is the Q05_Lidar-specific tool and must not be confused with any ordinary Q05 variant or package.
- Based on the shared installer visual style, but its resource structure and flashing flow are Q05_Lidar-specific.
- The first-row `获取权限` button installs `runtime.dat` -> `base.apk`, reboots to fastboot, waits for a real `fastboot devices` row like `<serial> fastboot` with a non-aggressive interval, then fetches a boot key through `POST /api/authorizations/boot-challenge` then `POST /api/authorizations/boot-key`, decrypts embedded `resource.dat`, flashes `init_boot`, immediately reboots, and deletes the temporary img. Keep the decrypted img lifetime as short as possible.
- `resource.dat` is AES-GCM encrypted and must match the server `BOOT_KEY`; the tool only accepts `data.sessionKey` from `boot-key`.
- Device fingerprint data sent to the server includes ADB serial, `ro.serialno`, `ro.boot.serialno`, manufacturer, model, device, build fingerprint, and VIN.
- `刷入语言包` installs Magisk modules, not APKs. It opens `com.topjohnwu.magisk`, warns the user to grant Shell/root permission, verifies `/debug_ramdisk/su -c "id"` returns `uid=0`, extracts `Q05_Lidar-package.bin`, then pushes module files to `/data/local/tmp/q05_lidar_modules/<MODID>/` and root-copies them into `/data/adb/modules/<MODID>`.
- `Q05_Lidar-package.bin` should unpack with module files at archive root: `module.prop`, scripts, `system/`, and `disable-wireless-adb-vecentek-magisk.zip`; do not wrap them in an outer `Q05_LIDAR_DATA/` directory.
- Q05_Lidar package cache is `%LOCALAPPDATA%\.cache\system\.android\apps_cache_Q05_Lidar`; the tool cleans it on startup/extraction and on normal/atexit shutdown.
- Q05_Lidar `runtime.dat` cache is `%LOCALAPPDATA%\.cache\system\.android\apps_cache_q05_lidar_runtime`; treat it as temporary and clean stale contents before extraction.
- `Q05_Lidar-package.bin` is an external release file next to the exe because it is large. `resource.dat` is embedded in the exe; `runtime.dat` should be copied next to the exe by the pack script.
- `package-key` must include the `vehicleName` returned by `auth-check` for the VIN. The tool caches `data.vehicleName` from password query / authorization check and uses it for package-key; if missing, query `auth-check` first rather than falling back to a hardcoded Q05_Lidar value.
- All `adb shell` commands in Q05_Lidar, including Magisk launch and `/debug_ramdisk/su -c ...`, must go through `run_adb_shell()` so the tool silently sends `adb36987`.
- The `安装App` button remains the APK install path: file picker -> `adb push` -> `setprop vecentek.model 1` -> `pm install -r -d -f` -> cleanup. Do not replace it with the Magisk module flow.
- Temporary debug mode exists only for development and should be removed before release when requested. Press `Ctrl+Shift+D`; the password is verified through `POST /api/authorizations/verify-debug-mode-password`.
- In Q05_Lidar debug mode, hidden buttons appear for:
- `指纹测试`: collect and log device fingerprint fields plus local SHA256 summary.
- `解密测试`: if VIN/device is available, fetch boot key; otherwise prompt for a pasted `BOOT_KEY`/`sessionKey`, decrypt `resource.dat` locally to a temporary img, log size/SHA256, then delete it.
- `解压测试`: fetch `package-key`, extract `Q05_Lidar-package.bin`, and verify the main Magisk module plus `disable_wireless_adb_vecentek` module can be identified.
- Do not log the actual boot key/session key in debug mode.
### Install App (unified single/batch)
"安装App" button uses `filedialog.askopenfilenames` for multi-file selection, replacing old separate "单个安装" and "批量安装" buttons. Select 1 or more APKs and installs all in one pass (`adb install -r`).
### Yidong/app-yidong.py
### Debug mode (hidden)
Press `Ctrl+Shift+D` → password `zxch5200` to enter debug mode:
- Bypasses device connection and authorization checks (UI shows "已连接" / "已授权")
- Logs all raw ADB commands and output to the log panel
- Exiting debug mode auto-refreshes real device state
- Uses `apps_cache_yidong`.
- Has 7za compatibility handling for progress switches and `Incorrect command line` fallback.
- `Yidong/pack_yidong.bat` output name is ASCII: `Changan-Yidong-Language-Installer.exe`, to avoid CMD codepage issues with Chinese `NAME`.
### Language quick-set
Popup with 8 one-click locale switches (zh-CN, en-US, ru-RU, fr-FR, es-ES, pt-BR, it-IT, ar-SA). Also links to native Android language settings. Changes take effect after reboot.
## Build Notes
### Model-specific behaviors
- Pack scripts install/use `pyinstaller`, `cython`, and usually `pyzipper`.
- Cython success requires Microsoft C++ Build Tools.
- Cython success signs in logs:
- `building '_core' extension`
- `_core.cpXXX-win_amd64.pyd`
- `PYD: _core...pyd`
- output under `dist_cy\dist\...exe`
- If logs show `[WARN] Cython failed, fallback` and `[INFO] Normal PyInstaller`, the exe still builds but is normal PyInstaller and easier to reverse.
- For security-sensitive tools like Q05_Lidar, do not keep a normal PyInstaller fallback. If Cython fails or no `_core*.pyd` is generated, stop the build and show an error.
- A Cython onefile PyInstaller build should use a tiny `launcher.py` that imports `main` from compiled `_core.pyd`, and the exe archive should contain `_core*.pyd`. Confirm with PyInstaller archive viewer when in doubt.
- `UNIZ/pack_uniz.bat` and `Mazda-EZ60/pack_mazda_ez60.bat` use ASCII output names to avoid CMD encoding problems.
- Generated `.exe`, `.spec`, `build/`, `dist/`, and `dist_cy/` are build artifacts and should not be committed unless explicitly requested.
| Feature | Q07 (app.py) | S05 (S05.py) | X5plus (X5plusTool.py) | 逸动 (app-install/yidong) |
|---------|-------------|-------------|------------------------|---------------------------|
| Root perm | Y | Y | N (no btn_root) | N |
| priv-app | Y | Y | Y | N (app only) |
| ADB shell | Standard | Standard | Standard | Auto-password `adb36987` |
| VIN key | ca_vin_info/VIN | ca_vin_info/VIN | ca_vin_info/VIN | ca.car.vin |
| Old app cleanup | N | N | Y (5 packages) | N |
| Font push | N | N | Y (FZLTHPro) | N |
| Overlay enable | N | N | N | N (removed) |
| Password query | N | Y | N | Y |
| Factory hints | N | Y | Y (dynamic pwd) | Y |
## Key Behaviors To Preserve
## Build process
1. Keep original tools untouched when a fixed or model-specific copy exists.
2. Preserve VIN-based authorization for normal flashing tools.
3. Fetch `package-key` from the server instead of hardcoding package passwords.
4. Keep all shell commands in 逸动/Mazda tools behind `run_adb_shell()`.
5. Keep UNI-Z shell-free.
6. Use `run_on_ui_thread()` for all tkinter UI updates from worker threads.
7. Keep shared Android/7za binaries under root `tools/` and have pack scripts copy from there.
Each `pack_*.bat` follows the same pipeline:
1. Install deps: `pyinstaller`, `cython`, `pyzipper`
2. Clean old build dirs
3. Cython compile: `{source}.py``_core.pyd`
4. Copy resources: `adb.exe`, DLLs, `app.ico`
5. PyInstaller: single `.exe` with `--uac-admin`, bundling `_core.pyd` + ADB + DLLs
6. Fallback to normal PyInstaller if Cython fails
## Current Local State (2026-05-28)
Output exe is self-contained — bundles `adb.exe` and DLLs via `sys._MEIPASS`, no external ADB needed.
- `UNIZ/UNIZ.py` and `UNIZ/pack_uniz.bat` exist locally. Cython build has succeeded after installing Microsoft C++ Build Tools, producing `dist_cy\dist\UNIZ-Language-Pusher.exe`.
- `Mazda-EZ60/Mazda-EZ60.py` and `Mazda-EZ60/pack_mazda_ez60.bat` exist locally. Mazda has 7za progress extraction, unconditional post-install configuration, three overlay enables, and nine package disables.
- `Yidong/app-yidong.py` has been updated for 7za progress compatibility and `Incorrect command line` fallback.
- `Yidong/pack_yidong.bat` has been updated with quoted paths, `cd /d "%~dp0"`, and ASCII output name.
- `.gitignore` has been expanded to ignore generated exe/spec artifacts.
- There may be untracked local build outputs and generated specs; inspect `git status --ignored` before committing.
## Key behaviors to preserve
## Known Issues
1. **Thread safety**: Never call tkinter from background threads — always use `run_on_ui_thread`
2. **VIN-based auth**: Authorization required before push; flow must remain intact
3. **Silent extraction**: Auto-extract `package.bin` without user step
4. **ADB portability**: `self.adb` resolves to bundled exe path; all commands go through `run_adb_command`
5. **vecentek.model**: Set to 1 before install, 0 after
6. **Chinese encoding**: `# -*- coding: utf-8 -*-` throughout
7. **Debug mode**: `self.debug_mode` flag gates auth/connection bypass and verbose logging
8. **Separate cache dirs**: Each tool extracts to its own cache folder
## Known issues
- `test_extract.py` hardcodes password — should fetch from API
- `on_disable_upgrade` uses `findstr` (Windows-specific)
- Exception handling is minimal in many places (bare `except: pass`)
- 逸动 tools (app-install/yidong) use `subprocess.Popen` with stdin password injection — fragile
- Some older tools still have minimal exception handling and bare `except: pass`.
- `test_extract.py` hardcodes a password and should not be treated as production flow.
- `on_disable_upgrade` behavior is Windows/vehicle specific.
- Pure PyInstaller fallback is easy to reverse; prefer successful Cython builds for release.