Skip to content

Commit 2f78727

Browse files
committed
Add Support for KernelSU LKM driver Flash
- Might be buggy on Pixel 6\Pixel 6A stock boot.img
1 parent 78b3d6d commit 2f78727

File tree

12 files changed

+184
-7
lines changed

12 files changed

+184
-7
lines changed

app/src/main/assets/ksuinit

455 KB
Binary file not shown.

app/src/main/java/com/github/capntrips/kernelflasher/MainActivity.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ class MainActivity : ComponentActivity() {
188188
copyNativeBinary("httools_static") // v3.2.0
189189
copyNativeBinary("magiskboot") // v29.0
190190
copyAsset("mkbootfs")
191+
copyAsset("ksuinit")
191192
copyAsset("flash_ak3.sh")
192193
copyAsset("flash_ak3_mkbootfs.sh")
193194
} catch (e: Exception) {

app/src/main/java/com/github/capntrips/kernelflasher/ui/components/FlashButton.kt

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package com.github.capntrips.kernelflasher.ui.components
22

33
import android.net.Uri
4+
import android.provider.OpenableColumns
5+
import android.widget.Toast
46
import androidx.activity.compose.rememberLauncherForActivityResult
57
import androidx.activity.result.contract.ActivityResultContracts
68
import androidx.compose.animation.ExperimentalAnimationApi
@@ -28,6 +30,7 @@ import kotlinx.serialization.ExperimentalSerializationApi
2830
@Composable
2931
fun FlashButton(
3032
buttonText: String,
33+
validExtension: String,
3134
callback: (uri: Uri) -> Unit
3235
) {
3336
val mainActivity = LocalContext.current as MainActivity
@@ -51,7 +54,23 @@ fun FlashButton(
5154
}
5255
result.value?.let {uri ->
5356
if (mainActivity.isAwaitingResult) {
54-
callback.invoke(uri)
57+
val contentResolver = mainActivity.contentResolver
58+
val fileName = contentResolver.query(uri, null, null, null, null)?.use { cursor ->
59+
val nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
60+
if (nameIndex != -1 && cursor.moveToFirst()) {
61+
cursor.getString(nameIndex)
62+
} else {
63+
null
64+
}
65+
}
66+
67+
if (fileName != null && fileName.endsWith(validExtension, ignoreCase = true)) {
68+
callback.invoke(uri)
69+
}
70+
else {
71+
// Invalid file extension, show an error message or handle it
72+
Toast.makeText(mainActivity.applicationContext, "Invalid file selected!", Toast.LENGTH_LONG).show()
73+
}
5574
}
5675
mainActivity.isAwaitingResult = false
5776
}

app/src/main/java/com/github/capntrips/kernelflasher/ui/screens/slot/SlotFlashContent.kt

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,18 +78,24 @@ fun ColumnScope.SlotFlashContent(
7878
if (navController.currentDestination!!.route!!.endsWith("/flash")) {
7979
DataCard (stringResource(R.string.flash))
8080
Spacer(Modifier.height(5.dp))
81-
FlashButton(stringResource(R.string.flash_ak3_zip), callback = { uri ->
81+
FlashButton(stringResource(R.string.flash_ak3_zip), "zip" ,callback = { uri ->
8282
navController.navigate("slot$slotSuffix/flash/ak3") {
8383
popUpTo("slot$slotSuffix")
8484
}
8585
viewModel.flashAk3(context, uri)
8686
})
87-
FlashButton(stringResource(R.string.flash_ak3_zip_mkbootfs), callback = { uri ->
87+
FlashButton(stringResource(R.string.flash_ak3_zip_mkbootfs), "zip" ,callback = { uri ->
8888
navController.navigate("slot$slotSuffix/flash/ak3") {
8989
popUpTo("slot$slotSuffix")
9090
}
9191
viewModel.flashAk3_mkbootfs(context, uri)
9292
})
93+
FlashButton(stringResource(R.string.flash_ksu_lkm), "ko" ,callback = { uri ->
94+
navController.navigate("slot$slotSuffix/flash/image/flash") {
95+
popUpTo("slot$slotSuffix")
96+
}
97+
viewModel.flashKsuDriver(context, uri)
98+
})
9399
OutlinedButton(
94100
modifier = Modifier
95101
.fillMaxWidth(),
@@ -104,7 +110,7 @@ fun ColumnScope.SlotFlashContent(
104110
DataCard (stringResource(R.string.flash_partition_image))
105111
Spacer(Modifier.height(5.dp))
106112
for (partitionName in PartitionUtil.AvailablePartitions) {
107-
FlashButton(partitionName, callback = { uri ->
113+
FlashButton(partitionName, "img" ,callback = { uri ->
108114
navController.navigate("slot$slotSuffix/flash/image/flash") {
109115
popUpTo("slot$slotSuffix")
110116
}
@@ -195,13 +201,13 @@ fun ColumnScope.SlotFlashContent(
195201
}
196202
}
197203
}
198-
if (navController.currentDestination!!.route!!.contains("ak3") && viewModel.wasFlashSuccess.value == true && viewModel.showCautionDialog == true){
204+
if (viewModel.wasFlashSuccess.value == true && viewModel.showCautionDialog == true){
199205
AlertDialog(
200206
onDismissRequest = { viewModel.hideCautionDialog() },
201207
title = { Text("CAUTION!", style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.Bold) },
202208
text = {
203209
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
204-
Text("You have flashed AnyKernel Zip to inactive slot!", fontWeight = FontWeight.Bold)
210+
Text("You have flashed to inactive slot!", fontWeight = FontWeight.Bold)
205211
Text("But the active slot is not changed after flashing.", fontWeight = FontWeight.Bold)
206212
Text("Change active slot or return to System Updater to complete OTA.", fontWeight = FontWeight.Bold)
207213
Text("Do not reboot from here, unless you know what you are doing.", fontWeight = FontWeight.Bold)

app/src/main/java/com/github/capntrips/kernelflasher/ui/screens/slot/SlotViewModel.kt

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,24 @@ class SlotViewModel(
551551
}
552552
}
553553

554+
@Suppress("FunctionName")
555+
private fun _copyDriver(context: Context, uri: Uri) {
556+
flashUri = uri
557+
flashFilename = context.contentResolver.query(uri, null, null, null, null)?.use { cursor ->
558+
if (!cursor.moveToFirst()) return@use null
559+
val name = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
560+
return@use cursor.getString(name)
561+
} ?: "kernelsu.ko"
562+
val source = context.contentResolver.openInputStream(uri)
563+
val file = File(context.filesDir, "kernelsu.ko")
564+
source.use { inputStream ->
565+
file.outputStream().use { outputStream ->
566+
inputStream?.copyTo(outputStream)
567+
}
568+
}
569+
Shell.cmd("chmod +rwx $file").exec()
570+
}
571+
554572
@Suppress("FunctionName")
555573
private suspend fun _flashAk3(context: Context, type: String) {
556574
if (!isActive) {
@@ -645,6 +663,129 @@ class SlotViewModel(
645663
}
646664
}
647665

666+
fun flashKsuDriver(context: Context, uri: Uri) {
667+
launch {
668+
_clearFlash()
669+
addMessage("Copying KernelSU Driver ...")
670+
_copyDriver(context, uri)
671+
if (!isActive) {
672+
resetSlot()
673+
}
674+
val driver = fileSystemManager.getFile(context.filesDir, "kernelsu.ko")
675+
val newBootImg = File(context.filesDir, "new-boot.img")
676+
var image: ExtendedFile? = null
677+
try {
678+
if (driver.exists()) {
679+
addMessage("Copied $flashFilename")
680+
_wasFlashSuccess.value = false
681+
val partitionName = bootInfo.ramdiskLocation?.removeSuffix(".img") ?: "boot"
682+
val magiskboot = File(context.filesDir, "magiskboot")
683+
val ksuinit = File(context.filesDir, "ksuinit")
684+
if(partitionName == "boot")
685+
{
686+
addMessage("Unpacking boot.img")
687+
Shell.cmd("$magiskboot unpack $boot").exec()
688+
}
689+
else
690+
{
691+
addMessage("Unpacking init_boot")
692+
Shell.cmd("$magiskboot unpack $initBoot").exec()
693+
}
694+
695+
val ramdisk = File(context.filesDir, "ramdisk.cpio")
696+
697+
if (ramdisk.exists()) {
698+
addMessage("Patching Ramdisk")
699+
700+
if(Shell.cmd("$magiskboot cpio ramdisk.cpio 'exists kernelsu.ko'").to(flashOutput, flashOutput).exec().isSuccess) {
701+
Shell.cmd("$magiskboot cpio ramdisk.cpio 'rm init'")
702+
.to(flashOutput, flashOutput).exec()
703+
Shell.cmd("$magiskboot cpio ramdisk.cpio 'add 0755 init $ksuinit'")
704+
.to(flashOutput, flashOutput).exec()
705+
Shell.cmd("$magiskboot cpio ramdisk.cpio 'rm kernelsu.ko'")
706+
.to(flashOutput, flashOutput).exec()
707+
Shell.cmd("$magiskboot cpio ramdisk.cpio 'add 0755 kernelsu.ko $driver'")
708+
.to(flashOutput, flashOutput).exec()
709+
}
710+
else
711+
{
712+
Shell.cmd("$magiskboot cpio ramdisk.cpio 'mv init init.real'").to(flashOutput, flashOutput).exec()
713+
Shell.cmd("$magiskboot cpio ramdisk.cpio 'add 0755 init $ksuinit'")
714+
.to(flashOutput, flashOutput).exec()
715+
Shell.cmd("$magiskboot cpio ramdisk.cpio 'add 0755 kernelsu.ko $driver'")
716+
.to(flashOutput, flashOutput).exec()
717+
}
718+
if(partitionName == "boot")
719+
{
720+
addMessage("Repacking boot.img")
721+
Shell.cmd("$magiskboot repack $boot").exec()
722+
}
723+
else
724+
{
725+
addMessage("Repacking init_boot.img")
726+
Shell.cmd("$magiskboot repack $initBoot").exec()
727+
}
728+
729+
if(newBootImg.exists()) {
730+
image = fileSystemManager.getFile(context.filesDir, "new-boot.img")
731+
}
732+
else {
733+
Shell.cmd("$magiskboot cleanup").exec()
734+
log(context, "Image Repack Failed!", shouldThrow = true)
735+
}
736+
} else {
737+
Shell.cmd("$magiskboot cleanup").exec()
738+
log(context, "Ramdisk not found", shouldThrow = true)
739+
}
740+
Shell.cmd("$magiskboot cleanup").exec()
741+
742+
addMessage("Flashing $image to $partitionName$slotSuffix ...")
743+
val blockDevice = partitionName?.let {
744+
PartitionUtil.findPartitionBlockDevice(context,
745+
it, slotSuffix)
746+
}
747+
if (blockDevice != null && blockDevice.exists()) {
748+
if (PartitionUtil.isPartitionLogical(context, partitionName)) {
749+
if (image != null) {
750+
PartitionUtil.flashLogicalPartition(context, image, blockDevice, partitionName, slotSuffix, hashAlgorithm) { message ->
751+
addMessage(message)
752+
}
753+
}
754+
} else {
755+
if (image != null) {
756+
PartitionUtil.flashBlockDevice(image, blockDevice, hashAlgorithm)
757+
}
758+
}
759+
} else {
760+
log(context, "Partition $partitionName$slotSuffix was not found", shouldThrow = true)
761+
}
762+
addMessage("Flashed ${image?.name} to $partitionName$slotSuffix")
763+
addMessage("Cleaning up ...")
764+
clearTmp(context)
765+
addMessage("Done.")
766+
_wasFlashSuccess.value = true
767+
} else {
768+
log(context, "KernelSU Driver is missing", shouldThrow = true)
769+
}
770+
} catch (e: Exception) {
771+
clearFlash(context)
772+
throw e
773+
} finally {
774+
addMessage("")
775+
if (driver.exists())
776+
driver.delete()
777+
if (newBootImg.exists())
778+
newBootImg.delete()
779+
if (wasSlotReset) {
780+
resetSlot()
781+
viewModelScope.launch(Dispatchers.Main) {
782+
showCautionDialog() // Show dialog instead of uiPrint
783+
}
784+
}
785+
}
786+
}
787+
}
788+
648789
fun flashImage(context: Context, uri: Uri, partitionName: String) {
649790
launch {
650791
_clearFlash()
@@ -686,6 +827,9 @@ class SlotViewModel(
686827
addMessage("")
687828
if (wasSlotReset) {
688829
resetSlot()
830+
viewModelScope.launch(Dispatchers.Main) {
831+
showCautionDialog() // Show dialog instead of uiPrint
832+
}
689833
}
690834
}
691835
}

app/src/main/res/values-ja/strings.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@
3131
<string name="flash_ak3_zip">AK3 Zip をフラッシュ</string>
3232
<string name="flash_ak3_zip_mkbootfs">mkbootfs を使って AK3 Zip をフラッシュする</string>
3333
<string name="flash_partition_image">パーティションイメージをフラッシュ</string>
34-
<string name="restore">復元</string>
34+
<string name="flash_ksu_lkm">" KernelSU LKM Driver"</string>
35+
<string name="restore">復元</string>
3536
<string name="check_kernel_version">カーネルバージョンを確認</string>
3637
<string name="mount_vendor_dlkm">Vendor DLKM をマウント</string>
3738
<string name="unmount_vendor_dlkm">Vendor DLKM をアンマウント</string>

app/src/main/res/values-pl/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
<string name="flash_ak3_zip">Sflashuj archiwum AK3</string>
3232
<string name="flash_ak3_zip_mkbootfs">Flashuj archiwum AK3 za pomocą mkbootfs</string>
3333
<string name="flash_partition_image">Sflashuj obraz partycji</string>
34+
<string name="flash_ksu_lkm">Sflashuj KernelSU LKM Driver</string>
3435
<string name="restore">Przywróć</string>
3536
<string name="check_kernel_version">Sprawdź wersję jądra</string>
3637
<string name="mount_vendor_dlkm">Zamontuj Vendor DLKM</string>

app/src/main/res/values-pt-rBR/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
<string name="flash_ak3_zip">Flash AK3 ZIP</string>
3131
<string name="flash_ak3_zip_mkbootfs">Flash AK3 Zip using mkbootfs</string>
3232
<string name="flash_partition_image">Flashar imagem de partição</string>
33+
<string name="flash_ksu_lkm">Flash KernelSU LKM Driver</string>
3334
<string name="restore">Restaurar</string>
3435
<string name="check_kernel_version">Verificar versão do kernel</string>
3536
<string name="mount_vendor_dlkm">Montar Vendor DLKM</string>

app/src/main/res/values-ru/string.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
<string name="flash_ak3_zip">Прошить AK3 Zip</string>
3131
<string name="flash_ak3_zip_mkbootfs">Прошить AK3 Zip с помощью mkbootfs</string>
3232
<string name="flash_partition_image">Прошить образ раздела</string>
33+
<string name="flash_ksu_lkm">Прошивка KernelSU LKM Driver</string>
3334
<string name="restore">Восстановить</string>
3435
<string name="check_kernel_version">Проверить версию ядра</string>
3536
<string name="mount_vendor_dlkm">Подключить Vendor DLKM</string>

app/src/main/res/values-zh-rCN/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
<string name="flash_ak3_zip">刷入 AK3 压缩包</string>
3131
<string name="flash_ak3_zip_mkbootfs">刷入 AK3 压缩包 使用 mkbootfs</string>
3232
<string name="flash_partition_image">刷入分区镜像</string>
33+
<string name="flash_ksu_lkm">刷入 KernelSU LKM Driver</string>
3334
<string name="restore">恢复</string>
3435
<string name="check_kernel_version">检查内核版本</string>
3536
<string name="mount_vendor_dlkm">挂载 Vendor DLKM</string>

0 commit comments

Comments
 (0)