@@ -48,12 +48,21 @@ class SlotViewModel(
4848) : ViewModel() {
4949 companion object {
5050 const val TAG : String = " KernelFlasher/SlotState"
51+ const val HEADER_VER = " HEADER_VER"
52+ const val KERNEL_FMT = " KERNEL_FMT"
53+ const val RAMDISK_FMT = " RAMDISK_FMT"
5154 }
5255
56+ data class BootInfo (
57+ var kernelVersion : String? = null ,
58+ var bootFmt : String? = null ,
59+ var headerVersion : String? = null ,
60+ var initBootFmt : String? = null ,
61+ var ramdiskLocation : String? = null
62+ )
63+
5364 private var _sha1 : String? = null
54- var kernelVersion: String? = null
55- var bootFmt: String? = null
56- var initBootFmt: String? = null
65+ private val _bootInfo : MutableState <BootInfo > = mutableStateOf(BootInfo ())
5766 var hasVendorDlkm: Boolean = false
5867 var isVendorDlkmMapped: Boolean = false
5968 var isVendorDlkmMounted: Boolean = false
@@ -86,58 +95,49 @@ class SlotViewModel(
8695 get() = _error
8796 val showCautionDialog: Boolean
8897 get() = _showCautionDialog .value
98+ val bootInfo: BootInfo
99+ get() = _bootInfo .value
89100
90101 init {
91102 refresh(context)
92103 }
93104
94- /* *
95- * Extracts the KERNEL_FMT value from the given boot_unpack_op string.
96- *
97- * @param fmtString The full unpack output as a single string.
98- * @return The value of KERNEL_FMT (e.g., "raw"), or null if not found.
99- */
100- fun extractKernelFmt (fmtString : String ): String? {
101- // Split the string into lines
102- val lines = fmtString.split(" \n " )
103-
104- // Iterate through each line
105- for (line in lines) {
106- // Check if the line starts with "KERNEL_FMT"
107- if (line.trim().startsWith(" KERNEL_FMT" ) || line.trim().startsWith(" RAMDISK_FMT" )) {
108- // Split the line by '[' and ']' to extract the value
109- val parts = line.split(" [" , " ]" )
110- if (parts.size > 1 ) {
111- return parts[1 ].trim() // Return the value inside the brackets
112- }
113- }
114- }
115-
116- // Return null if KERNEL_FMT is not found
117- return null
105+ private fun extractKernelValues (input : String , key : String ): String? {
106+ val regex = Regex (" $key \\ s*\\ [([^]]+)]" )
107+ return regex.find(input)?.groupValues?.get(1 )
118108 }
119109
120110 fun refresh (context : Context ) {
121111 _error = null
112+ _sha1 = null
113+ _bootInfo .value = _bootInfo .value.copy(kernelVersion = null , bootFmt = null , headerVersion = null , initBootFmt = null , ramdiskLocation = null )
122114
123115 if (! isActive) {
124116 inInit = true
125117 }
126118
127119 val magiskboot = File (context.filesDir, " magiskboot" )
128- // getOut() return List<string>
120+ Shell .cmd(" $magiskboot cleanup" ).exec()
121+
129122 val unpackBootOutput = mutableListOf<String >()
130- Shell .Builder .create().setFlags( Shell . FLAG_MOUNT_MASTER ).build().newJob().add (" $magiskboot unpack $boot " ).to(unpackBootOutput, unpackBootOutput).exec()
131- val boot_unpack_op = unpackBootOutput.joinToString(" \n " )
123+ Shell .cmd (" $magiskboot unpack $boot " ).to(unpackBootOutput, unpackBootOutput).exec()
124+ val bootUnpackOp = unpackBootOutput.joinToString(" \n " )
132125
133- bootFmt = extractKernelFmt(boot_unpack_op.trimIndent())
134- if (initBoot != null ) {
135- Shell .cmd(" $magiskboot unpack $initBoot " ).exec()
126+ _bootInfo .value.headerVersion = extractKernelValues(bootUnpackOp.trimIndent(), HEADER_VER )
127+ _bootInfo .value.bootFmt = extractKernelValues(bootUnpackOp.trimIndent(), KERNEL_FMT )
128+ _bootInfo .value.initBootFmt = extractKernelValues(bootUnpackOp.trimIndent(), RAMDISK_FMT )
129+ if (_bootInfo .value.initBootFmt != null )
130+ _bootInfo .value.ramdiskLocation = " boot.img"
136131
132+ Log .d(TAG , _bootInfo .value.toString())
133+ if (initBoot != null && _bootInfo .value.initBootFmt == null ) {
137134 val unpackInitBootOutput = mutableListOf<String >()
138- Shell .Builder .create().setFlags(Shell .FLAG_MOUNT_MASTER ).build().newJob().add(" $magiskboot unpack $initBoot " ).to(unpackInitBootOutput, unpackInitBootOutput).exec()
139- val init_boot_unpack_op = unpackInitBootOutput.joinToString(" \n " )
140- initBootFmt = extractKernelFmt(init_boot_unpack_op.trimIndent())
135+ if (Shell .cmd(" $magiskboot unpack $initBoot " ).to(unpackInitBootOutput, unpackInitBootOutput).exec().isSuccess)
136+ {
137+ val initBootUnpackOp = unpackInitBootOutput.joinToString(" \n " )
138+ _bootInfo .value.initBootFmt = extractKernelValues(initBootUnpackOp.trimIndent(), RAMDISK_FMT )
139+ _bootInfo .value.ramdiskLocation = " init_boot.img"
140+ }
141141 }
142142
143143 val ramdisk = File (context.filesDir, " ramdisk.cpio" )
@@ -166,16 +166,26 @@ class SlotViewModel(
166166 }
167167 } else if (kernel.exists()) {
168168 _sha1 = Shell .cmd(" $magiskboot sha1 $boot " ).exec().out .firstOrNull()
169+ if (_bootInfo .value.headerVersion.equals(" 4" ) && _bootInfo .value.ramdiskLocation.equals(null ))
170+ {
171+ _bootInfo .value.ramdiskLocation = " boot.img"
172+ _bootInfo .value.initBootFmt = " lz4_legacy"
173+ }
169174 } else {
170- _error = " Invalid boot.img, no ramdisk or kernel found"
175+ if (_bootInfo .value.headerVersion.equals(" 4" ) && _bootInfo .value.ramdiskLocation.equals(null ))
176+ {
177+ _bootInfo .value.ramdiskLocation = " boot.img"
178+ _bootInfo .value.initBootFmt = " lz4_legacy"
179+ }
180+ _error = " Unable to generate SHA1 hash. Invalid boot.img or magiskboot unpack failed!"
171181 }
172182 Shell .cmd(" $magiskboot cleanup" ).exec()
173183
174184 PartitionUtil .AvailablePartitions .forEach { partitionName ->
175185 _backupPartitions [partitionName] = true
176186 }
177187
178- kernelVersion = null
188+ _bootInfo .value. kernelVersion = null
179189 inInit = false
180190 }
181191
@@ -291,14 +301,11 @@ class SlotViewModel(
291301 private fun _getKernel (context : Context ) {
292302 val magiskboot = File (context.filesDir, " magiskboot" )
293303 Shell .cmd(" $magiskboot unpack $boot " ).exec()
294- if (initBoot != null ) {
295- Shell .cmd(" $magiskboot unpack $initBoot " ).exec()
296- }
297304 val kernel = File (context.filesDir, " kernel" )
298305 if (kernel.exists()) {
299306 val result = Shell .cmd(" strings kernel | grep -E -m1 'Linux version.*#' | cut -d\\ -f3-" ).exec().out
300307 if (result.isNotEmpty()) {
301- kernelVersion = result[0 ].replace(""" \(.+\)""" .toRegex(), " " ).replace(""" \s+""" .toRegex(), " " )
308+ _bootInfo .value. kernelVersion = result[0 ].replace(""" \(.+\)""" .toRegex(), " " ).replace(""" \s+""" .toRegex(), " " )
302309 }
303310 }
304311 Shell .cmd(" $magiskboot cleanup" ).exec()
@@ -425,13 +432,13 @@ class SlotViewModel(
425432 fun backup (context : Context ) {
426433 launch {
427434 _clearFlash ()
428- val currentKernelVersion = if (kernelVersion != null ) {
429- kernelVersion
435+ val currentKernelVersion = if (_bootInfo .value. kernelVersion != null ) {
436+ _bootInfo .value. kernelVersion
430437 } else if (isActive) {
431438 System .getProperty(" os.version" )!!
432439 } else {
433440 _getKernel (context)
434- kernelVersion
441+ _bootInfo .value. kernelVersion
435442 }
436443 val now = LocalDateTime .now().format(DateTimeFormatter .ofPattern(" yyyy-MM-dd--HH-mm" ))
437444 val backupDir = createBackupDir(context, now)
@@ -458,7 +465,7 @@ class SlotViewModel(
458465 val now = LocalDateTime .now().format(DateTimeFormatter .ofPattern(" yyyy-MM-dd--HH-mm" ))
459466 val backupDir = createBackupDir(context, now)
460467 val jsonFile = backupDir.getChildFile(" backup.json" )
461- val backup = Backup (now, " ak3" , kernelVersion!! , null , flashFilename)
468+ val backup = Backup (now, " ak3" , _bootInfo .value. kernelVersion!! , null , flashFilename)
462469 val indentedJson = Json { prettyPrint = true }
463470 jsonFile.outputStream().use { it.write(indentedJson.encodeToString(backup).toByteArray(Charsets .UTF_8 )) }
464471 val destination = backupDir.getChildFile(flashFilename!! )
0 commit comments