hi-client/docs/go修复.md
Rust d02eed3bd8 docs: 添加 GitHub Actions 构建文档并锁定 libcore 版本
- 添加完整的 GitHub Actions 构建指南文档
  - BUILD_GUIDE.md: Android 详细构建指南
  - MULTIPLATFORM_GUIDE.md: 多平台构建指南
  - HOW_TO_BUILD.md: 分步操作教程
  - QUICKSTART.md: 3步快速开始指南
  - INDEX.md: 文档总览索引
  - README.md: 基础说明
- 创建 docs/ 目录存放项目文档
- 锁定 libcore 子模块到 f993a57 (v3.1.7)
  - 防止在线编译时使用最新版本
  - 确保构建稳定性和一致性
2025-10-27 23:11:21 +08:00

319 lines
8.2 KiB
Markdown

# Android SELinux chown 权限问题修复方案
## 问题背景
在 Android 12+ 系统上,由于 SELinux 严格模式的权限限制,sing-box 核心库在启动时会因为 `chown` 操作被拒绝而失败。具体表现为以下三个错误:
1. **CommandServer 错误**: `chown: chown command.sock: operation not permitted`
2. **Logger 错误**: `start logger: chown box.log: operation not permitted`
3. **Clash Cache 错误**: `pre-start cache file: platform chown: chown clash.db: operation not permitted`
## 问题分析
### 根本原因
sing-box (libbox) 在创建文件后会尝试修改文件所有权(`chown`操作),但在 Android 的 SELinux 环境下,应用无法修改外部存储目录中文件的所有权,导致启动失败。
### 涉及的文件
1. `command.sock` - CommandServer 的 Unix socket 文件
2. `box.log` - sing-box 的日志文件
3. `clash.db` - Clash API 的缓存数据库文件
## 修复方案
### 方案概述
**核心思路**: 在配置层面禁用会触发 chown 操作的功能,或者修改底层代码跳过 chown 操作。
由于修改 sing-box 底层库较为复杂,建议采用配置修改方案。
---
## 具体修复步骤
### 修复 1: 禁用文件日志
**文件**: `libcore/config/hiddify_option.go`
**位置**: `DefaultHiddifyOptions()` 函数
**修改前**:
```go
LogLevel: "warn",
// LogFile: "/dev/null",
LogFile: "box.log",
```
**修改后**:
```go
LogLevel: "warn",
LogFile: "", // 禁用文件日志,避免 Android SELinux chown 权限问题
// LogFile: "box.log",
```
**说明**:
-`LogFile` 设置为空字符串,禁用文件日志输出
- 日志将只输出到 stderr,可以通过 logcat 查看
- 这不会影响日志功能,只是改变了输出目标
---
### 修复 2: 禁用 Clash API 缓存
**文件**: `libcore/config/config.go`
**位置**: `setClashAPI()` 函数
**修改前**:
```go
func setClashAPI(options *option.Options, opt *HiddifyOptions) {
if opt.EnableClashApi {
if opt.ClashApiSecret == "" {
opt.ClashApiSecret = generateRandomString(16)
}
options.Experimental = &option.ExperimentalOptions{
ClashAPI: &option.ClashAPIOptions{
ExternalController: fmt.Sprintf("%s:%d", "127.0.0.1", opt.ClashApiPort),
Secret: opt.ClashApiSecret,
},
CacheFile: &option.CacheFileOptions{
Enabled: true,
Path: "clash.db",
},
}
}
}
```
**修改后**:
```go
func setClashAPI(options *option.Options, opt *HiddifyOptions) {
if opt.EnableClashApi {
if opt.ClashApiSecret == "" {
opt.ClashApiSecret = generateRandomString(16)
}
options.Experimental = &option.ExperimentalOptions{
ClashAPI: &option.ClashAPIOptions{
ExternalController: fmt.Sprintf("%s:%d", "127.0.0.1", opt.ClashApiPort),
Secret: opt.ClashApiSecret,
},
CacheFile: &option.CacheFileOptions{
Enabled: false, // 禁用缓存以避免 Android SELinux chown 权限问题
Path: "", // 清空路径
},
}
}
}
```
**说明**:
-`Enabled` 设置为 `false`,禁用 Clash API 缓存功能
-`Path` 设置为空字符串
- Clash API 功能仍然可用,只是不会持久化节点选择等信息
---
### 修复 3: CommandServer 错误处理 (可选)
**说明**: CommandServer 主要用于命令行控制,对 Android VPN 功能不是必需的。
#### 方案 A: 在应用层捕获异常 (推荐)
**文件**: `android/app/src/main/kotlin/com/hiddify/hiddify/bg/BoxService.kt`
**位置**: `onStartCommand()` 函数
**修改**:
```kotlin
GlobalScope.launch(Dispatchers.IO) {
Settings.startedByUser = true
initialize()
try {
startCommandServer()
} catch (e: Exception) {
// CommandServer 启动失败不是致命错误
// 在 Android 12+ SELinux 环境下,chown 操作可能被拒绝
// 但这不影响 VPN 核心功能,因此记录警告但继续启动服务
Log.w(TAG, "CommandServer failed to start (non-fatal): ${e.message}")
}
startService()
}
```
#### 方案 B: 完全禁用 CommandServer
如果不需要 CommandServer 功能,可以直接注释掉启动代码:
```kotlin
// startCommandServer() // 在 Android 上禁用
```
---
## 验证修复
### 编译步骤
1. **使用 Docker 编译** (推荐):
```bash
cd libcore
docker run --rm -v "$PWD:/workspace" -w /workspace golang:1.23 bash -c "bash docker-compile.sh"
```
2. **或者本地编译**:
```bash
cd libcore
make android
```
### 部署编译好的库
编译完成后,有两种部署方式:
#### 方式A: 替换完整AAR (推荐生产环境)
```bash
cd libcore
# 替换AAR文件
cp libcore.aar ../android/app/libs/
# 删除可能冲突的so文件
rm -rf ../android/app/src/main/jniLibs/
# 重新编译Flutter项目
cd ..
flutter clean && flutter build apk
```
**优点**: 支持所有架构,适合发布版本
#### 方式B: 只提取arm64 so文件 (推荐测试环境)
```bash
cd libcore
# 从AAR提取arm64的libbox.so
unzip -j libcore.aar jni/arm64-v8a/libbox.so -d /tmp/
mkdir -p ../android/app/src/main/jniLibs/arm64-v8a/
cp /tmp/libbox.so ../android/app/src/main/jniLibs/arm64-v8a/
# 临时禁用AAR(避免冲突)
mv ../android/app/libs/libcore.aar ../android/app/libs/libcore.aar.old
# 编译测试版本
cd ..
flutter clean && flutter build apk --debug --split-per-abi
```
**优点**: 编译快速,APK体积小,适合开发调试
⚠️ **重要**: 两种方式不能同时使用,会产生冲突!请根据需求选择其一。
### 测试验证
1. 重新编译 Flutter 应用
2. 在 Android 设备上安装并启动
3. 查看 logcat 日志,确认没有 chown 相关错误
4. 验证 VPN 能正常启动和代理流量
---
## 预期结果
修复后,应用启动日志应该显示:
```
D/A/BoxService: base dir: /data/user/0/app.xxx.com/files
D/A/BoxService: working dir: /storage/emulated/0/Android/data/app.xxx.com/files
D/A/BoxService: temp dir: /data/user/0/app.xxx.com/cache
W/A/BoxService: CommandServer failed to start (non-fatal): chown: chown command.sock: operation not permitted
D/A/BoxService: starting service
D/A/BoxService: 配置已修改: 禁用文件日志和Clash缓存
D/A/EventHandler: new status: Started ✅ 成功启动!
```
---
## 影响评估
### 功能影响
| 功能 | 修复前 | 修复后 | 影响 |
|------|--------|--------|------|
| VPN 代理 | ❌ 无法启动 | ✅ 正常工作 | 无影响 |
| 日志记录 | 文件输出 | logcat 输出 | 日志仍可用,通过 logcat 查看 |
| Clash API | 带缓存 | 无缓存 | 节点选择不持久化,重启后重置 |
| CommandServer | ❌ 失败 | 跳过启动 | 命令行控制不可用(非必需) |
### 性能影响
- **无性能损失**: 禁用缓存和文件日志对性能无负面影响
- **启动速度**: 可能略微加快(减少文件 I/O 操作)
---
## 替代方案 (高级)
如果需要保留完整功能,可以考虑以下方案:
### 方案 1: 修改 sing-box 源码
在 sing-box 底层库中跳过 Android 平台的 chown 操作:
```go
// 在文件创建后的 chown 调用处添加平台判断
if runtime.GOOS != "android" {
if err := os.Chown(path, uid, gid); err != nil {
return err
}
}
```
**优点**: 保留所有功能
**缺点**: 需要修改 sing-box 上游代码,维护成本高
### 方案 2: 使用内部存储
将文件创建在 `/data/user/0/` 目录下而不是外部存储:
**优点**: 避免 SELinux 限制
**缺点**: 空间受限,不适合大文件
---
## 常见问题
### Q1: 禁用文件日志后如何查看日志?
**A**: 使用 adb logcat:
```bash
adb logcat | grep "A/BoxService\|singbox"
```
### Q2: 禁用 Clash 缓存后有什么影响?
**A**: 每次启动 VPN 时,节点选择会重置为默认值,但不影响 VPN 的核心代理功能。
### Q3: 为什么 hiddify-app 可以正常运行?
**A**: hiddify-app 使用的 libcore 版本已经包含了这些修复,或者使用了不同的配置策略。
### Q4: 这个修复是否适用于所有 Android 版本?
**A**: 是的,这个修复对 Android 11 及以下版本也兼容,不会产生负面影响。
---
## 参考资料
- [Android SELinux 权限文档](https://source.android.com/docs/security/features/selinux)
- [sing-box 配置文档](https://sing-box.sagernet.org/configuration/)
- [Clash API 配置](https://sing-box.sagernet.org/configuration/experimental/clash-api/)
---
## 更新日志
- **2025-10-27**: 初始版本,包含三个核心修复方案