我这台是华为畅享 70S,Android 12,Termux 0.118。下面这些命令都是在这台机器上跑出来的。
11 月 3 号凌晨两点多,手机上 7Tan 又打不开了。
页面一直转,控制台底下那行红字是「服务无响应(可能已挂起)」。我点「一键重启服务」,没动静;再点,还是没动静;退回管理器点「③ 打开 7Tan」,照样空转。
第一反应是内存。开了监控盯了十几分钟,python 主进程常驻 112MB,内存还空着一大半,根本不是内存的事。
后来把 /proc 翻了一遍才看清:进程还在,9900 端口也还占着,但它一行代码都不跑。安卓管这叫被冻住了,不是我程序写崩了。
先别急着一刀杀掉
打不开有三种,长得都很像,但处理办法完全相反。当时记下来的对照:
| 你看到的现象 | Termux 进程 | 9900 端口 | 实际是什么 |
|---|---|---|---|
| 页面转很久,最后弹「服务未运行」 | 还在 | 占着,但请求不回 | 被冷冻 |
| 浏览器立刻说「无法连接」 | 没了 | 没人监听 | 已经退出 |
| 页面能开,点某个功能才报错 | 在 | 正常 | 服务活着,是另一码事 |
头一行和第二行最容易混。一个得叫醒,一个得重新拉起来。分不清就动手,基本等于瞎试。我前面几个小时就这么白耗掉了。
三种情况画在一张图上,中间那个才是冷冻
重点看 wchan 那一行
Termux 里贴这四行,不用 root:
PID=$(pgrep -f mobile/start_web.py | head -1)
echo "PID=$PID"
cat /proc/$PID/wchan; echo
grep -E '^(Name|State)' /proc/$PID/status
curl -m 3 -s -o /dev/null -w 'HTTP %{http_code}\n' http://127.0.0.1:9900/api/healthwchan 那一行有三种值:
do_epoll_wait,正常,闲着等请求,服务是好的
__refrigerator,被系统冻住了
空的而且 State 是 Z,僵尸,杀掉重开
我冻住那次,抓到的原样是这样:
PID=9582
__refrigerator
Name: python
State: D (disk sleep)
$ curl -m 3 -s -o /dev/null -w 'HTTP %{http_code}\n' http://127.0.0.1:9900/api/health
HTTP 000 # 3 秒超时,一个字节都没回来注意 wchan 得在 Termux 里读。我从电脑 adb 读同一个进程,读回来是 0,那是权限不够,不代表它没被冻。
这里有个坑我踩得很深:冻住的进程,端口还是占着的。TCP 那三次握手是内核替你完成的,程序本身根本没接手。所以「端口连得上」这件事,一点都证明不了服务活着。
同一个冻死的进程,我在手机上量过:TCP 连接 1 毫秒就建好了,真发一个 HTTP 请求,4 秒没人应。
也因为它占着端口,自启脚本去拉新进程时会一直卡在「端口 9900 被占用,等待旧进程退出…」,等一个永远不会退出的人。日志还照样打 health ok,看着挺正常。
为什么偏偏是 Termux
Android 11 之后有个 cached app freezer。App 一退到后台,系统就把它的整组进程按暂停键冻起来,既不占 CPU,下次打开还快,代价是这些进程不再回任何请求。
Termux 正好踩在这个位置上:它没有常驻的前台服务身份,界面一退后台,整组进程就被划进 cached。
更难受的是,冻着的进程杀不掉。D 状态是不可中断睡眠,SIGKILL 挂着等不到处理。我执行 kill -9,直接回 Permission denied。所以「点重启没反应」真不是按钮坏了,是没人叫得醒它。
三步把它叫醒
第一步,把 Termux 切到前台。点一下图标、进到界面就行,一个字都不用敲。三秒内 wchan 从 __refrigerator 变回 do_epoll_wait,服务自己就活了。
第二步,回管理器点「③ 打开 7Tan」。管理器会先探一次端口,回 200 就直接加载。1.2.9 之后加了看门狗,页面开着的时候每 5 秒探一次,连着两次没响应(大约 10 秒)它就自己把恢复命令投递出去,不用我手点。
第三步,前两步都不行,才用 force-stop。这一步是有代价的,Termux 里所有会话都会结束,正在跑的任务一起清掉。
有电脑:adb shell am force-stop com.termux
没电脑:设置 → 应用 → 应用管理 → Termux → 强行停止
顺序千万别反。先 force-stop 再切前台,等于白忙。它本来没死,你这么一弄直接全干掉,之前跑的进度也没了。
根上的四个开关
A 和 D 在手机上点就行,B 和 C 得写系统设置。
A,电池白名单。设置 → 电池 → 应用启动管理 → Termux 和 7Tan 管理器 → 关掉「自动管理」,改「手动管理」,自启动、关联启动、后台活动三个全打开。
插着电脑的话,等价于这几行:
adb shell dumpsys deviceidle whitelist +com.termux adb shell dumpsys deviceidle whitelist +com.seventan.booter adb shell "dumpsys deviceidle whitelist | grep -i termux"
B,把冷冻本身关掉。
adb shell settings put global cached_apps_freezer disabled adb shell settings get global cached_apps_freezer # 想恢复:adb shell settings put global cached_apps_freezer enabled
有的系统不认这个键,读回来是 null。那就改另一处:adb shell device_config put activity_manager_native_boot use_freezer false,改完重启一次。我这两处都动了。
C,幻影进程杀手。Android 12 起多了个 phantom process killer,专清后台 fork 出来的子进程,Termux 里跑 Python 正是它的重点对象。表现就是「服务跑着跑着没了,什么都没报」。
adb shell settings put global settings_enable_monitor_phantom_procs false adb shell settings get global settings_enable_monitor_phantom_procs
D,华为自己那一层。最近任务里把 Termux 卡片往下拉,点小锁,锁住之后一键清理不会清它。开发人员选项里「不保留活动」「后台进程限制」都改回默认,这两个只要动过就会误伤。
四个开关,A 和 D 都在图形界面里,不用电脑
没电脑的能弄一半。A 和 D 纯粹点界面,用不着电脑;B 和 C 是 global settings,Termux 默认没权限写,会抛 SecurityException。要弄就只能借一次电脑,插上线跑那几行,跑完拔线,改动是持久的。或者装 Shizuku,无线调试启动,再授权 Termux 去执行 settings。能用,但为了这一件事多装个软件,我不太推荐。
怎么算是修好了
验的时候我是这么看的:
# 1. 压后台十分钟再切回来
adb shell am start -n com.termux/.HomeActivity
adb shell "curl -m 3 -s -o /dev/null -w '%{http_code}' http://127.0.0.1:9900/api/health"
# 要 200,不是 000
# 2. 看 wchan
cat /proc/$(pgrep -f mobile/start_web.py | head -1)/wchan
# 要 do_epoll_wait,不该再出现 __refrigerator
# 3. 看看门狗有没有在动
adb logcat -s 7TanBoot正常的时候 health 返回 {"status":"ok","version":"1.0.23"},版本号跟着你的包走。
今天在这台机器上复查:health 200,两个 setting 一个是 disabled 一个是 false,白名单里能找到 com.termux。
代价是有的。关掉冷冻不是白得的,后台进程不再被系统暂停,待机耗电会多一点。多多少我测不准,但确实有。所以别一次全上:先做 A 和 D,看一天;还冻,再加 B;还有问题,才动 C。
要退回去就把值改回来:
adb shell settings put global cached_apps_freezer enabled adb shell settings put global settings_enable_monitor_phantom_procs true adb shell dumpsys deviceidle whitelist -com.termux
管理器那边四层兜底,前三层负责叫醒,第四层才防得住再被冻
还有一点,看门狗只在我看着页面的时候跑,退到后台就停了,为的是不耗电。所以「完全不开 App、只用系统浏览器打开 9900」这条路,还是只能靠 2 分钟一次的心跳兜底,中间断掉的那两分钟是真真空。想彻底不断,还是得把 B 和 C 关掉。
几个被问到的
改了还是在冻
先确认值真生效,settings get 读回来是 disabled 吗。有的系统改完要重启一次才认。华为的「应用启动管理」和「电池优化」是两个独立开关,只改一个不算改完。
会不会影响别的 App
B 和 C 是全局设置,会改变所有后台 App 的行为,耗电上升也是全局的。白名单只影响加进去的那几个,很安全。
要 root 吗
不用。上面所有命令 adb shell(shell 用户)就能跑,root 只是让你不必插电脑。
以前的版本为什么没这毛病
以前手机上的服务是靠 .bashrc 起的,你打开 Termux 它才跑,进程活得短,来不及被冻。现在改成常驻了,反而正面撞上冷冻机制。功能变强带来的副作用。
写完这段,我又压了十分钟后台再切回来,health 还是 200,wchan 是 do_epoll_wait。
要是你照做完还是冻,把机型、/proc/$PID/wchan 那行输出、还有两个 settings 的值贴在下面。机型不同值会差一点,但 __refrigerator 这个词是不会变的。