Cloud-Kernel v1.5
DEVELOPER REFERENCE

Cloud-Kernel 开发文档

面向 Android 平台的内核驱动管理套件 —— 驱动选择与注入、PTY 终端交互、系统信息检测、在线更新与主题自定义。

com.js.fc versionName 1.5 minSdk 21 · targetSdk 29 Java + C++ (JNI) armeabi-v7a / arm64-v8a

01 项目概述

1.1 项目简介

Cloud-Kernel(云内核)是一款面向 Android 平台的内核驱动管理套件,提供内核驱动选择与注入、PTY 终端命令行交互、系统信息检测、在线更新和主题自定义等功能。该应用运行在已获取 Root 权限的 Android 设备上,通过 JNI 调用原生 C/C++ 代码,利用 PTY(伪终端)技术与系统 Shell 进行交互。

1.2 基本信息

属性
应用名称Cloud-Kernel
包名com.js.fc
版本号versionCode=1, versionName=1.5
最低 SDKAPI 21 (Android 5.0)
目标 SDKAPI 29 (Android 10)
开发语言Java (Android) + C++ (JNI)
构建系统Android SDK + NDK (ndk-build)
支持架构armeabi-v7a, arm64-v8a
启动入口SplashActivityMainActivity

1.3 权限声明

权限用途
INTERNET在线版本检查与文件下载
ACCESS_NETWORK_STATE检测网络状态
READ_EXTERNAL_STORAGE读取外部存储图片(背景图)
WRITE_EXTERNAL_STORAGE (maxSdkVersion=28)写入外部存储
SYSTEM_ALERT_WINDOW悬浮窗口(预留)
应用配置中启用了 usesCleartextTraffic="true" 以允许 HTTP 明文流量,以及 requestLegacyExternalStorage="true" 以兼容 Android 10 的分区存储。

02 项目结构

新纪元/ ├── AndroidManifest.xml # 应用清单文件 ├── project.properties # 项目属性(target=android-29) ├── jni/ │ ├── Android.mk # NDK 构建配置 │ ├── Application.mk # NDK 应用配置(ABI、平台) │ └── ptyterm.cpp # PTY 终端 JNI 实现 ├── res/ │ ├── drawable/ # 可绘制资源(按钮、卡片、图标样式) │ ├── layout/ # 布局文件 │ │ ├── activity_main.xml # 主界面布局 │ │ ├── activity_splash.xml # 启动页布局 │ │ └── dialog_download_prompt.xml # 下载提示对话框 │ ├── mipmap-anydpi-v26/ # 自适应图标 │ ├── values/ # 值资源 │ │ ├── colors.xml # 颜色定义 │ │ ├── strings.xml # 字符串资源 │ │ └── styles.xml # 主题样式 │ └── values-v28/ # API 28+ 样式覆盖 │ └── styles.xml └── src/com/js/fc/ ├── MainActivity.java # 主界面 Activity(核心逻辑) ├── SplashActivity.java # 启动页 Activity └── PtyTerminal.java # PTY 终端 JNI 接口类

03 核心架构

3.1 整体架构图

┌─────────────────────────────────────────────────────┐ │ Android 应用层 │ │ ┌───────────────┐ ┌──────────────────────────────┐ │ │ │ SplashActivity│ │ MainActivity │ │ │ │ (启动动画) │ │ ┌──────────┬─────────────┐ │ │ │ │ │ │ │ 首页 │ 驱动页面 │ │ │ │ │ 2.5s 后跳转 │ │ │ 终端页面 │ 设置页面 │ │ │ │ └───────┬───────┘ │ └──────────┴─────────────┘ │ │ │ │ │ │ │ │ └──────────┤ PtyTerminal.java (JNI接口) │ │ │ └──────────────┬───────────────┘ │ └────────────────────────────────────┼─────────────────┘ │ JNI ┌────────────────────────────────────┼─────────────────┐ │ C/C++ 原生层 │ │ ┌──────────────┴───────────────┐ │ │ │ libptyterm.so │ │ │ │ ┌─────────────────────────┐ │ │ │ │ │ my_openpty() │ │ │ │ │ │ startPty() │ │ │ │ │ │ nativeStartShell() │ │ │ │ │ │ nativeRead/Write/Close │ │ │ │ │ └─────────────────────────┘ │ │ │ └──────────────────────────────┘ │ └──────────────────────────────────────────────────────┘

3.2 页面导航

应用采用单 Activity + 四页面切换架构,通过底部 Dock 导航栏在四个页面间切换:

页面索引功能
首页 (page_home)0系统状态、Root 检测、设备信息展示
驱动 (page_driver)1dits 工具下载与执行
终端 (page_terminal)2PTY Shell 交互终端
设置 (page_settings)3主题、背景、更新、公告、资助

页面切换采用淡入淡出动画(alpha 属性动画,200ms),标签栏随选中状态改变颜色、字号和粗体。

04 启动页 (SplashActivity)

4.1 功能描述

SplashActivity 作为应用入口(LAUNCHER),展示品牌启动动画,2.5 秒后自动跳转到 MainActivity

4.2 动画流程

阶段时间线动画描述
内容渐显100mssplash_content alpha 0→1,持续 200ms
圆点呼吸200mssplash_dot 放大 1x→2.8x,alpha 1→0,持续 500ms,加速插值器
图标弹入500mssplash_icon 缩放 0→1,持续 800ms,OvershootInterpolator(1.5f)
文字渐显900mssplash_text_group alpha 0→1,持续 400ms
副标题渐显1300mssplash_subtitle alpha 0→1,持续 300ms
下划线绘制1600mssplash_underline scaleX 0→1,持续 450ms
跳转2500ms启动 MainActivity,淡入淡出过渡

4.3 界面元素

元素说明
splash_dot16dp 圆形装饰点,背景 splash_dot_bg
splash_icon140dp 应用图标,ic_splash_icon
splash_title"Cloud-Kernel",42sp,颜色 #D97757
splash_subtitle"绝世",24sp,颜色 #888888
splash_underline4dp 高下划线,splash_underline_bg

4.4 状态栏处理

  • 白色状态栏背景 (0xFFFFFFFF)
  • API 26+ 设置浅色状态栏图标 (SYSTEM_UI_FLAG_LIGHT_STATUS_BAR)
  • API 28+ 适配刘海屏 (LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES)

05 主界面 (MainActivity)

5.1 初始化流程

MainActivity.onCreate() 按以下顺序执行初始化:

  1. setContentView(R.layout.activity_main)
  2. applyFullScreenImmersive() — 全屏沉浸式
  3. 页面引用绑定 (pages[0-3], tabLabels, tabIcons, tabContainers)
  4. 终端视图引用 (tvTerminal, scrollTerminal, inputTerminal)
  5. Root 检测按钮绑定
  6. initKernelDriver() — 驱动选择初始化
  7. initBackgroundImage() — 背景图片初始化
  8. initThemeColor() — 主题颜色初始化
  9. initTerminal() — 终端初始化
  10. initDriverPage() — 驱动页面初始化
  11. initSoftwareUpdate() — 软件更新初始化
  12. initKernelUpdate() — 内核更新初始化
  13. 标签页点击事件绑定
  14. fillDeviceInfo() — 填充设备信息
  15. refreshRootStatus() — 刷新 Root 状态
  16. loadCachedContent() — 加载缓存内容
  17. checkAnnouncementPopup() — 检查公告弹窗
  18. 延迟 1000ms → checkSoftwareUpdate()
  19. 延迟 1500ms → checkCloudUpdate()
  20. 延迟 2000ms → syncContent(公告)
  21. 延迟 2500ms → syncContent(资助)

5.2 生命周期

回调行为
onResume()重新应用全屏沉浸式,刷新 Root 状态
onPause()保存所有偏好设置 (saveAllPrefs())
onDestroy()移除所有 Handler 回调,停止 PTY 会话

5.3 全屏沉浸式

applyFullScreenImmersive() 方法设置的标志位:

JAVA
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY

状态栏和导航栏颜色设为 #F9F9F7,API 30+ 额外调用 WindowInsetsController.hide() 隐藏状态栏。500ms 后重新应用标志位以确保生效。

06 首页 —— 设备信息与 Root 检测

6.1 设备信息展示

fillDeviceInfo() 方法通过 Build 类获取以下设备信息:

字段数据来源显示 ID
设备指纹Build.FINGERPRINTinfo_fingerprint
内核版本System.getProperty("os.version")info_kernel
Android 版本Build.VERSION.RELEASE + API Levelinfo_android
设备型号Build.MANUFACTURER + Build.MODELinfo_device

6.2 Root 权限检测

checkRootPermission() 方法采用双重检测策略:

第一层——文件存在检测:遍历以下 su 路径,检查文件是否存在:

  • /system/bin/su, /system/xbin/su, /system/app/Superuser.apk
  • /sbin/su, /system/sbin/su, /vendor/bin/su
  • /data/local/su, /data/local/xbin/su, /su/bin/su

第二层——功能验证:创建临时脚本 check_su.sh(内容为 id),通过 su -c 执行,读取输出并检查退出码是否为 0。

检测结果通过 indicator_root绿色 / 灰色圆点)和 info_root_status("已获取"/"未获取",颜色绿/红)显示。

07 驱动内核管理

7.1 驱动选择器

应用提供 8 个驱动选项按钮:

索引按钮 ID显示文本特殊功能
0btn_drv_1多驱动展开子项选择 (sub_row)
1btn_drv_2绝世KPM旧
2btn_drv_3TwT驱动[推荐]
3btn_drv_4橘子驱动[停服]
4btn_drv_5LQ驱动[推荐]展开触摸模式 (touch_row)
5btn_drv_6Gin驱动
6btn_drv_7绝世KPM[新版]
7btn_drv_8TearGame

7.2 子项选择(驱动 0 专属)

当选择"多驱动"时,展开子项选择行:

索引按钮 ID显示文本
0btn_sub_0ditpro_kpm[很推荐]
1btn_sub_1ditpro_ko
2btn_sub_2qx(10.6)-ko
3btn_sub_3rtdev-ko

7.3 触摸模式(驱动 4 专属)

按钮含义
btn_touch_off"0"不启动
btn_touch_on"1"启动

7.4 防录屏开关

按钮含义
btn_scr_1"1"关闭
btn_scr_2"2"开启

7.5 运行内核命令

点击"运行"按钮时,根据当前驱动类型拼接命令:

SHELL
# 驱动 0(多驱动)
printf "1\n0\n1\n" | {updateFilePath}

# 驱动 4(LQ驱动)
printf "5\n{touchInput}\n1\n" | {updateFilePath}

# 其他驱动
printf "N\n1\n" | {updateFilePath}

执行前检查 updateFilePath 文件是否存在,执行后设置 5 秒冷却时间。

08 驱动管理页面 (Dits)

8.1 概述

驱动管理页面提供 dits 工具的下载和 6 种操作选项的执行。dits 是一个外部二进制工具,通过 execViaScript 方法以 root 权限执行。

8.2 下载流程

  1. 检查 ditsFilePath 文件是否存在,若存在则标记 ditsDownloaded = true
  2. 点击下载按钮或执行操作时自动触发下载
  3. 下载 URL:DITS_DOWNLOAD_URL(123 云盘链接)
  4. 下载完成后自动执行 chmod 755 设置可执行权限
  5. 状态更新为绿色"下载完成",操作按钮文字变为主题色

8.3 操作选项

6 个操作按钮对应 btn_drv_opt0_execbtn_drv_opt5_exec,执行时:

  1. 若未下载,弹出下载提示对话框
  2. 若正在运行,忽略点击
  3. drvOptSelected 设为对应值
  4. 切换到终端页面显示输出
  5. 通过 startExecuteDits(option) 执行

8.4 卡片折叠

驱动管理卡片头部 drv_card_header 点击可展开/折叠 drv_card_body,折叠时 drv_chevron 图标旋转 180°。

09 PTY 终端系统

9.1 JNI 接口 (PtyTerminal.java)

PtyTerminalfinal 类,私有构造函数,通过静态块加载 libptyterm.so

方法参数返回值说明
nativeStartString command, int rows, int colsint[2]启动 PTY 执行命令,返回 [fd, pid]
nativeStartShellString shell, int rows, int colsint[2]启动指定 Shell 的 PTY,返回 [fd, pid]
nativeReadint fd, int maxBytesbyte[]从 PTY 主设备读取数据
nativeWriteint fd, byte[] dataint向 PTY 主设备写入数据
nativeResizeint fd, int rows, int colsvoid调整 PTY 窗口大小
nativeWaitExitint pidint阻塞等待进程退出,返回退出码
nativeCloseint fd, int pidvoid关闭 PTY 并终止进程

9.2 C++ 原生实现 (ptyterm.cpp)

9.2.1 构建配置

Android.mk
LOCAL_MODULE := ptyterm
LOCAL_SRC_FILES := ptyterm.cpp
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)
Application.mk
APP_ABI := armeabi-v7a arm64-v8a
APP_PLATFORM := android-21
APP_STL := c++_static

9.2.2 my_openpty() —— PTY 创建

C
static int my_openpty(int *amaster, int *aslave, char *name,
                      const struct termios *termp,
                      const struct winsize *winp)

流程:

  1. posix_openpt(O_RDWR | O_NOCTTY) 打开主 PTY 设备
  2. grantpt(master) 授予从设备权限
  3. unlockpt(master) 解锁从设备
  4. ptsname(master) 获取从设备名称
  5. open(slave_name, O_RDWR | O_NOCTTY) 打开从设备
  6. 若提供 winsize,通过 ioctl(TIOCSWINSZ) 设置窗口大小

9.2.3 startPty() —— 创建 PTY 并 Fork 进程

C
static jintArray startPty(JNIEnv *env, const char *cmd, jint rows, jint cols)

流程:

  1. 设置 winsize(默认 24 行 x 80 列)
  2. 调用 my_openpty() 创建 PTY
  3. fork() 创建子进程

子进程:

  • setsid() 创建新会话
  • ioctl(slave_fd, TIOCSCTTY, 0) 设置控制终端
  • dup2() 将 stdin/stdout/stderr 重定向到从设备
  • 关闭主设备 fd
  • 设置环境变量:TERM=dumbPATH 为 Android 系统路径,清空 PS1/PS2/PS4/PROMPT_COMMAND/BASH_ENV,HISTFILE=/dev/null
  • 若提供 cmd,执行 sh -c cmd;否则执行 sh
  • _exit(127) 兜底

父进程:

  • 关闭从设备 fd
  • 设置 master fd 为 FD_CLOEXEC
  • 返回 int[2]:{master_fd, pid}

9.2.4 nativeStartShell() —— 启动指定 Shell 的 PTY

nativeStart 类似,区别在于子进程端执行:

C
const char *initCmd = "stty -echo 2>/dev/null; export PS1=''; export PS2=''; "
                       "export PS4=''; export PROMPT_COMMAND=''; exec /system/bin/sh";
execlp(shellPath, shellPath, "-c", initCmd, nullptr);
execl("/system/bin/sh", "sh", "-c", initCmd, nullptr);  // 兜底

9.2.5 nativeRead() —— 读取终端输出

C
JNIEXPORT jbyteArray JNICALL
Java_com_js_fc_PtyTerminal_nativeRead(JNIEnv *env, jobject, jint fd, jint maxBytes)
  • maxBytes 范围限制:≤ 0 时设为 4096,> 65536 时截断为 65536
  • 通过 read() 系统调用读取数据
  • 返回 byte[],若读取失败返回空数组

9.2.6 nativeWrite() —— 写入终端输入

C
JNIEXPORT jint JNICALL
Java_com_js_fc_PtyTerminal_nativeWrite(JNIEnv *env, jobject, jint fd, jbyteArray data)
  • 获取 Java 字节数组长度和内容
  • 通过 write() 系统调用写入
  • 返回实际写入字节数

9.2.7 nativeResize() —— 调整终端窗口

C
JNIEXPORT void JNICALL
Java_com_js_fc_PtyTerminal_nativeResize(JNIEnv *, jobject, jint fd, jint rows, jint cols)

通过 ioctl(fd, TIOCSWINSZ, &win) 发送窗口大小变更信号。

9.2.8 nativeWaitExit() —— 等待进程退出

C
JNIEXPORT jint JNICALL
Java_com_js_fc_PtyTerminal_nativeWaitExit(JNIEnv *, jobject, jint pid)
  • 阻塞调用 waitpid(pid, &status, 0)
  • 若被 EINTR 中断,继续等待
  • 正常退出返回退出码,信号终止返回 128 + 信号编号

9.2.9 nativeClose() —— 关闭 PTY 和终止进程

C
JNIEXPORT void JNICALL
Java_com_js_fc_PtyTerminal_nativeClose(JNIEnv *, jobject, jint fd, jint pid)
  1. 关闭 fd
  2. 向进程发送 SIGTERM
  3. 轮询等待最多 20 次(每次 50ms),检查进程是否退出
  4. 若仍未退出,发送 SIGKILL 强制终止

9.3 Java 层终端管理

9.3.1 终端会话启动

startTerminalSession() 在后台线程中执行:

  1. 通过 computeTermSize() 计算终端行列数
  2. 优先尝试 PtyTerminal.nativeStartShell("su", rows, cols) 启动 root shell
  3. 若失败,回退到 PtyTerminal.nativeStartShell("/system/bin/sh", rows, cols)
  4. 保存 ptyFdptyPid,标记 ptySessionAlive = true
  5. 清空终端显示,调整窗口大小
  6. 启动读取线程

9.3.2 终端输出读取

startPtyReader() 在守护线程中循环读取:

JAVA
while (ptyReading && ptyFd >= 0) {
    byte[] data = PtyTerminal.nativeRead(ptyFd, 4096);
    if (data == null || data.length == 0) break;
    String clean = sanitizeTerminalOutput(chunk);
    if (clean.length() > 0) appendTerminal(clean);
}

9.3.3 终端输出过滤

sanitizeTerminalOutput()isUiTerminalNoise() 负责过滤不需要的输出:

  • ANSI 转义序列过滤:stripAnsi() 移除 ESC 序列(CSI 序列和 OSC 序列)
  • UI 噪音过滤:移除应用的 UI 提示消息(如 [错误]、[提示]、[完成]、[会话已结束] 等)
  • 提示符过滤:移除单独的 $#>% 提示符
  • 命令回显过滤:移除以 #$>% 开头的行,以及以这些符号结尾的路径行

9.3.4 终端大小计算

computeTermSize() 通过测量 TextView 的字符宽度和行高计算最优行列数:

JAVA
float charW = paint.measureText("M");
float lineH = paint.getFontSpacing() + dp(3);
cols = Math.max(20, (int)(w / charW));
rows = Math.max(5,  (int)(h / lineH));

9.3.5 命令发送

sendTerminalCmd() 从输入框获取命令,通过 nativeWrite 写入 PTY master fd,命令末尾追加 \n

9.3.6 会话终止

stopPtySession() 停止读取线程,调用 nativeClose(fd, pid) 关闭 PTY 并终止进程。

10 内核命令执行

10.1 execViaScript()

内核命令通过写入临时 Shell 脚本文件执行,避免命令注入和参数转义问题:

JAVA
private void execViaScript(File parentDir, String scriptName,
                           String cmdContent, ShellLineCallback cb)

流程:

  1. 在 parentDir 下创建脚本文件
  2. 写入 #!/system/bin/sh\n{cmdContent}
  3. 通过 runPtyCommand("su -c 'sh {scriptPath}'", cb) 以 root 权限执行
  4. 执行完成后删除脚本文件

10.2 runPtyCommand()

创建临时 PTY 会话执行命令,逐行回调输出:

JAVA
private void runPtyCommand(String cmd, ShellLineCallback cb)
  • 使用 nativeStart 而非 nativeStartShell(一次性命令执行)
  • 循环读取输出,按 \n 分割逐行回调
  • 忽略 \r 字符
  • 命令结束后调用 nativeWaitExit 获取退出码,然后 nativeClose

10.3 stdbuf 检测

hasStdbuf() 检测系统中是否存在 stdbuf 命令,用于 wrapUnbuffered() 方法。若存在,在命令前添加 stdbuf -oL -eL 以禁用输出缓冲,确保实时获取输出。

11 在线更新系统

11.1 更新架构

应用包含两套独立的更新系统:

更新类型版本检查 URL下载 URL本地文件名
内核更新http://xn--evv35d.top:6861/versionhttp://xn--evv35d.top:6861/Downloadupdate_kernel
软件更新http://xn--evv35d.top:6864/versionhttp://xn--evv35d.top:6864/Downloadupdate_software.apk

11.2 内核更新流程

checkCloudUpdate() # 自动检查(启动时) ├── fetchVersionFile() # GET 版本号,去除非数字字符 ├── 与 cloudVersion 比较 └── showUpdateDialog(newVersion) # 弹窗确认 ├── 取消 → snoozeUpdate(24h) └── 确认 → downloadToFile() ├── 支持 HTTP 重定向(最多 10 次) ├── 实时进度回调 ├── 下载完成 chmod 755 ├── 通过 su 再次 chmod 755 └── executeUpdateFile()

手动检查(checkKernelUpdate())不受 24 小时休眠限制,始终弹出更新对话框。

11.3 软件更新流程

checkSoftwareUpdate() # 自动检查或手动触发 ├── fetchSoftwareVersion() # GET 版本号,去除非数字和点字符 ├── isNewerVersion(serverVer, "1.5")# 语义版本比较 └── showUpdateConfirmDialog() # 弹窗确认 ├── 取消 → snoozeUpdate(24h) └── 确认 → startDownloadApk() └── installSoftwareApk() ├── 复制 APK 到公共下载目录 ├── 构造 ACTION_VIEW Intent └── 调用系统安装器

11.4 下载引擎

downloadToFile() 方法特性:

  • 支持 HTTP 重定向(301/302/303/307/308),最多 10 次
  • 相对 URL 自动解析为绝对 URL
  • 8KB 缓冲区流式写入
  • 每 80ms 回调一次进度(下载量、总量、百分比、速度)
  • 下载完成后自动 chmod 755su -c chmod 755

11.5 更新休眠机制

取消更新后 24 小时内不再弹出相同类型的更新提示,通过 SharedPreferences 存储休眠截止时间戳。

更新使用 HTTP 明文传输,未做签名验证,详见 21.1 安全性

12 内容同步系统

12.1 公告与资助

应用从服务器拉取公告和资助信息:

内容缓存 Key哈希 KeyURL
公告cache_announcecache_announce_hashhttps://xn--evv35d.top/软件公告.txt
资助cache_fundingcache_funding_hashhttps://xn--evv35d.top/资助.txt

12.2 同步机制

syncContent() 方法:

  1. 通过 fetchTextFile() 获取文本内容(5 秒超时)
  2. 计算 SHA-256 哈希
  3. 与缓存哈希比较,相同则跳过
  4. 不同则更新 UI 和缓存

12.3 公告弹窗

应用启动时检查公告更新:

  1. 获取最新公告内容
  2. 计算 SHA-256 哈希
  3. PREF_ANNOUNCE_LAST_SHOWN_HASH 比较
  4. 不同则弹出公告对话框
  5. 用户点击"知道了"后记录已读哈希

12.4 可点击链接

buildClickableAnnouncementText() 解析公告文本中的 URL(https://http://www. 开头),将其渲染为可点击的 ClickableSpan,颜色为主题色,点击后通过 ACTION_VIEW 在浏览器中打开。

13 主题系统

13.1 预设主题

索引名称主色渐变尾色
0柠檬绿#A9E657#CDEE9A
1翡翠绿#10B981#6EE7B7
2红色#EF4444#FCA5A5
3紫色#8B5CF6#C4B5FD
4橙色#F97316#FDBA74

13.2 自定义颜色

通过 Rainbow SeekBar(0-359 色相)选择自定义颜色。SPECIAL_COLORS 数组定义了 9 个渐变色节点,通过 HSV 插值实现平滑过渡:

JAVA
private static final int[] SPECIAL_COLORS = {
    0xFFFF6B6B, 0xFFFFA94D, 0xFFFFD93D, 0xFF6BCB77,
    0xFF4DD0E1, 0xFF4D96FF, 0xFFA55EEA, 0xFFFF6BB3, 0xFFFF6B6B
};

自定义颜色时 themeSchemeIndex = -1,渐变尾色通过降低饱和度(0.45)生成。

13.3 渐变开关

switch_theme_gradient 控制是否启用渐变效果。启用后按钮、进度条等使用 themeColor → themeGradientEnd 的线性渐变(TL_BR 方向)。

13.4 主题应用范围

applyThemeColor() 影响以下 UI 元素:

  • 标签栏文字和图标颜色
  • 设置页标题文字颜色
  • 进度条颜色(PorterDuffColorFilter
  • 按钮背景渐变(applyGradientToButton
  • Switch 组件的 thumb 和 track 颜色
  • Chevron 图标颜色
  • RGB 十六进制标签背景和文字颜色

13.5 主题预览

updateThemePreviewBar() 在设置页显示当前主题的实时预览条,支持纯色和渐变两种模式。

14 背景图片系统

14.1 功能

用户可为首页、驱动页、终端页设置自定义背景图片,并调整透明度。

14.2 图片选择

pickBackgroundImage() 根据 Android 版本采用不同策略:

  • API 33+:先通过 su -c pm grant 授予 READ_MEDIA_IMAGES 权限,再调用 ACTION_OPEN_DOCUMENT 选择图片
  • API 23-32:检查 READ_EXTERNAL_STORAGE 权限,必要时请求运行时权限
  • API 22 及以下:直接启动图片选择器

14.3 图片加载

loadBgImageFromUri() 使用 BitmapFactory.Options 采样加载,限制最大宽度为 2048px,避免 OOM。通过 BitmapDrawable 设置背景,初始 alpha 值由 imgAlpha 决定。

14.4 透明度调节

SeekBar(0-255)控制背景透明度,updateBgImageAlpha() 实时更新三个页面的背景 alpha。

14.5 持久化

图片 URI 通过 takePersistableUriPermission() 获取持久读取权限,URI 字符串和 alpha 值保存到 SharedPreferences

15 动画系统

15.1 弹性动画

springAnim(View v) 实现按钮点击弹性效果:

scaleX/scaleY: 1.0 → 0.88 (100ms) → 1.0 (420ms, OvershootInterpolator 2.4f)

15.2 按压效果

applyPressEffect(View v) 为按钮添加触摸反馈:

事件动画
ACTION_DOWNscale 1.0→0.92 (80ms),叠加半透明黑色前景
ACTION_UPscale 0.92→1.0 (350ms, OvershootInterpolator 2.0f),移除前景
ACTION_CANCELscale 恢复 1.0 (200ms),移除前景

applyPressEffectNoShadow() 是简化版,无前景叠加效果。

15.3 对话框动画

animateUnifiedDialog() 为对话框添加弹出动画:

初始状态: scaleX=0.84, scaleY=0.84, alpha=0 目标状态: scaleX=1.0, scaleY=1.0 (240ms, DecelerateInterpolator 1.5f), alpha=1 (160ms)

15.4 页面切换动画

switchPage() 在页面间切换时:

  • 旧页面:alpha 1→0 (200ms),完成后隐藏
  • 新页面:alpha 0→1 (200ms,延迟 100ms)
  • 标签栏:选中态颜色、字号、粗体变化
  • 轻量弹性动画:scale 1.0→0.94→1.0 (320ms, OvershootInterpolator 1.8f)

16 数据持久化

16.1 SharedPreferences

应用使用两个 SharedPreferences 实例:

实例名用途
kernel_prefs用户偏好设置
cache_prefs缓存内容(公告、资助)

16.2 持久化字段

类型默认值说明
curDrvint0当前选中驱动索引
drvInputString"1"驱动编号
subInputString"0"子项选择
touchInputString"0"触摸模式
scrInputString"1"防录屏开关
bgImageUriStringnull背景图片 URI
imgAlphaint255背景透明度
cloudVersionString"0"云内核版本
drvOptSelectedint-1驱动操作选项
themeSchemeIndexint0主题方案索引
themeGradientEnabledbooleanfalse渐变开关
themeCustomR/G/Bint255/122/255自定义主题 RGB
subMem_0~7int0各驱动的子项记忆
touchMem_0~7int0各驱动的触摸记忆
software_update_snooze_untillong0软件更新休眠截止
kernel_update_snooze_untillong0内核更新休眠截止

17 颜色系统

17.1 颜色定义 (colors.xml)

颜色名称色值用途
bgPrimary#F9F9F7主背景色
bgSecondary#FFFFFF次背景色
bgCard#FFFFFF卡片背景
bgCardHover#F0F1F5卡片悬停
bgSurface#EEF0F4表面色
accentPrimary#007AFF默认强调色
accentPrimaryDark#0066E0深色强调
accentSecondary#66B0FF浅色强调
textPrimary#1A1A2E主文字色
textSecondary#6B7280次文字色
textTertiary#9CA3AF三级文字色
textOnAccent#FFFFFF强调色上文字
successGreen#10B981成功绿
errorRed#EF4444错误红
warningOrange#F59E0B警告橙
borderSubtle#E5E7EB淡边框
borderMedium#D1D5DB中边框
borderAccent#007AFF强调边框
iconActive#007AFF激活图标
iconInactive#9CA3AF未激活图标
terminalBg#F9FAFB终端背景
terminalText#1F2937终端文字
terminalPrompt#007AFF终端提示符
dockBg#E6FFFFFFDock 背景
dockBorder#E5E7EBDock 边框

18 Drawable 资源说明

文件类型说明
btn_outline.xmlshape轮廓按钮
btn_primary.xmlshape主按钮
btn_primary_small.xmlshape小号主按钮
card_bg.xmlshape卡片背景
color_circle_*.xmlshape彩色圆点(蓝/绿/青柠/橙/紫/红)
dialog_bg.xmlshape对话框背景
dialog_btn_cancel.xmlshape对话框取消按钮
dialog_btn_confirm.xmlshape对话框确认按钮
dock_glass_bg.xmlshapeDock 毛玻璃背景
driver_btn_off.xmlshape驱动按钮(未选中)
driver_btn_on.xmlshape驱动按钮(选中)
ic_chevron_down.xmlvector向下箭头图标
ic_drive.xmlvector驱动图标
ic_home.xmlvector首页图标
ic_launcher_background.xmlvector启动器背景
ic_launcher_foreground.xmlvector启动器前景
ic_settings.xmlvector设置图标
ic_splash_icon.xmlvector启动页图标
ic_terminal.xmlvector终端图标
indicator_active.xmlshape激活指示器(绿色圆点)
indicator_inactive.xmlshape未激活指示器(灰色圆点)
seekbar_thumb.xmlshapeSeekBar 滑块
splash_dot_bg.xmlshape启动页圆点背景
splash_icon_bg.xmlshape启动页图标背景
splash_underline_bg.xmlshape启动页下划线
terminal_bg.xmlshape终端背景

19 构建与部署

19.1 构建前提

  • Android SDK(API 29)
  • Android NDK(支持 ndk-build)
  • JDK 8+

19.2 NDK 构建

jni/ 目录执行:

SHELL
ndk-build

生成产物:

  • libs/armeabi-v7a/libptyterm.so
  • libs/arm64-v8a/libptyterm.so

19.3 APK 构建

使用 Android SDK 构建工具:

SHELL
android update project --path . --target android-29
ant debug

或使用 Android Studio / Gradle 导入项目后构建。

19.4 签名与发布

应用使用 HTTP 明文通信,部署时需注意:

  • 确保服务器支持 HTTP 访问
  • 目标设备需已获取 Root 权限
  • 应用通过在线更新分发,初始安装通过 APK 侧载

20 关键类与方法索引

20.1 MainActivity 成员变量

变量类型说明
pages[4]View[]四个页面视图
tabLabels[4]TextView[]标签文字
tabIcons[4]ImageView[]标签图标
tabContainers[4]View[]标签容器
drvBtns[8]Button[]驱动按钮
subBtns[4]Button[]子项按钮
touchBtns[2]Button[]触摸模式按钮
scrBtns[2]Button[]防录屏按钮
curDrvint当前驱动索引
subMem[8]int[]各驱动子项记忆
touchMem[8]int[]各驱动触摸记忆
ptyFdvolatile intPTY master fd
ptyPidvolatile intPTY 子进程 PID
ptySessionAlivevolatile booleanPTY 会话状态
themeColorint当前主题色
themeGradientEnabledboolean渐变开关
bgImageUriString背景图片 URI
imgAlphaint背景透明度

20.2 MainActivity 方法索引

方法说明
onCreate()初始化入口
applyFullScreenImmersive()全屏沉浸式
switchPage(int)页面切换
springAnim(View)弹性动画
applyPressEffect(View)按压效果
showUnifiedNotice(String, String)统一通知弹窗
fillDeviceInfo()填充设备信息
checkRootPermission()检测 Root 权限
checkSu()su 文件检测
refreshRootStatus()刷新 Root 状态
initKernelDriver()初始化驱动选择器
updateDrvUI(int)更新驱动 UI
runKernelInternal(String)执行内核命令
initTerminal()初始化终端
startTerminalSession()启动 PTY 会话
startPtyReader()启动 PTY 读取线程
sendTerminalCmd()发送终端命令
sanitizeTerminalOutput(String)过滤终端输出
stopPtySession()停止 PTY 会话
initBackgroundImage()初始化背景图
pickBackgroundImage()选择背景图
loadBgImageFromUri(Uri)加载背景图
initThemeColor()初始化主题
applyTheme(int)应用预设主题
applyCustomColor(int)应用自定义颜色
applyThemeColor()刷新主题色
initSoftwareUpdate()初始化软件更新
checkSoftwareUpdate()检查软件更新
startDownloadApk()下载 APK
installSoftwareApk()安装 APK
initKernelUpdate()初始化内核更新
checkKernelUpdate()检查内核更新
checkCloudUpdate()自动检查云更新
downloadToFile(String, File, DownloadCallback)通用下载
initDriverPage()初始化驱动页面
startDownloadDits()下载 dits 工具
startExecuteDits(int)执行 dits 操作
execViaScript(...)通过脚本执行命令
runPtyCommand(String, ShellLineCallback)PTY 命令执行
syncContent(...)同步服务器内容
buildClickableAnnouncementText(String)构建可点击公告
saveAllPrefs() / loadAllPrefs()偏好设置读写

21 注意事项

21.1 安全性

  • 应用通过 su -c 以 root 权限执行命令,存在安全风险,仅应在受信任设备上使用
  • 内核文件通过 HTTP 明文传输,未使用 HTTPS 加密,存在中间人攻击风险
  • 下载的内核文件直接赋予可执行权限并执行,未进行签名验证

21.2 兼容性

  • 最低支持 Android 5.0 (API 21),但实际功能依赖 Root 权限和 su 命令
  • 不同厂商的 Android 系统对 PTY 的支持可能不同
  • 存储权限处理区分了 API 33(READ_MEDIA_IMAGES)和 API 23(READ_EXTERNAL_STORAGE
  • 背景图片选择在 API 33+ 设备上通过 pm grant 授权,依赖 su 可用

21.3 性能

  • PTY 终端输出在 4KB 缓冲区中循环读取,高频输出时可能存在延迟
  • 背景图片加载限制最大宽度 2048px,通过采样减少内存占用
  • 下载使用 8KB 缓冲区,进度回调间隔 80ms
  • 更新休眠机制 24 小时,避免频繁网络请求

21.4 代码规范

  • MainActivity.java 将所有逻辑集中在单个类中,约 3400 行,建议按功能模块拆分
  • 硬编码的 URL 和字符串分散在代码中,建议集中管理
  • 部分异常处理使用空的 catch (Throwable t) {} 静默吞掉异常,不利于调试
  • 大量使用匿名内部类和 runOnUiThread,增加了代码复杂度