@@ -48,12 +48,21 @@ class SlotViewModel(
48
48
) : ViewModel() {
49
49
companion object {
50
50
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"
51
54
}
52
55
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
+
53
64
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 ())
57
66
var hasVendorDlkm: Boolean = false
58
67
var isVendorDlkmMapped: Boolean = false
59
68
var isVendorDlkmMounted: Boolean = false
@@ -86,58 +95,49 @@ class SlotViewModel(
86
95
get() = _error
87
96
val showCautionDialog: Boolean
88
97
get() = _showCautionDialog .value
98
+ val bootInfo: BootInfo
99
+ get() = _bootInfo .value
89
100
90
101
init {
91
102
refresh(context)
92
103
}
93
104
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 )
118
108
}
119
109
120
110
fun refresh (context : Context ) {
121
111
_error = null
112
+ _sha1 = null
113
+ _bootInfo .value = _bootInfo .value.copy(kernelVersion = null , bootFmt = null , headerVersion = null , initBootFmt = null , ramdiskLocation = null )
122
114
123
115
if (! isActive) {
124
116
inInit = true
125
117
}
126
118
127
119
val magiskboot = File (context.filesDir, " magiskboot" )
128
- // getOut() return List<string>
120
+ Shell .cmd(" $magiskboot cleanup" ).exec()
121
+
129
122
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 " )
132
125
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"
136
131
132
+ Log .d(TAG , _bootInfo .value.toString())
133
+ if (initBoot != null && _bootInfo .value.initBootFmt == null ) {
137
134
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
+ }
141
141
}
142
142
143
143
val ramdisk = File (context.filesDir, " ramdisk.cpio" )
@@ -166,16 +166,26 @@ class SlotViewModel(
166
166
}
167
167
} else if (kernel.exists()) {
168
168
_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
+ }
169
174
} 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!"
171
181
}
172
182
Shell .cmd(" $magiskboot cleanup" ).exec()
173
183
174
184
PartitionUtil .AvailablePartitions .forEach { partitionName ->
175
185
_backupPartitions [partitionName] = true
176
186
}
177
187
178
- kernelVersion = null
188
+ _bootInfo .value. kernelVersion = null
179
189
inInit = false
180
190
}
181
191
@@ -291,14 +301,11 @@ class SlotViewModel(
291
301
private fun _getKernel (context : Context ) {
292
302
val magiskboot = File (context.filesDir, " magiskboot" )
293
303
Shell .cmd(" $magiskboot unpack $boot " ).exec()
294
- if (initBoot != null ) {
295
- Shell .cmd(" $magiskboot unpack $initBoot " ).exec()
296
- }
297
304
val kernel = File (context.filesDir, " kernel" )
298
305
if (kernel.exists()) {
299
306
val result = Shell .cmd(" strings kernel | grep -E -m1 'Linux version.*#' | cut -d\\ -f3-" ).exec().out
300
307
if (result.isNotEmpty()) {
301
- kernelVersion = result[0 ].replace(""" \(.+\)""" .toRegex(), " " ).replace(""" \s+""" .toRegex(), " " )
308
+ _bootInfo .value. kernelVersion = result[0 ].replace(""" \(.+\)""" .toRegex(), " " ).replace(""" \s+""" .toRegex(), " " )
302
309
}
303
310
}
304
311
Shell .cmd(" $magiskboot cleanup" ).exec()
@@ -425,13 +432,13 @@ class SlotViewModel(
425
432
fun backup (context : Context ) {
426
433
launch {
427
434
_clearFlash ()
428
- val currentKernelVersion = if (kernelVersion != null ) {
429
- kernelVersion
435
+ val currentKernelVersion = if (_bootInfo .value. kernelVersion != null ) {
436
+ _bootInfo .value. kernelVersion
430
437
} else if (isActive) {
431
438
System .getProperty(" os.version" )!!
432
439
} else {
433
440
_getKernel (context)
434
- kernelVersion
441
+ _bootInfo .value. kernelVersion
435
442
}
436
443
val now = LocalDateTime .now().format(DateTimeFormatter .ofPattern(" yyyy-MM-dd--HH-mm" ))
437
444
val backupDir = createBackupDir(context, now)
@@ -458,7 +465,7 @@ class SlotViewModel(
458
465
val now = LocalDateTime .now().format(DateTimeFormatter .ofPattern(" yyyy-MM-dd--HH-mm" ))
459
466
val backupDir = createBackupDir(context, now)
460
467
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)
462
469
val indentedJson = Json { prettyPrint = true }
463
470
jsonFile.outputStream().use { it.write(indentedJson.encodeToString(backup).toByteArray(Charsets .UTF_8 )) }
464
471
val destination = backupDir.getChildFile(flashFilename!! )
0 commit comments