跳至主要内容

LG V35 刷 LineageOS(上):備份與升級 Android 10

· 閱讀時間約 21 分鐘

手邊有一支 LG V35(LM-V350AWM,AT&T 硬體),之前交叉刷成美版開放版的 Pie 20f。這次想刷 LineageOS 22.2(Android 15)當 App 測試機,但 LineageOS 官方安裝說明要求先裝「最新的原廠 Android 10」,而 AT&T 的 Android 10 只透過 OTA 推送,沒有 KDZ 可以用 LGUP 刷。

最後是用開源的 edl 工具進高通 EDL(9008)模式,先把手機獨有的分區完整備份,再把網友從手機讀出來的 AT&T 30e 原廠分區寫進 b 槽。這篇是上集,寫到 Android 10 開機成功,刷 LineageOS 留到下集。

免責聲明

這是我在「一支手機」上的實作紀錄,不是保證成功的教學。刷寫手機底層分區可能讓手機開不了機(變磚)、遺失 IMEI 或 Wi-Fi 校準資料,也拿不到原廠保固。請自行承擔風險,動手前先完整備份,並確認自己的狀況跟下面的「適用範圍」相符。

適用範圍​

項目本文的環境
手機型號LG V35 ThinQ LM-V350AWM(AT&T 硬體)
開始時的韌體美版開放版 Pie V350ULM20f(ARB00)
之前刷過的韌體AT&T 原廠 → 剛買到時刷成美版開放版 Oreo V350ULM10h(V350ULM10h_00_NAO_US_OP_1130.kdz)→ 後來因為 Roon 的 App 不支援 Android 8,再刷成 Pie 20f
Bootloader已解鎖(本文不含解鎖步驟)
電腦macOS 27.0.1,Apple Silicon(arm64)
工具bkerler/edl commit 1cda1a6(2026-09-19)、Python 3.14.6、libusb 1.0.30
日期2026-10-19

沒測試過、不保證適用:

  • 其他 V35 型號(LM-V350N 韓版、LM-V350ULM、LM-V350EAW…):分區表可能不同,已知韓版和美版的分區大小不一樣
  • 從 AT&T 原廠韌體、Oreo、韓版韌體開始
  • Windows/Linux 電腦、其他版本的 edl
  • 還沒解鎖的手機

各步驟的驗證狀態:

步驟狀態
工具準備✅ 已在真機驗證
進入 EDL✅(成功率看手感,我試了很多次)
讀分區表✅
完整備份(做法)✅;整理後的 read_lun 指令 🧪
驗證備份腳本✅(已用實際備份執行)
寫入前自我檢查腳本✅(已用實際分區表和 30e 映像執行)
寫入 b 槽(做法)✅;整理後的 write_lun 指令 🧪
Android 10 開機✅
LineageOS⏳ 下集

✅ 是在上面的環境實際執行並成功;🧪 是指令語法和參數已經用假的 edl 乾跑測試過,跟實際執行時一致,但這份整理後的指令本身還沒接真機跑過;⏳ 是還沒做。

目標與限制​

  • 目標:LineageOS 22.2,保留 Hi-Fi Quad DAC
  • 用途:App 測試機,只用 Wi-Fi,沒有 SIM
  • 工具只用開源、看得到原始碼的版本。之前下載過假的「修改版 LGUP」,結果帳號被盜,這次不想再賭
  • 每一步寫入前先完整備份
  • 不覆蓋手機獨有的分區:persist、ftm、modemst1/2、fsg、fsc 等

手機現況​

2026-10-19 用 adb 讀到的:

項目值
ro.boot.vendor.lge.model.nameLM-V350AWM
ro.vendor.lge.swversionV350AWM20f
ro.vendor.lge.factoryversionLMV350AT-00-V20f-LAO-COM-FEB-18-2020-ARB00+0
對應的 KDZV350ULM20f_00_NAO_US_OP_0218.kdz
ro.boot.verifiedbootstateorange(已解鎖)
ro.boot.slot_suffix_a
root無
電池(用 charge counter 估)約 2,350/3,300 mAh,約 71%

Bootloader 是 2024 年照 Nemo 社區的教學,用 EDL 加工程版 abl 解鎖的,當時用的 firehose 檔還留在 NAS 上。

工具準備​

# 開源 EDL 工具(GPL-3.0)
git clone --depth 1 https://github.com/bkerler/edl.git # commit 1cda1a6
python3 -m venv venv && ./venv/bin/pip install -r edl/requirements.txt
# 只抓需要的 LG SDM845 firehose
curl -L -o edl/Loaders/LG/0008b0e100310000_1030cd12ce708f29_fhprg.bin \
https://raw.githubusercontent.com/bkerler/Loaders/main/LG/0008b0e100310000_1030cd12ce708f29_fhprg.bin
  • 安裝前先看過 edl 的相依套件和網路呼叫:只有附屬工具會連網,主程式不會
  • firehose 核對了兩件事:git blob 雜湊和 GitHub 上一致(2ed52868…);SHA-256 是 82808c5e…1da13,跟 2024 年解鎖時用的 prog_ufs_firehose_Sdm845_lge.elf 完全相同

為什麼不能直接用 LGUP​

檔案跟手機相不相符格式LGUP 能不能刷
V350AWM30e.zip(Android 10)✅ 同硬體網友從手機讀出的分區映像包❌ 只能用 EDL 一個一個寫
V350ULM20f KDZ(Pie)✅ 手機原本的韌體LG 官方 KDZ✅ 救機用
V350N 30a/30d KDZ(Android 10)⚠️ 韓版KDZ要用修改版 LGUP 的 PARTITION DL

有同型號的官方 KDZ 時,用 LGUP 的 Upgrade 模式就等於官方更新,風險低。AWM 沒有 Android 10 的 KDZ,所以只能走 EDL。

另外要注意,KDZ 本身就包含 persist、ftm、mpt 這些映像(飞羽 ROM 從韓版 KDZ 抽出的檔案裡就看得到),PARTITION DL 如果全選,會用 KDZ 裡的內容蓋掉手機原本的。不在 KDZ 裡的只有 modemst1/2、fsg。

研究過但沒採用的兩條路:

  • 飞羽 ROM(Nemo 社區的韓版 30a/30c 卡刷包):讀了它的 update-binary,發現會用 dd 覆蓋 persist、ftm、mpt、misc、persdata 這些手機獨有的分區,不用
  • 韓版 V350N 30d KDZ:要用修改版 LGUP,而且有人回報刷到美版後 Wi-Fi、網路壞掉,不用

下載的韌體​

AT&T V350AWM30e(Android 10)分區包​

  • 來源:XDA 上 jacob019 分享的「V350AWM30e ATT_US stock & rooted partitions」
  • 3,698,834,161 bytes,SHA-256 cb962c92…f876,unzip -t 沒有錯誤
  • 裡面沒有任何 Windows 執行檔:partitions/ 是原廠分區,modified/ 是改過的 boot、dtbo、vendor(Magisk、TWRP、關 verity),另外還有 sources/、notes.txt、load.sh
  • vendor 指紋 lge/judyp_lao_com/judyp:10/QKQ1.191222.002,安全性更新 2020-04-01

讀完 notes 和討論串記下的重點:

  • 作者只寫 b 槽,a 槽留著當退路
  • OP.bin(650 MB)比手機的 OP 分區(450 MB)大,不能刷
  • persist.bin 是作者手機的校準資料,絕對不能刷
  • 有人回報 modified 的 boot 讓手機變磚,所以只用原廠映像
  • ARB(防降級)值從映像字串讀不到;間接證據是 XDA 有人從 30e 刷回 Pie 20f 成功

LineageOS 官方檔案​

全部核對過官方的 SHA-256:

  • lineage-22.2-20261015-nightly-judyp-signed.zip
  • boot.img(Lineage Recovery)、dtbo.img、vbmeta.img
  • MindTheGapps-15.0.0-arm64-20260915_032013.zip
  • copy-partitions-20220613-signed.zip(SignApk 簽章)

救機用​

NAS 上留著兩個 KDZ:V350ULM20f(Pie 20f,跟手機現在一樣)和 V350ULM10i(Oreo)。

進入 EDL(9008)​

這是花最多時間的一步。失敗的嘗試:

嘗試結果USB(vid:pid)
adb reboot edl進 LG Download 模式,LG 把它導向 LAF(無效)1004:633A
按住電源+音量下,黑屏時「放開」再連按音量上Download 模式,試了 2 次(無效)1004:633A
關機,按住音量上+音量下再插 USB關機充電畫面(無效)1004:6300
同上,時機稍早LG 的 IMEI 條碼資訊畫面,無害,按電源離開(無效)1004:633E → 斷線

成功的按法(14:00:23 偵測到 05C6:9008):

  1. 手機接著 Mac,從 Download 模式或開機狀態開始都可以
  2. 按住電源+音量下,全程不要放
  3. 螢幕一黑,另一隻手指快速連按音量上
  4. 電腦偵測到 9008 之後,才放開所有按鍵

一開始我照英文教學,理解成「黑屏時放開電源+音量下」,所以一直進到 Download 模式。後來看 Nemo 社區的中文原文,上面寫得很清楚:「切記同時不要鬆開音量減和電源鍵」。

成功那次的 USB 變化:

13:59:55 1004:633A Download 模式
14:00:04 斷線 → 1004:633E
14:00:21 斷線(黑屏)
14:00:23 05C6:9008 EDL ✔

兩隻手按著按鍵很難同時盯螢幕,所以寫了一個小迴圈,偵測到 9008 就用 Mac 的語音念出來:

# 偵測到 Qualcomm 9008 時用語音通知,就不用盯著螢幕
while :; do
ioreg -p IOUSB -l -w0 | grep -q '"idProduct" = 36872' && { say "E D L"; break; }
sleep 0.3
done

36872 就是 0x9008(1478 是 0x05C6)。Mac 靜音的時候聽不到 say,後來另外用 osascript 跳出視窗:

osascript -e 'display alert "偵測到 EDL!" message "立刻放開所有按鍵,不要再碰手機。" giving up after 15'

另外兩個坑:

  • 電源+音量下按滿約 10 秒會強制重開,在 EDL 裡也一樣,所以偵測到 9008 就要立刻全部放開
  • 手機在 EDL 裡進入錯誤狀態後,只能重新進一次 EDL(按電源+音量下重開)

讀分區表(只讀)​

python edl.py printgpt --memory=ufs --loader=Loaders/LG/0008b0e100310000_1030cd12ce708f29_fhprg.bin
  • CPU 是 SDM845,PK_HASH 開頭 1030cd12ce708f29,跟 loader 檔名一致
  • firehose 支援 14 個指令:program、read、nop、patch、configure、setbootablestoragedrive、erase、power、firmwarewrite、getstorageinfo、benchmark、emmc、ufs、fixgpt
  • UFS 是東芝 THGAF8G9T43BAIRB0300,7 個 LUN,block 4096
  • OP_a 大小 0x1c200000(450 MB),比 30e 的 OP.bin(650 MB)小,證實 OP 不能刷

各 LUN 的完整分區清單(照分區表順序):

  • LUN0:mpt、drm、sns、ssd、persist、misc、ftm、power、encrypt、eksst、rct、fota、srtc、pstore、els、carrier、persdata、oem_a、oem_b、vendor_a、vendor_b、system_a、system_b、OP_a、OP_b、userdata、grow
  • LUN1:xbl_a、xbl_config_a
  • LUN2:xbl_b、xbl_config_b
  • LUN3:ALIGN_TO_128K_1、cdt、ddr
  • LUN4:aop_a、tz_a、hyp_a、modem_a、mdtpsecapp_a、mdtp_a、abl_a、dsp_a、keymaster_a、akmu_a、boot_a、cmnlib_a、cmnlib64_a、devcfg_a、qupfw_a、laf_a、vbmeta_a、dtbo_a、storsec_a、raw_resources_a、sid_a、aop_b、tz_b、hyp_b、modem_b、mdtpsecapp_b、mdtp_b、abl_b、dsp_b、keymaster_b、akmu_b、boot_b、cmnlib_b、cmnlib64_b、devcfg_b、qupfw_b、laf_b、vbmeta_b、dtbo_b、storsec_b、raw_resources_b、sid_b、sec、devinfo、dip、apdp、msadp、spunvm、limits、toolsfv、logfs、sti、logdump
  • LUN5:ALIGN_TO_128K_2、modemst1、modemst2、fsg、fsc(IMEI 和網路設定)
  • LUN6:frp

完整備份(只讀)​

本來打算用 rl 一次讀完整機,跳過 userdata,用 --genxml 產生之後可以整機寫回的 rawprogram xml:

python edl.py rl ~/LG-V35-backup/dumps \
--memory=ufs --skip=userdata --genxml \
--loader=Loaders/LG/0008b0e100310000_1030cd12ce708f29_fhprg.bin

結果一口氣讀失敗,前後進了 6 次 EDL 才讀完:

第幾次進 EDL做法結果
1(14:00)rl 整機讀讀了約 187 MB,到 els 出現 USBError(32, 'Pipe error'),手機進入「Sahara error state」(無效)
2(14:11)偵測到後隔約 1 分鐘才開始讀手機已經自己重開回 Android,可能等太久,或電源鍵按太久(無效)
3(14:15)每個分區各呼叫一次 edl rmodemst1/2、fsg、fsc、devinfo、sec、abl_a/b 成功;讀 laf_a 時手機重開,推測是聽到提示後電源鍵還按著超過 10 秒
4(14:21)同上laf_a/b、boot_a 成功;boot_b 讀到一半 Pipe error
5(14:25)同上cdt、ddr、frp、carrier、persdata 成功;els 又失敗(Input/Output Error)
6(14:37)同一個 LUN 的分區用一次 edl r 讀完(逗號分隔清單)32 個分區一次成功;接著讀 b 槽的韌體也成功,讀到 modem_a 時又 Pipe error(有效)

每讀一個分區就重新呼叫一次 edl,等於每次都重新連線,在這台手機上很容易觸發 USB Overflow/Pipe error。bkerler/edl 的 issue #752 也有人回報「第二次連線就 overflow」。改成一個 LUN 呼叫一次之後穩定很多。

整理後的備份指令​

下面是把上面的做法整理成可以直接跑的版本。語法和參數已經用假的 edl 乾跑測試過,但這份指令本身還沒接真機跑過(🧪),下次進 EDL 時會實際跑一次確認。

在 edl 的資料夾裡執行,手機要已經在 EDL(9008)。edl r 可以用逗號一次指定多個分區和對應的檔名,所以先寫一個小函式把清單接起來:

cd edl # bkerler/edl 的資料夾
PY=../venv/bin/python # 安裝 edl 相依套件的 venv
LOADER=Loaders/LG/0008b0e100310000_1030cd12ce708f29_fhprg.bin
OUT=~/LG-V35-backup/dumps # 備份存放位置

# 讀取同一個 LUN 的多個分區(只呼叫 edl 一次),已經存在的檔案會跳過
read_lun() {
local lun=$1; shift
local names=() files=() p
mkdir -p "$OUT/lun$lun"
for p in "$@"; do
[ -s "$OUT/lun$lun/$p.bin" ] && continue
names+=("$p"); files+=("$OUT/lun$lun/$p.bin")
done
[ ${#names[@]} -eq 0 ] && return 0
(IFS=,; "$PY" edl.py r "${names[*]}" "${files[*]}" --memory=ufs --lun="$lun" --loader="$LOADER")
}

# 1. 手機獨有:IMEI/網路設定
read_lun 5 modemst1 modemst2 fsg fsc
# 2. 手機獨有:校準、出廠、解鎖狀態(els 讀不到,不列)
read_lun 0 mpt drm sns ssd persist misc ftm power encrypt eksst rct fota srtc pstore carrier persdata
read_lun 3 cdt ddr
read_lun 6 frp
read_lun 4 devinfo sec apdp msadp spunvm limits toolsfv dip logfs sti
# 3. 開機鏈(a/b 兩槽)
read_lun 1 xbl_a xbl_config_a
read_lun 2 xbl_b xbl_config_b
read_lun 4 abl_a abl_b laf_a laf_b boot_a boot_b vbmeta_a vbmeta_b dtbo_a dtbo_b
# 4. 韌體(a/b 兩槽)
read_lun 4 tz_a aop_a hyp_a keymaster_a cmnlib_a cmnlib64_a devcfg_a qupfw_a storsec_a \
sid_a akmu_a raw_resources_a mdtpsecapp_a mdtp_a dsp_a
read_lun 4 tz_b aop_b hyp_b keymaster_b cmnlib_b cmnlib64_b devcfg_b qupfw_b storsec_b \
sid_b akmu_b raw_resources_b mdtpsecapp_b mdtp_b dsp_b

幾個要注意的地方:

  • 一次 EDL 裡呼叫 edl 的次數還是越少越好,我實測到第 5 次呼叫時又出現 Pipe error。中斷後重新進 EDL,再跑同樣的指令就好,已經讀好的會自動跳過
  • 讀到一半中斷的檔案大小會不對,重跑前要先刪掉(或像下一節那樣比對大小)
  • els(LUN0,16 MB)兩次都讀到 3~4 MB 就失敗,判定讀不到,跳過。讀到一半的檔案另外留著,不列入雜湊清單

驗證備份​

拿 printgpt 的輸出當基準,檢查每個分區有沒有備份到、大小對不對、內容是不是全空:

# 先把分區表存成檔案(手機在 EDL 時執行一次即可)
cd edl
../venv/bin/python edl.py printgpt --memory=ufs \
--loader=Loaders/LG/0008b0e100310000_1030cd12ce708f29_fhprg.bin > ~/LG-V35-backup/printgpt.log
#!/usr/bin/env python3
# verify_backup.py <printgpt.log> <dumps 資料夾>
import os, re, sys

log, dumps = sys.argv[1], sys.argv[2]
lun, parts = None, []
for line in open(log):
m = re.match(r'Parsing Lun (\d+)', line)
if m:
lun = int(m.group(1)); continue
m = re.match(r'(\S+):\s+Offset 0x[0-9a-f]+, Length 0x([0-9a-f]+)', line)
if m and lun is not None:
parts.append((lun, m.group(1), int(m.group(2), 16)))

missing, wrong_size, empty = [], [], []
for lun, name, length in parts:
if name == 'userdata':
continue
path = os.path.join(dumps, f'lun{lun}', f'{name}.bin')
if not os.path.exists(path):
missing.append(f'lun{lun}/{name}'); continue
size = os.path.getsize(path)
if size != length:
wrong_size.append(f'lun{lun}/{name} ({size} != {length})'); continue
data = open(path, 'rb').read()
if not any(data[i:i+4096].strip(b'\x00') and data[i:i+4096].strip(b'\xff')
for i in range(0, len(data), 4096)):
empty.append(f'lun{lun}/{name}')

print('missing:', missing)
print('wrong size:', wrong_size)
print('all zero/FF:', empty)
python3 verify_backup.py ~/LG-V35-backup/printgpt.log ~/LG-V35-backup/dumps
# 最後產生雜湊清單,之後可用 shasum -c 檢查備份有沒有損壞
cd ~/LG-V35-backup/dumps && find . -name '*.bin' -print0 | sort -z | xargs -0 shasum -a 256 > ../SHA256SUMS.txt
  • 「wrong size」通常是讀到一半中斷,刪掉那個檔再重讀
  • 「all zero/FF」不一定是錯,有些分區本來就是空的,但要回頭看讀取紀錄有沒有錯誤

備份結果​

77 個分區,加上 2 個分區表檔(gpt_main0、gpt_backup0),約 1 GB。SHA-256 清單涵蓋這 79 個檔案(讀到一半的 els 不列入),連同完整分區表和 rawprogram xml 一起存在 Mac 上:

類別分區狀態
IMEI/網路設定(4)modemst1、modemst2、fsg、fsc✅(fsc 本來就是空的)
校準/出廠(15)persist、ftm、mpt、cdt、ddr、carrier、persdata、power、drm、sns、ssd、rct、srtc、fota、pstore✅
解鎖狀態(2)devinfo、sec✅
開機鏈(a/b 兩槽,14)xbl、xbl_config、abl、laf、boot、vbmeta、dtbo✅
韌體(a/b 兩槽,30)tz、aop、hyp、keymaster、cmnlib、cmnlib64、devcfg、qupfw、storsec、sid、akmu、raw_resources、mdtp、mdtpsecapp、dsp✅
其他小分區(12)frp、apdp、msadp、spunvm、limits、toolsfv、dip、logfs、sti、misc、encrypt、eksst✅

全空(全 0 或全 FF)的有 12 個:misc、eksst、cdt、fsc、mdtpsecapp_a、mdtpsecapp_b、mdtp_a、mdtp_b、dip、spunvm、toolsfv、sti。大小正確、讀取也沒有錯誤,判定本來就是空的。

沒備份的有:

  • system、vendor、OP、oem、modem 的 a/b 兩槽,共約 12 GB,NAS 上的 Pie 20f KDZ 裡都有
  • logdump(系統紀錄)、grow、ALIGN_TO_128K_*(對齊用的空分區)
  • 讀不到的 els

手機獨有、下載不到的分區都已經備份到了。

把 30e 寫進 b 槽​

準備:

  • 從 30e 包只解出 partitions/,排除 OP.bin(比分區大)和 persist.bin(原作者手機的校準資料)
  • 不用 modified/,只用原廠映像
  • 26 個映像依 GPT 對到 _b 分區,大小全部跟分區長度相同
  • 依 LUN 分資料夾:LUN4(21 個)、LUN2(xbl_b、xbl_config_b)、LUN0(oem_b、system_b、vendor_b)

準備檔案,把 30e 的映像改名成 _b 分區名,依 LUN 分資料夾:

ZIP=~/Downloads/V350AWM30e.zip
STAGE=~/LG-V35-work/30e_slot_b
mkdir -p "$STAGE" && cd "$STAGE"
# 只解出原廠分區,排除 OP 與 persist
unzip -q "$ZIP" 'V350AWM30e/partitions/*' \
-x 'V350AWM30e/partitions/OP.bin' 'V350AWM30e/partitions/persist.bin'
P=V350AWM30e/partitions
mkdir -p lun0 lun2 lun4
for n in oem system vendor; do mv "$P/$n.bin" "lun0/${n}_b.bin"; done
for n in xbl xbl_config; do mv "$P/$n.bin" "lun2/${n}_b.bin"; done
for n in abl akmu aop boot cmnlib cmnlib64 devcfg dsp dtbo hyp keymaster laf \
mdtp mdtpsecapp modem qupfw raw_resources sid storsec tz vbmeta; do
mv "$P/$n.bin" "lun4/${n}_b.bin"
done

寫入前一定要先做自我檢查:拿你自己手機的分區表比對每個映像,任何一個不符就不要寫,代表你的手機跟本文的環境不同。

#!/usr/bin/env python3
# precheck_30e.py <printgpt.log> <staging folder>
# Before writing: every staged image must map to an existing partition on THIS phone,
# sit on the expected LUN, and be EXACTLY the partition's size. Any mismatch -> do not write.
import os, re, sys

log, stage = sys.argv[1], sys.argv[2]
NEVER = {'persist', 'ftm', 'mpt', 'misc', 'persdata', 'modemst1', 'modemst2', 'fsg', 'fsc',
'devinfo', 'frp', 'OP_a', 'OP_b'}

lun, gpt = None, {}
for line in open(log):
m = re.match(r'Parsing Lun (\d+)', line)
if m:
lun = int(m.group(1)); continue
m = re.match(r'(\S+):\s+Offset 0x[0-9a-f]+, Length 0x([0-9a-f]+)', line)
if m and lun is not None:
gpt[m.group(1)] = (lun, int(m.group(2), 16))

problems, count = [], 0
for d in sorted(os.listdir(stage)):
m = re.fullmatch(r'lun(\d+)', d)
if not m:
continue
folder_lun = int(m.group(1))
for f in sorted(os.listdir(os.path.join(stage, d))):
if not f.endswith('.bin'):
continue
count += 1
name = f[:-4]
size = os.path.getsize(os.path.join(stage, d, f))
if name in NEVER:
problems.append(f'{d}/{f}: {name} must never be written')
elif not name.endswith('_b'):
problems.append(f'{d}/{f}: not a slot-b partition')
elif name not in gpt:
problems.append(f'{d}/{f}: partition {name} does not exist on this phone')
elif gpt[name][0] != folder_lun:
problems.append(f'{d}/{f}: {name} is on lun{gpt[name][0]}, not lun{folder_lun}')
elif size != gpt[name][1]:
problems.append(f'{d}/{f}: image {size} bytes != partition {gpt[name][1]} bytes')

print(f'checked {count} images')
if problems:
print('DO NOT WRITE:')
for p in problems:
print(' ' + p)
sys.exit(1)
print('OK: every image matches a slot-b partition of exactly the same size')
python3 precheck_30e.py ~/LG-V35-backup/printgpt.log ~/LG-V35-work/30e_slot_b

我的手機跑出來的結果:

checked 26 images
OK: every image matches a slot-b partition of exactly the same size

也故意用錯的輸入測過:放了 persist、放錯 LUN、大小不符,都會列出問題並回傳錯誤碼 1。

寫入一樣是一個 LUN 呼叫一次 edl,全部在同一次 EDL 裡做完。這段也是整理後的版本(🧪):

cd edl
PY=../venv/bin/python
LOADER=Loaders/LG/0008b0e100310000_1030cd12ce708f29_fhprg.bin
STAGE=~/LG-V35-work/30e_slot_b

# 把某個 LUN 資料夾裡的所有 <分區名>.bin 一次寫入
write_lun() {
local lun=$1 names=() files=() f
for f in "$STAGE/lun$lun"/*.bin; do
names+=("$(basename "$f" .bin)"); files+=("$f")
done
(IFS=,; "$PY" edl.py w "${names[*]}" "${files[*]}" --memory=ufs --lun="$lun" --loader="$LOADER")
}

python3 ../precheck_30e.py ~/LG-V35-backup/printgpt.log "$STAGE" && \
write_lun 4 && write_lun 2 && write_lun 0 && \
"$PY" edl.py setactiveslot b --loader="$LOADER"
  • 自我檢查沒通過,就完全不會寫入
  • 用 && 串起來,任何一步失敗就停下,不會在寫入不完整時切換槽位
  • 寫入前 edl 會檢查映像是不是比分區大,太大就不寫
步驟花的時間結果
LUN4 的 21 個分區22 秒✅
LUN21 秒✅
LUN0(含 4.4 GB 的 system_b)3 分 7 秒,約 30 MB/s✅
setactiveslot b13 秒✅

寫完核對 log:每個寫入的起始磁區都等於 GPT 上 _b 分區的起點(例如 abl_b 155126、system_b 1754886、xbl_b 6),a 槽沒有被寫到。這次進 EDL 也是試了很多次才成功。

第一次開機進 Android 10​

長按電源+音量下重開,這次不按音量上。LG 標誌停了約 3 分鐘(Pie 留下的資料在做第一次開機的升級),15:03:49 adb 上線。沒有清資料,Pie 的 userdata 直接升級成功。

檢查結果
Android 版本/槽位10/_b
軟體版本V350AWM30e
出廠字串LMV350AT-00-V30e-LAO-COM-JUL-28-2020-ARB00+0
防降級(ARB)00,跟 Pie 20f 相同,之後可以退回 Pie
安全性更新2020-04-01
Bootloader仍是解鎖狀態(orange、flash.locked=0)
基頻MPSS.AT.4.0.c2.9-00088-SDM845_GEN_PACK
Wi-Fi已連線、VALIDATED,ping 正常
IMEI讀得到 15 位數
Hi-Fi Quad DACpersist.lge.hifiquaddac=true、hifi_dac=ON

30e 的 ARB 值在網路上查不到,這次直接從手機讀到是 ARB00。

升到 Android 10(30e)後的主畫面,16:26 拍

關於手機:Android 版本 10、軟體版本 V30e-310-410、型號 LM-V350AWM(S/N 和 IMEI 已塗掉)

刷成 Android 10 之後,滑動 UI 感覺比 Android 9 還順暢。

下集要做的事​

  • 移除手機上的 Google 帳號,避免觸發出廠重設保護
  • 用 EDL 把 Lineage Recovery(官方的 boot.img)寫進 boot_a、boot_b,不需要 root
  • 在 Lineage Recovery 裡 sideload copy-partitions,把 b 槽複製到 a 槽(會蓋掉 a 槽的 Pie)
  • Format data,sideload LineageOS 22.2,再 sideload MindTheGapps
  • 檢查 DAC 面板、Wi-Fi,以及要測的 App 裝不裝得上
  • 下次進 EDL 時,用整理後的 read_lun 實際跑一次(例如重讀一個小分區比對 SHA-256),把 🧪 改成 ✅

這次最花時間的兩件事都不是寫入本身:一個是進 EDL 時按鍵全程不能放,另一個是 edl 每呼叫一次就重連,分區要照 LUN 一次讀完才穩。

參考資料​

官方:

工具:

教學與討論:

韌體資料庫: