作者: Zeeko

  • 修复小新 Pad Pro 2021 运行 GSI 时的亮度问题

    This entry is part 3 of 3 in the series 小新 Pad Pro 2021

    上回书说道,我给小新 Pad Pro 2021(aka. Lenovo J716F)装上了 GSI 系统。当时用的联想 Y700 的模块勉强修复了自动亮度失效的问题。最近我心血来潮,经历了快 10 小时的摸索,终于为 J716F 制作出了专属的 Magisk 模块 —— lenovo-j716f-gsi-fix 年轻人的第一个 Magisk 模块

    这个模块与上一篇文章中的修复模块冲突,请先卸载之前的模块,再启用这个模块。重启平板之后,你应该会发现:

    • 亮度调节的最低档不再是「伸手不见五指」之黑了
    • 在系统设置中的 Phh Treble Settings / Lenovo features 中可以启用 DT2W

    不过可惜的是,磁吸锁屏开关功能还是无效。可能是缺少驱动程序导致的

    解决问题的历程

    自动亮度、自动旋转、亮度等级

    参考 Y700 模块的内容,自动亮度、亮度等级这类设置可以通过 vendor_hardware_overlay 控制。最简单的做法就是从原厂镜像中提取这些配置文件,然后通过 Magisk 模块安装到设备上。

    对于小新 Pad 而言,提取原厂文件的方法很简单,直接「只读」挂载原厂镜像的 system.img 文件就好了:

    sudo mount -t ext4 -o loop,ro ./system.img ./payload-fs/sys
    

    接着参考这篇帖子的内容 操作,就可以得到原厂的 hardware overlay。这篇帖子用到了 phhusson/vendor_hardware_overlay 项目,该项目并不能支持所有的厂商 hardware overlay 配置,需要手动删除不支持的配置。这是一个非常繁琐的体力操作,我制作了一个小工具来简化这一个过程:

    1. 把全部的 vender hardware overlay 文件拷贝到 phhusson/vendor_hardware_overlay 项目
    2. 执行下面的代码,导出所有不兼容的配置到一个临时文件中
    # 在 phhusson/vendor_hardware_overlay 根目录下执行
    ./tests/tests.sh | grep J716F | tee test-out
    
    1. 手动编译这个工具 https://github.com/ZeekoZhu/projects/tree/gsi-overlay-tool/apps/gsi-overlay-tool ,使用 fix 命令批量删除所有不兼容的配置
    ./dist/apps/gsi-overlay-tool/net7.0/GsiOverlayTool fix /path/to/test-out /path/to/phhusson/vendor_hardware_overlay/overlay/
    

    得到设备的 overlay 文件后,打包生成一个 apk 文件,放到一个 Magisk 模块中即可(参考操作)。

  • 网上冲浪指南 – 002

    This entry is part 2 of 3 in the series 网上冲浪指南

    Kitty https://sw.kovidgoyal.net/kitty/

    Kitty 是我现在的主力终端模拟器,它使用 GPU 渲染,性能强劲,并且功能强大:

    • 支持 CLI 命令操作 Kitty 界面(窗口、Tab),可以方便地用脚本打造自己的终端工作环境
    • 支持图像协议,cat 一个图片、视频会直接在终端展示,而不是被二进制输出糊一脸

    分享一下我使用 Kitty 快速启动工作环境的 fish shell 脚本:

    function work-start
      cd ~/path/to/project
      # 分屏打开一个新的 kitty 窗口
      set win1 (kitty @ launch --location split --copy-env --cwd current)
      # 分屏打开一个新的 kitty 窗口
      set win2 (kitty @ launch --location split --copy-env --cwd current)
      # 在窗口 1 中登录远程开发服务器
      kitty @ send-text --match id:$win1 'ssh foo@remote-server -t "screen -r dev"\n'
      # 在窗口 2 中启动代码同步服务
      kitty @ send-text --match id:$win2 'lsyncd ./frontend.lsyncd\n'
      # 光标聚焦回当前窗口
      kitty @ focus-window --match id:$KITTY_WINDOW_ID
    end
    
    在终端查看图片

    Chezmoi https://www.chezmoi.io

    Chezmoi 是一个基于 Git 管理 dotfiles 的命令行工具,我的个人目录下有各种各样的配置文件,为了能够在台式机跟笔记本上有相同的体验,我会使用 Chezmoi 定期在两台电脑上同步配置。Chezmoi 的这些功能我认为非常重要,能够极大地简化在多设备上维护配置文件的操作:

    • 文件模板,允许我们在应用配置之前使用变量替换模板文件中的占位符,这样类似主机名、用户名这样的每台机器上可能不尽相同的信息就可以从配置文件提取出来,方便复用配置模板
    • 密码管理器,像 ssh key 这样的信息并不适合明文存储在 Git 中,好在 Chezmoi 的模版语法中允许我们调用常用的密码管理器,从中读取信息

    搞机工具箱 https://www.coolapk.com/apk/com.byyoung.setting

    这是一款功能丰富过头的 Android 手机工具箱,其功能包括但远不限于:

    • Magisk 模块管理
      • 模块安装、卸载、编辑、更新、备份
      • 音量键救转
    • Xposed 模块管理
      • 模块安装、卸载、编辑、更新、备份
    • 应用管理
      • 系统、用户应用安装、卸载、冻结、编辑权限、多开、提取 apk、设置程序语言、备份、还原、IFW 设置
      • 替换国产系统恶心人的应用安装器
    • 系统工具
      • SWAP 设置
      • 查看 Wifi 密码
      • 修改 Host

    这些功能只是我最常用的,它们只是搞机工具箱全部功能的冰山一角,而且由于功能过多且晦涩,导致用户体验很差,上手难度比较高。
    不过总的来说,瑕不掩瑜,是一款不可多得的搞机必备应用。

  • 网上冲浪指南 – 001

    网上冲浪指南 – 001

    This entry is part 1 of 3 in the series 网上冲浪指南

    AstroNvim https://astronvim.com

    一个全功能的 NVim 发行版,开箱即可获得非常完整的 IDE 体验,预设的快捷键很符合我这个前 SpaceVim 用户的使用直觉。它跟 SpaceVim 有很多不同的地方:

    • AstroNvim 使用 lua 作为配置语言,官方提供了一个用户配置模板帮助用户自定义 AstroNvim。
    • 正如它的名称所示,AstroNvim 只支持 neovim 。

    这是我的 AstroNvim 配置 https://github.com/ZeekoZhu/AstroNvim

    Burning Vocabulary https://burningvocabulary.com

    这是一款简单好用的背单词浏览器插件,网上冲浪遇到不认识的单词,只需要用鼠标选中它,插件就会自动查询翻译并展示翻译结果,并且在之后的浏览中,会自动在网页上标注查过的生词。我个人认为,类似的浏览器插件有很多,但上手难度比它低、使用的顺滑度比它高不多:

    我现在会把 Burning Vocabulary 翻译的目标语言设置成英文(就是用英文解释英文),跟沙拉词典搭配使用,因为沙拉词典支持的词典源更加丰富,让我暂时还不能放弃。

    System Rescue https://www.system-rescue.org

    这是一个 Linux 系统急救工具箱,基于 Arch Linux 开发,一共 700M 的镜像大小,可以使用 Ventoy 制作成 Live CD 使用。

    最近我在扩容工作用笔记本 /root 分区时发现了它,自带图形界面跟 GParted,比单纯的 Arch Install ISO 要方便很多。

  • 给大代码库的类型检查提速

    This entry is part 4 of 4 in the series Nx Monorepo Experience

    当代码库达到一定规模后,在每次提交前进行完整的 TypeScript 类型检查会非常耗时,就像下面的代码库,执行完整的检查需要 47s,如果每次代码提交时执行类型检查,开发者都得等上接近 1 分钟才能完成 git commit,极大的拉低了开发体验。

    ───────────────────────────────────────────────────────────────────────────────
    Language                 Files     Lines   Blanks  Comments     Code Complexity
    ───────────────────────────────────────────────────────────────────────────────
    TypeScript                3721    271374    23335     21340   226699      16639
    
     nx run-many -t check --all
    
          nx run icons:check (3s)
          nx run visual:check (4s)
          nx run eslint-plugin-merico:check (4s)
          nx run vdev-api:check (176ms)
          nx run nx-plugin:check (3s)
          nx run illustrations:check (4s)
          nx run shared-lib_temp:check (4s)
          nx run fekit:check (12s)
          nx run charts:check (14s)
          nx run main:check (39s)
    
     —————————————————————————————
    
     >  NX   Successfully ran target check for 10 projects (47s)
    

    那么为什么会这么慢呢?责任真的全在 nodejs 的性能上?

    为什么这么慢

    TypeScript 文档中这样写道:

    Rather than doing a full check of all d.ts files, TypeScript will type check the code you specifically refer to in your app’s source code.

    所以当你的 monorepo 中存在项目间引用的时候,执行 tsc -p lib-bob/tsconfig.json 会同时在 lib-bob 及其依赖的 lib-alice 上运行类型检查,这意味着,如果你在 monorepo 中对所有项目分别执行 tsc -p xx/tsconfig.json,被其他项目依赖的项目,会被重复检查多次!

    为了避免这种问题,TypeScript 的 build mode 提供了一种基于增量构建的解决方案。启用 build mode 后,庞大的代码库可以被拆分成多个项目分别被 tsc 构建,tsc 会缓存每个项目的构建结果,当一个项目被其他项目引用的时候,这个项目不会被重新构建而是使用之前的构建结果。在后续的执行中,只有发生变动的项目才会被重新构建。

    如何配置 build mode

    启用 build mode 的方法比较简单,你只需要调整 tsconfig.json 中以下几个选项即可:

    • compilerOptions.composite: true,用来标记这个项目可以被增量构建
    • compilerOptions.noEmit: false,启用增量构建必须允许 tsc 生成文件
    • compilerOptions.outDir: path/to/tsc-out,设置生成文件(包括缓存文件)的路径,记得加入 gitignore
    • compilerOptions.emitDeclarationOnly: true,如果你使用 tsc 构建 js 文件,可以不设置这个选项
    • references,把依赖项目的 tsconfig 路径添加到这里,让 tsc 可以使用这些依赖项目的构建缓存
    • compilerOptions.rootDir,不建议设置,避免构建缓存生成到 outDir 目录之外

    现在,你就可以使用 tsc -b (注意,不是 tsc -p) 来构建你的项目了,同样还是开头展示的代码库,现在重新运行类型检查:

     time nx run-many -t check --all --skip-nx-cache
    
          nx run illustrations:check (3s)
          nx run icons:check (5s)
          nx run visual:check (5s)
          nx run shared-lib_temp:check (781ms)
          nx run vdev-api:check (5s)
          nx run eslint-plugin-merico:check (832ms)
          nx run nx-plugin:check (2s)
          nx run fekit:check (10s)
          nx run fekit-e2e:check (2s)
          nx run charts:check (12s)
          nx run main:check (27s)
    
     ——————————————————————————————
    
     >  NX   Successfully ran target check for 11 projects (44s)
    
    
    ________________________________________________________
    Executed in   44.50 secs    fish           external
       usr time  119.40 secs  213.00 micros  119.40 secs
       sys time    6.17 secs   67.00 micros    6.17 secs 
    

    看起来似乎长进不大,再运行一遍试试?

     time nx run-many -t check --all --skip-nx-cache
    
          nx run illustrations:check (752ms)
          nx run visual:check (760ms)
          nx run icons:check (768ms)
          nx run shared-lib_temp:check (732ms)
          nx run fekit:check (880ms)
          nx run vdev-api:check (1s)
          nx run eslint-plugin-merico:check (731ms)
          nx run charts:check (900ms)
          nx run nx-plugin:check (756ms)
          nx run fekit-e2e:check (773ms)
          nx run main:check (1s)
    
     —————————————————————————————
     >  NX   Successfully ran target check for 11 projects (4s)
     
    
    ________________________________________________________
    Executed in    4.49 secs    fish           external
       usr time   13.51 secs    0.00 micros   13.51 secs
       sys time    1.86 secs  369.00 micros    1.86 secs
    

    类型检查速度变得飞快,这是因为 tsc 复用了第一次生成的构建缓存。如果你这时检查 outDir,你就会发现除了 d.ts 之外,tsc 还生成了 tsbuildinfo 文件,这就是 tsc 用来判断是否可以复用 d.ts 的关键。

     ls dist/out-tsc/icons
    components  tsconfig.build.tsbuildinfo
    

    可以想象的是,在平常开发过程中,每个 commit 通常只会修改一小部分文件,如果我们把代码库中较大的项目(例如上面的 main 项目,代码量有 18w 行)进一步拆分,就可以更加充分地利用增量构建的特性,运行类型检查的范围就会更小,速度就会更快。

    维护 monorepo 中的项目依赖

    细粒度的拆分项目在提高类型检查速度的同时,又会带来一个新的问题,由开发者人工维护项目之间的 references 字段会变得很麻烦,而且容易出错。为了减少人工操作的负担,我开发了一个小工具 —— ts-sync-ref,它会分析项目的 monorepo 内依赖,进而更新 tsconfig.json 的 references 字段。

    # 安装 ts-sync-ref
    npm install -g @zeeko/ts-sync-ref
    # 更新 my-lib 的依赖到 tsconfig.json 中的 references 字段
    cd /path/to/my-monorepo
    ts-sync-ref -p packages/my-lib/tsconfig.json -f 'packages/my-lib/src/**/*.ts'
    

    你可以阅读 ts-sync-ref 的说明文档、代码,进一步了解使用方式及其实现原理。

    结论

    Monorepo 的组织方式有很多种,不管你在用什么工具管理你的 TypeScript monorepo,不妨试试通过 TypeScript 的 Project Reference 将大代码库拆分成多个项目,不仅可以提升类型检查、构建速度,还可以减少编辑器的内存占用,极大地提高开发体验。

    不过,需要注意的是,直接启用 Project Reference 可能会给你的项目带来一些影响,导致现有的构建脚本出错,例如:

    最后,如果你有兴趣的话,也欢迎你在评论区分享你的项目执行类型检查的方案。

  • 摩托新手的天鹰 TS150 2023 特仕版磨合期体验

    之前没接触过摩托车,通勤用的都是小电驴,今年拿了摩托车驾照后就加钱买了第一辆摩托车。

    刚入手的第一感觉就是体积大、车身重,骑了一段时间后发现这是俩优点:

    • 体积大,坐垫空间也大,后座体验更好,不会觉得挤
    • 车身重,跑到 60 km/h 以上很稳定,不会像小电驴有种轻飘飘的感觉

    很多人在买车前都比较关心下面的几个问题,我用自己的体验来回答一下:

    关于震动:
    我没有骑过其他的摩托车,跟我之前的小电驴比起来肯定更抖,但在可接受的范围内。连续骑行超过 1 小时,稍微会感觉手麻。然后就是车头在低速震动的时候有“哒哒”的响声,没找出来是什么零件发出的声音,最后就只能装作自己听不见了。

    关于减震:
    不能说跟小电驴的减震没有区别,只能说减震的差距不明显,过减速带、坑洼路面还是尽量慢行吧。

    关于油耗:
    11 升的油箱,加满油 70 多块(2023 年 5 月),夏天极限续航保守估计 350 公里左右。我都是在市区、郊区骑行,感觉这点儿油耗不值得花时间记录,油耗记录 App 装上没多久就卸载了。

    因为没有骑过其他的摩托车,我说不出这车相较于其他车的优点,但是使用过程中印象深刻的槽点还是有一些的:

    • 自动起停:骑行过程中停止超过 3 秒,车辆就会自动熄火,非常适合等灯过路口的场景。如果发动机温度足够,可以直接拧油门重新点火。但是如果长时间熄火等待,发动机降温,就没法用油门启动了,什么时候会无法通过油门启动是无法预测的,所以还是得习惯通过点火开关启动。
    • 车机互联:因为有手机投屏功能,所以我没有安装手机支架,而是把手机放在车头包里面,但是 Moto Fun 的互联功能实在太脆弱了,经常会断开连接。往往想要看看导航路线的时候,车机上显示的就只有一个互联用的二维码。综合我这么长时间的使用体验,开启车机互联并用手机投屏导航,大概有 50% 的时间投屏可以正常工作,40% 的时间断开投屏显示自带的地图,10% 的时间连接完全断开。

    最后分享一下新手的改装,提车没多久就是 618 了,于是就上网整了一些改装配件,主要是为了增强舒适性,毕竟踏板主打的就是骑行舒适度:

    • 加高的风挡,顺便前移后视镜,原装后视镜空出来后可以装个 10 mm 正牙装饰螺丝
    • 护杠,除了防撞还可以提供更大的脚踏空间,另外还可以把背包通过护杠绑在油箱上,非常实用
    • 带靠背的尾箱,需要改装尾箱架,拆装尾箱架需要 13 mm 扳手
    • 带腰靠的坐垫,腰靠功能几乎感受不到,但是可以很好的分隔前后坐的座位空间
    • 180 度后视镜,补盲效果差强人意,正常的小汽车进入左右后视镜盲区之后就会出现在这块镜子的视野中。但是,如果旁边车道的是个五菱 mini 这类的小车,就会被我的肩膀挡住,反而不容易发现,接下来准备试试粘在左右后视镜上的补盲镜

    年轻人的第一次摩托车抛锚

    没想到不到半年时间,我就遇到了第一次摩托车抛锚 —— 无法点火。经过排查后发现是我下车熄火后忘了断电就着急忙慌地离开了,等三小时后回到车子面前的时候,车辆电池电量所剩无几,只能勉强维持屏幕亮起,无法点火。还好停车位置附近就有修理店,花了 40 人民币搭电才重新启动发动机。

    由于电池缺电,重新启动发动机后需要保持发动机持续工作,给电池充电。稳妥起见,我关掉自动起停功能,连着跑了 10 公里,确认熄火后能够正常启动才回了家。

    总结下来,要避免类似情况发生得养成肌肉记忆,熄火后记得断电。

  • 如何使用 Zerotier 连接你家中的设备

    我在家里的旧笔记本上使用 Open My Vault 建立了 NAS,不过我只能在家里连上 WiFi 才能访问它。在过年回老家、出门旅游或者外出办公的时候就没法使用了。虽然在这些场景经常用不上 NAS,不过,“我可以不用,但不能没有”。

    经过一番调研后,我发现我需要的是一个 VPN 软件,通过 VPN 安全地访问运行在家里的网络服务。基于部署难度上的考量,我选择了 zerotier,这是一款非常简单易用的 VPN 软件,免费版可以连接 25 个节点,对于我来说,完全够用了。但是,在国内的网络环境下,节点间的连接往往不太稳定,我在国内没有自己的公网 IP 服务器,所以借助一台香港服务器,来提高 zerotier 网络的稳定性。

    首先,在 my.zerotier.com 创建一个虚拟网络,我选择的私有网段是 10.2.2.0/24,因为这个网段不容易跟常见的家庭路由器内网撞车。

    家里的网络有全局透明代理,可以直接在运行 NAS 的服务器上使用官方的 zerotier 客户端加入 zerotier 网络。

    我没有在路由器上安装 zerotier:

    • 我的 OpenWRT 虚拟机系统版本太奇葩了,没法从官方源安装 zerotier
    • 我希望路由器的功能尽量少一些,毕竟 OpenWRT 跟日常使用的 Linux 系统有很大区别,对我而言有额外的维护负担

    我的 VPS 在香港,也需要加入 zerotier network,直接使用官方的 Linux 客户端就行,我并没有在 VPS 上建立 zerotier moon 服务,这跟我手机上的连接 zerotier 的方式有关。

    手机有时会出门,而且没法设置多个代理,所以就用 v2ray 客户端(SagerNet)将所有访问 10.2.2.0/24 的请求转发到 VPS 服务器。因为 VPS 已经加入了 zerotier 网络,所以手机上就不用安装 zerotier 客户端。笔记本电脑也是同理,这样做还可以避免 zerotier VPN 跟工作 VPN 冲突。

    不过这样的设置也带来了新的问题,对于手机而言,部署在家里的服务在不同网络环境下有不同的 IP 地址,虽然 zerotier 有 DNS 功能,但是我的手机本质上并没有加入 zerotier VPN,所以实际上也没办法使用 zerodns。还好我有自己的域名,在公网上,我把指向家里服务的域名都解析到 zerotier 的私有地址(10.2.2.0/24)。在家里的路由器上,将这些域名强制设置为局域网址(192.168.1.0/24)。

    至此,出门在外的时候,我终于可以随时访问部署在家里的 NAS 了,使用联通 5G 网络运行 iperf3 测试,能够跑到 60Mbps(对比通过 VPS 代理测速的 speedtest.net 结果 120Mbps),应急使用完全足够了。

  • 不花钱提升工作笔记本的电池续航

    我的工作电脑是一台安装 Arch Linux 的轻薄笔记本,虽说 Linux 比 Windows 更加节省资源,但是我的工作笔记本续航比较尿崩,出门必须带充电器,进店必找有插座的位置。看到同事的 mbp 的超长续航不可能不羡慕,但我也不奢望过多,只期望出门后,笔记本能够支撑一下午的正常办公就足够了。

    amd_pstate

    刚好最近注意到 Linux 6.1 内核中集成了 amd_pstate 模块,这是用来实现动态调节 Ryzen CPU 频率的驱动模块,相较于原先的 acpi_cpufreq 驱动, amd_pstate 支持 CPPC(Collaborative Processor Performance Control) 功能,简单来说,CPPC 可以根据系统对性能、功耗的需求,调节 CPU 的工作频率。

    支持 CPPC 的 CPU driver 需要跟合适的 CPU scaling governor 配合使用。后者是 Linux 系统中用来调节 CPU 频率的软件,不同的 gorvernor 实现了不同的 CPU 频率调整算法,跟 CPPC 最搭配的是下面两个 gorvernor:

    • ondemand:基于当前工作负载动态调节 CPU 频率
    • schedutil:基于调度器的反馈动态调节 CPU 频率

    这两种 gorvernor 都能根据操作系统的需要动态降低或提升 CPU 的工作频率,从而实现比较理想节能效果。

    对于运行 6.1 版本或者更新内核的 Linux ,可以参考这个链接启用 amd_pstate 驱动。

    检测 amd_pstate 生效的方式也比较简单,推荐安装 cpupower

    analyzing CPU 14:
      driver: amd-pstate
      CPUs which run at the same hardware frequency: 14
      CPUs which need to have their frequency coordinated by software: 14
      maximum transition latency: 20.0 us
      hardware limits: 400 MHz - 1.90 GHz
      available cpufreq governors: conservative ondemand userspace powersave performance schedutil
      current policy: frequency should be within 400 MHz and 1.90 GHz.
                      The governor "ondemand" may decide which speed to use
                      within this range.
      current CPU frequency: Unable to call hardware
      current CPU frequency: 1.11 GHz (asserted by call to kernel)
      boost state support:
        Supported: yes
        Active: no
        AMD PSTATE Highest Performance: 166. Maximum Frequency: 4.51 GHz.
        AMD PSTATE Nominal Performance: 70. Nominal Frequency: 1.90 GHz.
        AMD PSTATE Lowest Non-linear Performance: 41. Lowest Non-linear Frequency: 1.11 GHz.
        AMD PSTATE Lowest Performance: 15. Lowest Frequency: 400 MHz.
    

    对于笔记本来说,更常见的需求是根据电源状态自动设置性能偏好,这里推荐使用 TLP,为了方便使用,我还安装了 tlpui。TLP 允许我们配置电脑在不同电源状态的 CPU 调节参数:

    • gorvernor
    • 最低频率、最高频率
    • 自动超频开关

    不过 TLP 的自动超频开关有些死板,即使是出门在外使用电池的场景,我也希望偶尔开启 Boost 提高一下 IDE 分析代码的速度。解决这个问题很简单,有两个方法:

    1. 手动按需执行开关 CPU Boost 的命令
    2. 安装 auto-cpureq,这个软件会在后台监听当前的工作负载,会在必要的时候开关 Boost

    经过一段时间的观察与调试,为了尽量减少风扇噪音、提高电池续航,我的笔记本(HP EliteBook 845 G8 / Ryzen 5800U)配置如下:

    • 外部电源:schedutil gorvernor,启用自动超频,限定最低频率在标称频率的 68%(大概 1.1GHz)
    • 内置电池:ondemand gorvernor, 配合 auto-cpufreq 动态调整超频开关

    实际续航测试

    目前的电池状况,标称容量 45wh,电池健康度 76%,屏幕亮度 30% ~ 35%。工作时会使用的软件包括:

    • Webpack Dev Server
    • WebStorm(180kloc TypeScript 项目)
    • Vivaldi 浏览器(通常控制在 30 个标签以内)
    • Firefox 浏览器(通常控制在 3 个标签以内)
    • 飞书 Linux 客户端
    • Telegram

    acpi_cpufreq

    在 acpi_cprfreq 驱动下,我的笔记本电脑的最低运行频率是 1.9 GHz,最高可以达到 4.1 GHz,下面是我记录的两次续航时长。

    roundstart timeend timetime to 10%
    12023-02-06 13:322023-02-06 16:413:10
    22023-02-13 14:112023-02-13 17:353:24

    amd_pstate

    在 amd_pstate 驱动下,最低运行频率可以到 400 MHz,通常会在 900 MHz 徘徊,最高可以达到 4.1 GHz。

    roundstart timeend timetime to 10%
    12023-02-19 10:1514:474:32
    22023-02-20 9:3714:304:53
    32023-03-06 13:3117:314:00

    在 IDE 的使用体验上没有明显区别,小项目依然很流畅,巨型项目该卡的操作还是卡,但是续航的提升非常明显,至少出门重度办公一下午没有续航焦虑了。

    如何进一步改善续航?

    关于这点,我建议你看看 极客湾的观点

    • 尽量减少 Boost 时长
    • 减少 CPU 以外硬件的功耗

    普通消费者几乎没法做硬件上的改进(最多禁用独显以提高续航),只能从减少 Boost 时长上入手,毕竟是否开启 Boost、需要多长时间的 Boost,这些参数是可以通过软件调节的,上面提到的 auto-cpufreq 就是干这件事的,这个软件是用 python 编写,除了可以通过配置文件来设置之外,自己也可以根据实际体验和偏好来调节相关算法。

  • 如何解决米家设备在透明代理下无法联网的问题

    我在家里的一台旧笔记本上部署了透明代理服务,让连上家里网络的设备都能赛博漫游到国外,不过最近,在我的透明代理网络下,米家设备全部没法联网。我的透明代理工作机制如下:

    OpenWRT 强制启用 DHCP,给米家设备设置特定的 IP 地址,并把米家设备的网关设置为主路由;其他设备的网关设置为 OpenWRT。

    OpenWRT 会把所有需要转发(FORWARD,即目标地址非 OpenWRT 本身)的请求发送给透明代理端口(localhost:12345),接着运行在 OpenWRT 上的 v2ray 会对来自 12345 端口的请求分流,国内请求直接发送,国外请求通过代理协议发送到服务端。

    经过一番排查后,我发现在最近的一次主路由固件升级过后,OpenWRT 强制启动 DHCP 失效了,米家设备的网关被主路由设置成了 OpenWRT 。米家设备需要请求 https://:Mijia Cloud。而 Mijia Cloud 的 IP 地址是米家设备通过其他接口获取的,无法通过正常的 DNS 解析。这时,就引发了 v2ray 的一个问题:v2ray 在分流时会嗅探请求的域名以及域名解析后的 IP 地址,帮助判断请求是否需要被代理。因为 Mijia Cloud 无法被解析,导致嗅探功能出错,v2ray 无法进一步处理请求,导致请求被丢弃

    知道了问题的成因,解决方法就很简单,通过 OpenWRT 上的 iptables 分流,让来自米家设备的请求绕过代理:

    iptables -t mangle -A V2RAY -s 192.168.68.<mijia device ip> -j RETURN

    但是这样做,米家设备还是无法联网,通过 tcpdump 发现米家设备只能发送请求,无法接收响应。

    又是一番搜索,怀疑是一些路由器会校验请求来源设备 IP 跟数据包中来源 IP 的一致性,米家设备请求被 OpenWRT 转发到主路由网关,导致来源设备 IP 跟数据包中的来源 IP 不一致,最终请求被拦截在了主路由处。要解决这个问题,得在 OpenWRT 对应的网络接口上启用「动态 IP 伪装」,说白了就是 NAT 。

    其他设备也是被 OpenWRT 转发到主路由的,为什么它们没有出现这种问题呢?这时就需要进一步了解 Linux 的网络原理了:

    所有发往网关的请求应该都需要转发(FORWARD,因为请求的目标 IP 不是网关本身),但是所有基于这篇透明代理白话文设置的透明代理中,转发流量都被 iptables 发到了 12345 端口,变成了入站请求(INPUT),经过代理软件处理后,作为出站请求(OUTPUT)发出,这些流量就不再被认为是转发流量了,在主路由看来,这些被 v2ray 处理过的流量来源请求都是 OpenWRT ,所以不会触发来源请求校验失败。而被 iptables 分流的米家设备请求,从主路由看来,都是由 OpenWRT 发出但是来自米家设备 IP 的,导致校验失败。

    上面的根因分析完全是我半吊子的推测,可能不够准确、专业,但是启用 OpenWRT 的「动态 IP 伪装」之后,确实解决了米家设备无法联网的问题。


    参考链接

  • 给小新 Pad Pro 2021 刷入 GSI 镜像

    This entry is part 2 of 3 in the series 小新 Pad Pro 2021

    上回书说道,我成功解锁了小新 Pad Pro 2021,但解锁不是最终目的,让 Pad 用上不那么拉胯的原生安卓才算成功。

    准备工作

    • android-platform-tools
    • 一台已经解锁了 bootloader 的小新 Pad
      • 需要已经升级到 ZUI 14,否则自动旋转会有故障
    • 一个心仪的 GSI 镜像,你可以在这里挑选,我选择的是带有完整 GApps 的 LineageOS 19 GSI 镜像。
    • 原厂固件中解压得到的 vbmeta.img 跟 boot.img
    • 用来启用自动亮度调节的 Magisk 模块

    开搞

    下面的内容主要参考这篇帖子

    首先进入平板系统,启用开发者模式,允许 adb 调试,然后通过 USB 连接到电脑。接着在电脑上执行下面的命令:

    $ adb reboot bootloader
    $ fastboot --disable-verity --disable-verification flash vbmeta vbmeta.img
    $ fastboot reboot fastboot
    $ fastboot flash system your-gsi-system.img

    继续通过平板上的音量键,进入 Recovery 模式,然后选择清除数据(工厂模式重置),最后重启设备。

    第一次启动可能会比较慢,如果发现卡在联想 Logo 页面超过了 3 分钟了,可以长按电源键重启设备,一次不行,就多试几次,这种情况通常只会出现在第一次启动系统。

    提高使用体验

    在 LineageOS 19 中,以往小新 Pad Pro GSI 系统中会遇到的自动旋转失效问题已经不存在了。但是原生安卓缺少国产 ROM 的“平行视界”功能,运行不适配横屏模式的应用的体验跟 iPad OS 一样,会强制竖屏。所以还是得安装一个旋转管理器,强制部分应用横屏展示得忍受一下 UI 错位 ,我用的是这个 Xposed 模块 —— 自由屏幕旋转

    另一个提高不适配横屏应用使用体验的方法就是安装 米窗 ,可以用来替代 ZUI 自带的小窗功能,据说把它设置为系统应用体验会更好,但是因为 GSI 已经不会随便杀后台了,所以我也没有对它做特别地处理。

    自动亮度调节功能需要刷入启用自动亮度调节的 Magisk 模块,默认的自动亮度会偏暗,但是 Android 12 有自适应亮度调节功能,会根据用户手动调节亮度条的习惯调整自动亮度的明暗,经过几天体验下来,自动亮度调节功能基本正常。

    原生系统的后台管理机制比较宽松,为了能让垃圾应用退出后老实一些,我选择用 scene4 的“应用偏见”自动冻结垃圾国产应用(例如,淘宝、京东)。

    至于快充,由于我的手机充电速度是 Pad 的 6 倍,实在很难感受到是否存在快充变慢的情况。至少系统界面会在使用原装充电器的时候显示 “Charging Rapidly”的文字。

    关于续航,Lineage OS 系统设置中有一个默认启用的 Screen Saver 选项,这是一个类似“常亮显示”的功能,会在屏幕熄灭后在屏幕上显示一个时钟。小新 Pad Pro 虽然使用的是 A 屏,但是硬件设计上可能压根不支持“常量显示”,导致屏幕耗电量剧增。实测关掉 Screen Saver 后,待机续航可以提升一倍(从一天不到提升到两天),而且充电速度也会有明显的提升。

  • 不靠官方,自己动手解锁小新 Pad Pro

    This entry is part 1 of 3 in the series 小新 Pad Pro 2021

    联想小新 Pad 的 官方解锁页面下线了,客服也不回邮件,为了摆脱疯狂杀后台的 ZUI,我决定尝试自己动手为小新 Pad Pro 2021 解锁,刷入第三方 ROM。

    本文内容主要参考这篇帖子编写,并在原帖基础上补充了一些避免实操踩坑的细节。这个文章的方法对于小新 Pad 2022 可能同样有效?

    准备工作

    • 基础的计算机命令行操作能力
    • 认识 16 进制
    • Windows 电脑
    • 你的小新 Pad 的序列号,关机后按住音量 – 和电源键开机,进入 bootloader 模式后就可以看见序列号
    • 高通刷机工具 QPST
    • 小新 Pad Pro 2021(Lenovo P11 TB-J716F)原厂固件
    • android-platform-tool 这个都不知道在哪里下载还是建议不要刷机了
    • 一个二进制文件编辑器
    • 一个用来解锁 Bootloader 的 sn.img 文件,这个文件对应的设备序列号是 HAHAHAHA

    开搞

    1. 下载并安装 QPST 工具,也请一并安装附带的驱动程序。安装完成后从开始菜单找到 QFIL 工具并启动
    2. 解压原厂固件到文件夹,请确保文件夹的路径没有空格、中文等特殊字符
    3. 在 QFIL 选择 flat build 选项,选中刚刚解压出来的 prog_firehose_ddr.elf 作为 Programmer 文件
    4. 将 Pad 关机,等到完全息屏后按住音量 + ,再将 Pad 通过 USB 连接到电脑上,这时 Pad 会进入 EDL 模式。EDL 模式跟 fastboot 有一个很大的不同,如果一段时间内没有操作,EDL 模式会超时,这时 QFIL 工具虽然还能检测到连接上的设备,但是对设备的操作都会失败。
    5. 打开 QFIL 工具的 Tools 菜单,选择 Partition Manager,等待几秒,会弹出一个新的窗口
    6. 新窗口中选择 fpinfo 分区,右键点击,选择 Manage Partition
    7. 点击 Read Data,QFIL 从设备上下载数据并存放到  AppData\Roaming\Qualcomm\QFIL\COMPORT_xxx
    8. 备份刚刚下载的文件,文件名包含数据分区的地址 0x2208,这个文件里面存储了你设备的序列号,请务必小心保管
    9. 使用二进制编辑器编辑上述文件的一个副本,把文件开头的序列号替换为 HAHAHAHA
    10. 回到 QFIL,点击 Load Image 把刚刚编辑后的文件上传到设备上
    11. 接着用同样的办法下载 frp 分区文件,文件名包含数据分区的地址 0x2188,也请妥善备份这个文件
    12. 使用二进制编辑器编辑上述文件的一个副本,把文件末尾的最后一个字节从 00 改为 01,如果你的文件末尾已经是 01 了,可以直接跳转到第 14 步
    13. 回到 QFIL,点击 Load Image 把刚刚替换的文件上传到设备上
    14. 点击 Close,等待 EDL 模式重置完成后,拔出线缆
    15. 按住电源键跟音量 -,开机后进入 bootloader 模式,切记,此时千万不要进入 Android 系统,否则刚刚进行的修改会被还原。
    16. 进入 bootloader 后,屏幕上显示的序列号应该为 HAHAHAHA。如果发现修改没有生效,请重新执行上面 4 ~ 14 步的操作,注意自己的操作是否有遗漏。
    17. 执行命令: fastboot flash unlock sn.img
    18. 执行命令: fastboot oem unlock-go
    19. 恭喜你,你的设备已经成功解锁 bootloader
    20. 最后收尾,参考之前的步骤,使用 QFIL 工具还原 0x2208 以及 0x2188 分区。