目录

主页键不走标准 HOME:给海尔 YunOS 电视换上 Aerial 桌面

家里这台电视是 2020 年前后的海尔 LUC65C51,型号名 yunostv_homeshell,Android 5.1.1,32 位,出厂桌面是带开机广告和推荐位的泰坦桌面(YUNOS)。

我想换掉它,理由很朴素:开机先看广告,首页推的全是我不看的东西。

正常 Android 电视换启动器,进设置挑一个就完事。这台电视折腾了我好久,最后发现卡住所有人的不是权限,是一颗键到底发了什么。

一、设置里翻遍了,没有“桌面”这一项

我先是按最省事的思路来:设置里找“默认桌面”。翻了两遍,没有这一项,桌面相关的入口一个都没留,系统设置被砍得很干净。

那就走 adb。先按下信源按钮,进入信源选择界面
信源选择
在这个界面依次按下遥控器的方向键 左-左-上-右,即可打开工厂菜单。
在菜单中打开ADB调试开关即可。然后 查看电视的网络信息拿到IP就可以远程链接了。
adb connect 192.168.8.11:5555 连得上,执行dumpsys、pm list packages 这类只读命令也都正常,看着挺顺利。

装第三方启动器也没什么用,装几个都是同一个结局:按主页键,画面闪一下,又回到那个满是推荐位的泰坦桌面。

二、先让它闭嘴:CleanYourTV 折了

换桌面一时半会儿没戏,我决定先把广告干掉。

第一个正经尝试是 CleanYourTV 这类开源精简脚本。它们维护了一份国产电视可安全停用的系统应用清单,按厂商分好类,思路也不复杂:adb 连上电视,把清单里的包批量 pm disable 或者 pm uninstall --user 0。

脚本在我电脑上跑得很顺。连得上 192.168.8.11:5555,读得到这台机器的一百多个包,也认得海尔的条目。看它把广告和预装应用一条条列出来的时候,我一度以为很快就能收工。

然后进了执行阶段:

1
2
3
4
5
pm disable-user --user 0 com.alira.info
→ SecurityException: Permission Denial

pm disable-user --user 0 com.yunos.advert.service
→ SecurityException: Permission Denial

一行一个,从上刷到底,一个没成。

报错的意思很明确:shell 改不了组件状态,整条路都是堵的,不是个别包受保护。CleanYourTV 的文档里把这种机型归到“无法通过 adb 精简”那一类,我原以为那是免责声明,看来是别人的实测结论。

既然 adb 不行,就换个思路,找自带系统权限的工具,让它在电视上动手,不经过 shell。网上翻到一个「海尔冻结应用」(com.haier.freezeapp),它用的是系统签名,在图形界面里就能停用应用,压根不经过 adb,自然也就绕开了 uid 2000 这道墙。

效果立竿见影。开机广告没了,桌面推荐位不弹了,后台那些进程也不再上报。整个过程不卸载、不 root,在「冻结应用」里点一下就解冻,随时能退回去。

但泰坦桌面还在,主页键照样往它身上跳,广告清干净了,问题一点没解决。

(清单里第 15 项 com.youku.taitan.tv 就是泰坦桌面本身。想彻底断根可以把它也冻掉,但要先把新桌面顶上来,否则按主页键会“没人接”,电视看起来像死机。)

三、那颗键到底发了什么

真正把问题说清楚的是日志。装好第三方启动器之后按一次主页键,然后马上把活动栈倒出来看:

1
adb shell dumpsys activity activities

里面有一条是这样的:

1
2
3
Intent { act=android.intent.action.VIEW
dat=yunostv_homeshell://start_home
cmp=com.youku.taitan.tv/com.youku.tv.home.activity.HomeActivity }

动作是 ACTION_VIEW,不是 ACTION_MAIN,数据部分也不是空的,是一个自家定义的 URI:yunostv_homeshell://start_home。

也就是说,这颗键根本没走系统那套“谁来当桌面”的机制。它拿这个 URI 去问 PackageManager 谁注册了这个 scheme,泰坦桌面是唯一答上来的,于是被拉起。

装多少启动器都没用,原因就在这里。它们声明的是 CATEGORY_HOME,而这台电视不查这一项。

反过来就是一个很具体的机会:只要有个启动器也注册了 yunostv_homeshell,它就能变成主页键的候选。不用求权限,也不用改默认值,这台电视压根没有“默认桌面”这个概念,只认谁响应这个协议。

四、给启动器伪造一个身份

思路定了,接下来是脏活:改 APK。

工具是 Zulu OpenJDK 17.0.21 加 apktool 3.0.3,签名用 jarsigner 走 SHA-256 v1。Android 5.1 只认 v1,这点不能省。

要往 AndroidManifest.xml 的主 Activity 里塞的,就这一段:

1
2
3
4
5
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="yunostv_homeshell" android:host="start_home"/>
</intent-filter>

CATEGORY_DEFAULT 不能漏,隐式意图靠它匹配,漏了就等不到那颗键。

然后重打包、签名、卸载旧版、装新版。签名换了跟原包对不上,必须先卸干净,这一步会丢数据,要留的配置提前记下来。

五、选择框弹出来的那一秒

第一个试验品是 FLauncher,Flutter 写的,代码简单,包也小。

装完,按主页键。

屏幕中间真的弹出了「打开方式」,两个候选并排:FLauncher 和泰坦桌面。

[图待补:FLauncher 与泰坦桌面的「打开方式」选择框]

折腾了几天,头一次觉得这电视算是能自己做主了。再手动触发一次 yunostv_homeshell://start_home,也能直达 FLauncher,协议这条路是通的。

不过高兴没持续多久。

六、每次都要选,这才是真正的问题

这台电视的「打开方式」框,没有「始终」这个按钮。我用 adb 试着把默认项写死,也写不进去。

结果就是每次按主页键都得拿遥控器再选一次。开始还没觉得麻烦,一天按十几次就受不了了:开机要选,退到桌面要选,看完视频回首页也要选。

缺的不是“默认桌面设置”,是有人盯着前台,厂商桌面一冒头就切走。

无障碍服务能做这件事,监听 TYPE_WINDOW_STATE_CHANGED,一看前台是泰坦桌面就切走。只是我手上没有合适的启动器,FLauncher 没这个能力。

七、换成 Aerial

顺着这个需求找到 Aerial(pengchujin/aerial-tv,app.orchard.tv):tvOS 风格的界面,底部应用货架,苹果航拍素材做的屏保,控制中心,无广告。最关键的是它自带一个叫「Aerial 桌面守护」的无障碍服务,做的正是这件事。

它要求最低 Android 5.0,这台 5.1.1 刚好够。拆开看了下,minSdkVersion: 21,带 armeabi-v7a 的 32 位库,版本 1.56,都对得上。

改法和之前一样,只往 manifest 里加了那个 intent-filter,dex 和资源没动,功能跟官方原版一致,只是多了个能被这颗键认出来的身份。

八、它自己把守护打开了

装完 Aerial 要过一遍授权,我照着官方脚本逐条跑,结果一半顺利一半报错。

pm grant 那几条基本都过了,WRITE_SECURE_SETTINGS、SYSTEM_ALERT_WINDOW、WRITE_SETTINGS 都没问题。下面两条连着报错:cmd notification allow_listener 直接 cmd: not found,5.1 那个年代还没有 cmd 这个命令;settings put secure enabled_accessibility_services 被拒,因为 shell 没有写 secure settings 的权限。

第二条报错的时候我以为完了。无障碍服务开不起来,守护就是空的,前面那些等于白做。

后来发现第一行就是答案:权限是发给 App 的,不是给 shell 自己用的。Aerial 带着 WRITE_SECURE_SETTINGS 启动,起来之后自己把守护开了,不需要我用 adb 硬塞。

查了一下:

1
adb shell dumpsys accessibility

输出里有这么一段:

1
2
services:{Service[label=Aerial 桌面守护, feedbackType[FEEDBACK_GENERIC],
capabilities=8, eventTypes=TYPE_WINDOW_STATE_CHANGED, ...]]}

看到这行就放心了。

顺手还发了两个配置广播,都回了 result=0:一个 keep_adb true,让 ADB 常开(这台电视开发者选项里没有“常开”开关,休眠就掉线,每次都要重新进设置点一遍,很烦);一个 own_screensaver true,把屏保也接管过来。

启动 Aerial,先是它的“设为主屏幕”引导页。走完就是正常桌面,控制中心里有音量、亮度、信号源、设置和个性化(但很遗憾 信号源功能无法支撑)。

九、验收

按官方文档的清单逐条跑了一遍,下面是真实返回,不修饰:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#1  dumpsys package app.orchard.tv | grep versionName
versionName=1.56 ← 已安装 ✅

#2 cmd package resolve-activity ... HOME
/system/bin/sh: cmd: not found ← 本机没有 cmd
(备用方案 pm resolve-activity 也是 Error: unknown command)

#3 settings get secure enabled_accessibility_services
app.orchard.tv/app.orchard.tv.guard.HomeGuardService ← 守护已启用 ✅

#4 dumpsys accessibility | grep -c -E 'label=(Aerial|app.orchard.tv)'
1 ← 守护在运行 ✅

#5 input keyevent KEYCODE_HOME
#6 sleep 3; dumpsys window | grep mCurrentFocus
android/com.android.internal.app.ResolverActivity ← 弹出选择框

按主页键,现在弹的是三选一:

pasted_1793589619774_gbg0pf.png

第 2 步和第 5、6 步说明两件事:没有 cmd 这个入口,选择框也不记选择。第 3、4 步说明守护在跑,这才是它能用的原因。

十、写在最后

用了一段时间,日常其实感知不到选择框的存在。系统起来之后会弹出一次选择框,按下Aerial后,再按下HOME按键会自动回到Aerial,日常使用没问题。

不完美,但一台 2020 年的、被厂商锁死的电视,能到这一步我已经挺满意了。

这事的钥匙不在“默认桌面”那个开关上,而在主页键到底发了什么 intent。海尔用的是 yunostv_homeshell://start_home,别的国产定制系统估计也有自己的一套。与其在设置里翻半天,不如按一下键,把 dumpsys activity activities 倒出来看看。

附:留下的东西

改好、装到电视上的启动器(都加了 yunostv_homeshell 协议):

文件 包名 说明
aerial-homeshell.apk app.orchard.tv Aerial 1.56,当前主用
flauncher-homeshell.apk me.efesser.flauncher FLauncher,留作备用

工具链是 Zulu JDK 17.0.21 加 apktool 3.0.3,签名走 jarsigner 的 v1 方案。

想撤销的话,adb uninstall app.orchard.tv 卸载掉就行,原桌面和系统都没动过;冻掉的那批应用在「冻结应用」里解冻即可恢复。

主要是没系统的签名文件,uid等级太低,root尝试了几个exp也没成功,也懒得继续折腾了,怕弄不好这东西又不好救砖。