@@ -18,12 +18,6 @@ obj-$(CONFIG_KSU) += kernelsu.o
|
|||||||
|
|
||||||
obj-$(CONFIG_KPM) += kpm/
|
obj-$(CONFIG_KPM) += kpm/
|
||||||
|
|
||||||
ifeq ($(CONFIG_KPM),y)
|
|
||||||
$(info -- KPM is enabled)
|
|
||||||
else
|
|
||||||
$(info -- KPM is disabled)
|
|
||||||
endif
|
|
||||||
|
|
||||||
|
|
||||||
# .git is a text file while the module is imported by 'git submodule add'.
|
# .git is a text file while the module is imported by 'git submodule add'.
|
||||||
ifeq ($(shell test -e $(srctree)/$(src)/../.git; echo $$?),0)
|
ifeq ($(shell test -e $(srctree)/$(src)/../.git; echo $$?),0)
|
||||||
@@ -56,6 +50,11 @@ $(info -- KernelSU Manager signature hash: $(KSU_EXPECTED_HASH))
|
|||||||
$(info -- Supported Unofficial Manager: 5ec1cff (GKI) ShirkNeko udochina (GKI and KPM))
|
$(info -- Supported Unofficial Manager: 5ec1cff (GKI) ShirkNeko udochina (GKI and KPM))
|
||||||
KERNEL_VERSION := $(VERSION).$(PATCHLEVEL)
|
KERNEL_VERSION := $(VERSION).$(PATCHLEVEL)
|
||||||
$(info -- KERNEL_VERSION: $(KERNEL_VERSION))
|
$(info -- KERNEL_VERSION: $(KERNEL_VERSION))
|
||||||
|
ifeq ($(CONFIG_KPM),y)
|
||||||
|
$(info -- KPM is enabled)
|
||||||
|
else
|
||||||
|
$(info -- KPM is disabled)
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
ccflags-y += -DEXPECTED_SIZE=$(KSU_EXPECTED_SIZE)
|
ccflags-y += -DEXPECTED_SIZE=$(KSU_EXPECTED_SIZE)
|
||||||
|
|||||||
@@ -419,10 +419,7 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
|
|||||||
|
|
||||||
pr_info("KPM: calling before arg2=%d\n", (int) arg2);
|
pr_info("KPM: calling before arg2=%d\n", (int) arg2);
|
||||||
|
|
||||||
res = sukisu_handle_kpm(arg2, arg3, arg4);
|
res = sukisu_handle_kpm(arg2, arg3, arg4, arg5);
|
||||||
copy_to_user(result, &res, sizeof(res));
|
|
||||||
|
|
||||||
pr_info("KPM: calling before arg2=%d res=%d\n", (int) arg2, (int) res);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +1,4 @@
|
|||||||
obj-y += kpm.o
|
obj-y += kpm.o
|
||||||
obj-y += compact.o
|
obj-y += compact.o
|
||||||
|
|
||||||
|
ccflags-y += -flto=thin
|
||||||
116
kernel/kpm/kpm.c
116
kernel/kpm/kpm.c
@@ -44,37 +44,83 @@
|
|||||||
#include "kpm.h"
|
#include "kpm.h"
|
||||||
#include "compact.h"
|
#include "compact.h"
|
||||||
|
|
||||||
|
#ifndef NO_OPTIMIZE
|
||||||
|
#if defined(__GNUC__) && !defined(__clang__)
|
||||||
|
#define NO_OPTIMIZE __attribute__((optimize("O0")))
|
||||||
|
#elif defined(__clang__)
|
||||||
|
#define NO_OPTIMIZE __attribute__((optnone))
|
||||||
|
#else
|
||||||
|
#define NO_OPTIMIZE
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
// ============================================================================================
|
// ============================================================================================
|
||||||
|
|
||||||
int sukisu_kpm_load_module_path(const char* path, const char* args, void* ptr) {
|
noinline
|
||||||
|
NO_OPTIMIZE
|
||||||
|
void sukisu_kpm_load_module_path(const char* path, const char* args, void* ptr, void __user* result) {
|
||||||
// This is a KPM module stub.
|
// This is a KPM module stub.
|
||||||
return -1;
|
int res = -1;
|
||||||
|
printk("KPM: Stub function called (sukisu_kpm_load_module_path). path=%s args=%s ptr=%p\n", path, args, ptr);
|
||||||
|
__asm__ volatile("nop"); // 精确控制循环不被优化
|
||||||
|
if(copy_to_user(result, &res, sizeof(res)) < 1) printk("KPM: Copy to user faild.");
|
||||||
}
|
}
|
||||||
|
|
||||||
int sukisu_kpm_unload_module(const char* name, void* ptr) {
|
noinline
|
||||||
|
NO_OPTIMIZE
|
||||||
|
void sukisu_kpm_unload_module(const char* name, void* ptr, void __user* result) {
|
||||||
// This is a KPM module stub.
|
// This is a KPM module stub.
|
||||||
return -1;
|
int res = -1;
|
||||||
|
printk("KPM: Stub function called (sukisu_kpm_unload_module). name=%s ptr=%p\n", name, ptr);
|
||||||
|
__asm__ volatile("nop"); // 精确控制循环不被优化
|
||||||
|
if(copy_to_user(result, &res, sizeof(res)) < 1) printk("KPM: Copy to user faild.");
|
||||||
}
|
}
|
||||||
|
|
||||||
int sukisu_kpm_num(void) {
|
noinline
|
||||||
|
NO_OPTIMIZE
|
||||||
|
void sukisu_kpm_num(void __user* result) {
|
||||||
// This is a KPM module stub.
|
// This is a KPM module stub.
|
||||||
return 0;
|
int res = 0;
|
||||||
|
printk("KPM: Stub function called (sukisu_kpm_num).\n");
|
||||||
|
__asm__ volatile("nop"); // 精确控制循环不被优化
|
||||||
|
if(copy_to_user(result, &res, sizeof(res)) < 1) printk("KPM: Copy to user faild.");
|
||||||
}
|
}
|
||||||
|
|
||||||
int sukisu_kpm_info(const char* name, void __user* out) {
|
noinline
|
||||||
|
NO_OPTIMIZE
|
||||||
|
void sukisu_kpm_info(const char* name, void __user* out, void __user* result) {
|
||||||
// This is a KPM module stub.
|
// This is a KPM module stub.
|
||||||
return -1;
|
int res = -1;
|
||||||
|
printk("KPM: Stub function called (sukisu_kpm_info). name=%s buffer=%p\n", name, out);
|
||||||
|
__asm__ volatile("nop"); // 精确控制循环不被优化
|
||||||
|
if(copy_to_user(result, &res, sizeof(res)) < 1) printk("KPM: Copy to user faild.");
|
||||||
}
|
}
|
||||||
|
|
||||||
int sukisu_kpm_list(void __user* out, unsigned int bufferSize) {
|
noinline
|
||||||
|
NO_OPTIMIZE
|
||||||
|
void sukisu_kpm_list(void __user* out, unsigned int bufferSize, void __user* result) {
|
||||||
// This is a KPM module stub.
|
// This is a KPM module stub.
|
||||||
return -1;
|
int res = -1;
|
||||||
|
printk("KPM: Stub function called (sukisu_kpm_list). buffer=%p size=%d\n", out, bufferSize);
|
||||||
|
if(copy_to_user(result, &res, sizeof(res)) < 1) printk("KPM: Copy to user faild.");
|
||||||
}
|
}
|
||||||
|
|
||||||
void sukisu_kpm_print_list(void) {
|
noinline
|
||||||
|
NO_OPTIMIZE
|
||||||
|
void sukisu_kpm_control(void __user* name, void __user* args, void __user* result) {
|
||||||
|
// This is a KPM module stub.
|
||||||
|
int res = -1;
|
||||||
|
printk("KPM: Stub function called (sukisu_kpm_control). name=%p args=%p\n", name, args);
|
||||||
|
__asm__ volatile("nop"); // 精确控制循环不被优化
|
||||||
|
if(copy_to_user(result, &res, sizeof(res)) < 1) printk("KPM: Copy to user faild.");
|
||||||
}
|
}
|
||||||
|
|
||||||
void sukisu_kpm_vesion(void) {
|
noinline
|
||||||
|
NO_OPTIMIZE
|
||||||
|
void sukisu_kpm_version(void __user* out, unsigned int bufferSize, void __user* result) {
|
||||||
|
int res = -1;
|
||||||
|
printk("KPM: Stub function called (sukisu_kpm_version). buffer=%p size=%d\n", out, bufferSize);
|
||||||
|
if(copy_to_user(result, &res, sizeof(res)) < 1) printk("KPM: Copy to user faild.");
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL(sukisu_kpm_load_module_path);
|
EXPORT_SYMBOL(sukisu_kpm_load_module_path);
|
||||||
@@ -82,49 +128,51 @@ EXPORT_SYMBOL(sukisu_kpm_unload_module);
|
|||||||
EXPORT_SYMBOL(sukisu_kpm_num);
|
EXPORT_SYMBOL(sukisu_kpm_num);
|
||||||
EXPORT_SYMBOL(sukisu_kpm_info);
|
EXPORT_SYMBOL(sukisu_kpm_info);
|
||||||
EXPORT_SYMBOL(sukisu_kpm_list);
|
EXPORT_SYMBOL(sukisu_kpm_list);
|
||||||
EXPORT_SYMBOL(sukisu_kpm_print_list);
|
|
||||||
EXPORT_SYMBOL(sukisu_kpm_version);
|
EXPORT_SYMBOL(sukisu_kpm_version);
|
||||||
|
EXPORT_SYMBOL(sukisu_kpm_control);
|
||||||
|
|
||||||
|
noinline
|
||||||
int sukisu_handle_kpm(unsigned long arg3, unsigned long arg4, unsigned long arg5)
|
int sukisu_handle_kpm(unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5)
|
||||||
{
|
{
|
||||||
if(arg3 == SUKISU_KPM_LOAD) {
|
if(arg2 == SUKISU_KPM_LOAD) {
|
||||||
char kernel_load_path[256] = { 0 };
|
char kernel_load_path[256] = { 0 };
|
||||||
char kernel_args_buffer[256] = { 0 };
|
char kernel_args_buffer[256] = { 0 };
|
||||||
|
|
||||||
if(arg4 == 0) {
|
if(arg3 == 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
strncpy_from_user((char*)&kernel_load_path, (const char __user *)arg4, 255);
|
strncpy_from_user((char*)&kernel_load_path, (const char __user *)arg3, 255);
|
||||||
if(arg5 != 0) {
|
if(arg4 != 0) {
|
||||||
strncpy_from_user((char*)&kernel_args_buffer, (const char __user *)arg4, 255);
|
strncpy_from_user((char*)&kernel_args_buffer, (const char __user *)arg4, 255);
|
||||||
}
|
}
|
||||||
return sukisu_kpm_load_module_path((const char*)&kernel_load_path, (const char*) &kernel_args_buffer, NULL);
|
sukisu_kpm_load_module_path((const char*)&kernel_load_path, (const char*) &kernel_args_buffer, NULL, (void __user*) arg5);
|
||||||
} else if(arg3 == SUKISU_KPM_UNLOAD) {
|
} else if(arg2 == SUKISU_KPM_UNLOAD) {
|
||||||
char kernel_name_buffer[256] = { 0 };
|
char kernel_name_buffer[256] = { 0 };
|
||||||
|
|
||||||
if(arg4 == 0) {
|
if(arg3 == 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
strncpy_from_user((char*)&kernel_name_buffer, (const char __user *)arg4, 255);
|
strncpy_from_user((char*)&kernel_name_buffer, (const char __user *)arg3, 255);
|
||||||
return sukisu_kpm_unload_module((const char*) &kernel_name_buffer, NULL);
|
sukisu_kpm_unload_module((const char*) &kernel_name_buffer, NULL, (void __user*) arg5);
|
||||||
} else if(arg3 == SUKISU_KPM_NUM) {
|
} else if(arg2 == SUKISU_KPM_NUM) {
|
||||||
return sukisu_kpm_num();
|
sukisu_kpm_num((void __user*) arg5);
|
||||||
} else if(arg3 == SUKISU_KPM_INFO) {
|
} else if(arg2 == SUKISU_KPM_INFO) {
|
||||||
char kernel_name_buffer[256] = { 0 };
|
char kernel_name_buffer[256] = { 0 };
|
||||||
|
|
||||||
if(arg4 == 0 || arg5 == 0) {
|
if(arg3 == 0 || arg4 == 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
strncpy_from_user((char*)&kernel_name_buffer, (const char __user *)arg4, 255);
|
strncpy_from_user((char*)&kernel_name_buffer, (const char __user *)arg3, 255);
|
||||||
return sukisu_kpm_info((const char*) &kernel_name_buffer, (char __user*) arg5);
|
sukisu_kpm_info((const char*) &kernel_name_buffer, (char __user*) arg4, (void __user*) arg5);
|
||||||
} else if(arg3 == SUKISU_KPM_LIST) {
|
} else if(arg2 == SUKISU_KPM_LIST) {
|
||||||
return sukisu_kpm_list((char __user*) arg4, (unsigned int) arg5);
|
sukisu_kpm_list((char __user*) arg3, (unsigned int) arg4, (void __user*) arg5);
|
||||||
} else if(arg3 == SUKISU_KPM_PRINT) {
|
} else if(arg2 == SUKISU_KPM_VERSION) {
|
||||||
sukisu_kpm_print_list();
|
sukisu_kpm_version((char __user*) arg3, (unsigned int) arg4, (void __user*) arg5);
|
||||||
|
} else if(arg2 == SUKISU_KPM_CONTROL) {
|
||||||
|
sukisu_kpm_control((char __user*) arg3, (char __user*) arg4, (void __user*) arg5);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#ifndef ___SUKISU_KPM_H
|
#ifndef ___SUKISU_KPM_H
|
||||||
#define ___SUKISU_KPM_H
|
#define ___SUKISU_KPM_H
|
||||||
|
|
||||||
int sukisu_handle_kpm(unsigned long arg3, unsigned long arg4, unsigned long arg5);
|
int sukisu_handle_kpm(unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5);
|
||||||
int sukisu_is_kpm_control_code(unsigned long arg2);
|
int sukisu_is_kpm_control_code(unsigned long arg2);
|
||||||
|
|
||||||
// KPM控制代码
|
// KPM控制代码
|
||||||
@@ -10,44 +10,35 @@ int sukisu_is_kpm_control_code(unsigned long arg2);
|
|||||||
|
|
||||||
// 控制代码
|
// 控制代码
|
||||||
|
|
||||||
// prctl(xxx, xxx, 1, "PATH", "ARGS")
|
// prctl(xxx, 28, "PATH", "ARGS")
|
||||||
// success return 0, error return -N
|
// success return 0, error return -N
|
||||||
#define SUKISU_KPM_LOAD 28
|
#define SUKISU_KPM_LOAD 28
|
||||||
|
|
||||||
// prctl(xxx, xxx, 2, "NAME")
|
// prctl(xxx, 29, "NAME")
|
||||||
// success return 0, error return -N
|
// success return 0, error return -N
|
||||||
#define SUKISU_KPM_UNLOAD 29
|
#define SUKISU_KPM_UNLOAD 29
|
||||||
|
|
||||||
// num = prctl(xxx, xxx, 3)
|
// num = prctl(xxx, 30)
|
||||||
// error return -N
|
// error return -N
|
||||||
// success return +num or 0
|
// success return +num or 0
|
||||||
#define SUKISU_KPM_NUM 30
|
#define SUKISU_KPM_NUM 30
|
||||||
|
|
||||||
// prctl(xxx, xxx, 4, Buffer, BufferSize)
|
// prctl(xxx, 31, Buffer, BufferSize)
|
||||||
// success return +out, error return -N
|
// success return +out, error return -N
|
||||||
#define SUKISU_KPM_LIST 31
|
#define SUKISU_KPM_LIST 31
|
||||||
|
|
||||||
// prctl(xxx, xxx, 5, "NAME", Buffer[256])
|
// prctl(xxx, 32, "NAME", Buffer[256])
|
||||||
// success return +out, error return -N
|
// success return +out, error return -N
|
||||||
#define SUKISU_KPM_INFO 32
|
#define SUKISU_KPM_INFO 32
|
||||||
|
|
||||||
// prctl(xxx, xxx, 6, "NAME", "ARGS")
|
// prctl(xxx, 33, "NAME", "ARGS")
|
||||||
// success return KPM's result value
|
// success return KPM's result value
|
||||||
// error return -N
|
// error return -N
|
||||||
#define SUKISU_KPM_CONTROL 33
|
#define SUKISU_KPM_CONTROL 33
|
||||||
|
|
||||||
// prctl(xxx, xxx, 7)
|
// prctl(xxx, 34, buffer, bufferSize)
|
||||||
// success will printf to stdout and return 0
|
// success return KPM's result value
|
||||||
// error will return -1
|
// error return -N
|
||||||
#define SUKISU_KPM_PRINT 34
|
#define SUKISU_KPM_VERSION 34
|
||||||
|
|
||||||
#define SUKISU_KPM_VERSION 35
|
|
||||||
|
|
||||||
|
|
||||||
/* A64 instructions are always 32 bits. */
|
|
||||||
#define AARCH64_INSN_SIZE 4
|
|
||||||
|
|
||||||
#define AARCH64_INSN_IMM_MOVNZ AARCH64_INSN_IMM_MAX
|
|
||||||
#define AARCH64_INSN_IMM_MOVK AARCH64_INSN_IMM_16
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -51,6 +51,7 @@ import androidx.compose.animation.shrinkVertically
|
|||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import shirkneko.zako.sukisu.ui.theme.CardConfig
|
import shirkneko.zako.sukisu.ui.theme.CardConfig
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
|
import shirkneko.zako.sukisu.ui.util.KernelConfigUtils.isKpmEnabled
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Destination<RootGraph>(start = true)
|
@Destination<RootGraph>(start = true)
|
||||||
@@ -157,6 +158,7 @@ fun HomeScreen(navigator: DestinationsNavigator) {
|
|||||||
if (!isSimpleMode) {
|
if (!isSimpleMode) {
|
||||||
DonateCard()
|
DonateCard()
|
||||||
LearnMoreCard()
|
LearnMoreCard()
|
||||||
|
ContributionCard()
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer(Modifier)
|
Spacer(Modifier)
|
||||||
@@ -347,6 +349,15 @@ private fun StatusCard(
|
|||||||
style = MaterialTheme.typography.bodyMedium
|
style = MaterialTheme.typography.bodyMedium
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Spacer(modifier = Modifier.height(4.dp))
|
||||||
|
|
||||||
|
if (isKpmEnabled()) {
|
||||||
|
val kpmVersion = getKpmVersion()
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.home_kpm_version, kpmVersion),
|
||||||
|
style = MaterialTheme.typography.bodyMedium
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -404,6 +415,32 @@ fun WarningCard(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@Composable
|
||||||
|
fun ContributionCard() {
|
||||||
|
ElevatedCard(
|
||||||
|
colors = getCardColors(MaterialTheme.colorScheme.secondaryContainer),
|
||||||
|
elevation = CardDefaults.cardElevation(defaultElevation = getCardElevation())
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(24.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Column {
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.home_ContributionCard_kernelsu),
|
||||||
|
style = MaterialTheme.typography.titleSmall
|
||||||
|
)
|
||||||
|
Spacer(Modifier.height(4.dp))
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.home_click_to_ContributionCard_kernelsu),
|
||||||
|
style = MaterialTheme.typography.bodyMedium
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun LearnMoreCard() {
|
fun LearnMoreCard() {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package shirkneko.zako.sukisu.ui.screen
|
package shirkneko.zako.sukisu.ui.screen
|
||||||
|
|
||||||
import android.app.Activity.RESULT_OK
|
import android.app.Activity.RESULT_OK
|
||||||
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||||
@@ -35,7 +36,15 @@ import shirkneko.zako.sukisu.ui.viewmodel.KpmViewModel
|
|||||||
import shirkneko.zako.sukisu.ui.util.loadKpmModule
|
import shirkneko.zako.sukisu.ui.util.loadKpmModule
|
||||||
import shirkneko.zako.sukisu.ui.util.unloadKpmModule
|
import shirkneko.zako.sukisu.ui.util.unloadKpmModule
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import androidx.core.content.edit
|
||||||
|
import shirkneko.zako.sukisu.ui.theme.ThemeConfig
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* KPM 管理界面
|
||||||
|
* 以下内核模块功能由KernelPatch开发,经过修改后加入SukiSU Ultra的内核模块功能
|
||||||
|
* 开发者:Shirkneko, Liaokong
|
||||||
|
*/
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Destination<RootGraph>
|
@Destination<RootGraph>
|
||||||
@Composable
|
@Composable
|
||||||
@@ -48,6 +57,11 @@ fun KpmScreen(
|
|||||||
val snackBarHost = remember { SnackbarHostState() }
|
val snackBarHost = remember { SnackbarHostState() }
|
||||||
val confirmDialog = rememberConfirmDialog()
|
val confirmDialog = rememberConfirmDialog()
|
||||||
val loadingDialog = rememberLoadingDialog()
|
val loadingDialog = rememberLoadingDialog()
|
||||||
|
val cardColor = if (!ThemeConfig.useDynamicColor) {
|
||||||
|
ThemeConfig.currentTheme.ButtonContrast
|
||||||
|
} else {
|
||||||
|
MaterialTheme.colorScheme.secondaryContainer
|
||||||
|
}
|
||||||
|
|
||||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
|
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
|
||||||
|
|
||||||
@@ -116,6 +130,9 @@ fun KpmScreen(
|
|||||||
viewModel.fetchModuleList()
|
viewModel.fetchModuleList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 使用 SharedPreferences 存储声明是否关闭的状态
|
||||||
|
val sharedPreferences = context.getSharedPreferences("app_preferences", Context.MODE_PRIVATE)
|
||||||
|
var isNoticeClosed by remember { mutableStateOf(sharedPreferences.getBoolean("is_notice_closed", false)) }
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
@@ -151,16 +168,42 @@ fun KpmScreen(
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
text = { Text(stringResource(R.string.kpm_install)) },
|
text = { Text(stringResource(R.string.kpm_install)) },
|
||||||
containerColor = MaterialTheme.colorScheme.secondaryContainer,
|
containerColor = cardColor.copy(alpha = 1f),
|
||||||
contentColor = MaterialTheme.colorScheme.onSecondaryContainer
|
contentColor = MaterialTheme.colorScheme.onSecondaryContainer
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
snackbarHost = { SnackbarHost(snackBarHost) }
|
snackbarHost = { SnackbarHost(snackBarHost) }
|
||||||
) { padding ->
|
) { padding ->
|
||||||
|
Column(modifier = Modifier.padding(padding)) {
|
||||||
|
if (!isNoticeClosed) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(16.dp),
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.kernel_module_notice),
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
textAlign = TextAlign.Center
|
||||||
|
)
|
||||||
|
IconButton(onClick = {
|
||||||
|
isNoticeClosed = true
|
||||||
|
sharedPreferences.edit() { putBoolean("is_notice_closed", true) }
|
||||||
|
}) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Outlined.Close,
|
||||||
|
contentDescription = stringResource(R.string.close_notice)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PullToRefreshBox(
|
PullToRefreshBox(
|
||||||
onRefresh = { viewModel.fetchModuleList() },
|
onRefresh = { viewModel.fetchModuleList() },
|
||||||
isRefreshing = viewModel.isRefreshing,
|
isRefreshing = viewModel.isRefreshing,
|
||||||
modifier = Modifier.padding(padding)
|
modifier = Modifier
|
||||||
) {
|
) {
|
||||||
if (viewModel.moduleList.isEmpty()) {
|
if (viewModel.moduleList.isEmpty()) {
|
||||||
Box(
|
Box(
|
||||||
@@ -220,6 +263,7 @@ fun KpmScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun KpmModuleItem(
|
private fun KpmModuleItem(
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package shirkneko.zako.sukisu.ui.util
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
object KernelConfigUtils {
|
||||||
|
|
||||||
|
fun isKpmEnabled(): Boolean {
|
||||||
|
return try {
|
||||||
|
val config = File("/proc/config.gz").readText()
|
||||||
|
config.contains("CONFIG_KPM=y")
|
||||||
|
} catch (e: Exception) {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -528,9 +528,9 @@ fun controlKpmModule(name: String, args: String? = null): String {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
fun printKpmModules(): String {
|
fun getKpmVersion(): String {
|
||||||
val shell = getRootShell()
|
val shell = getRootShell()
|
||||||
val cmd = "${getKpmmgrPath()} print"
|
val cmd = "${getKpmmgrPath()} version"
|
||||||
val result = ShellUtils.fastCmd(shell, cmd)
|
val result = ShellUtils.fastCmd(shell, cmd)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,21 +50,16 @@ class KpmViewModel : ViewModel() {
|
|||||||
|
|
||||||
val modules = parseModuleList(moduleInfo)
|
val modules = parseModuleList(moduleInfo)
|
||||||
moduleList = modules
|
moduleList = modules
|
||||||
|
|
||||||
|
// 获取 KPM 版本信息
|
||||||
|
val kpmVersion = getKpmVersion()
|
||||||
|
Log.d("KsuCli", "KPM Version: $kpmVersion")
|
||||||
} finally {
|
} finally {
|
||||||
isRefreshing = false
|
isRefreshing = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getInstalledKernelPatches(): List<ModuleInfo> {
|
|
||||||
return try {
|
|
||||||
val output = printKpmModules()
|
|
||||||
parseModuleList(output)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
emptyList()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseModuleList(output: String): List<ModuleInfo> {
|
private fun parseModuleList(output: String): List<ModuleInfo> {
|
||||||
return output.split("\n").mapNotNull { line ->
|
return output.split("\n").mapNotNull { line ->
|
||||||
if (line.isBlank()) return@mapNotNull null
|
if (line.isBlank()) return@mapNotNull null
|
||||||
|
|||||||
@@ -180,7 +180,7 @@
|
|||||||
<string name="su_not_allowed">不允许授予 %s 超级用户权限</string>
|
<string name="su_not_allowed">不允许授予 %s 超级用户权限</string>
|
||||||
<string name="settings_disable_su">禁用 su 兼容性</string>
|
<string name="settings_disable_su">禁用 su 兼容性</string>
|
||||||
<string name="settings_disable_su_summary">临时禁止任何应用程序通过 su 命令获取 Root 权限(现有的 Root 进程不受影响)</string>
|
<string name="settings_disable_su_summary">临时禁止任何应用程序通过 su 命令获取 Root 权限(现有的 Root 进程不受影响)</string>
|
||||||
<string name="using_mksu_manager">你正在使用的是 MKSU 第三方管理器</string>
|
<string name="using_mksu_manager">你正在使用的是 SukiSU beta版管理器</string>
|
||||||
<string name="module_install_multiple_confirm">确定要安装选择的 %d 个模块吗?</string>
|
<string name="module_install_multiple_confirm">确定要安装选择的 %d 个模块吗?</string>
|
||||||
<string name="module_install_multiple_confirm_with_names">确定要安装以下 %1$d 个模块吗?\n\n%2$s</string>
|
<string name="module_install_multiple_confirm_with_names">确定要安装以下 %1$d 个模块吗?\n\n%2$s</string>
|
||||||
<string name="more_settings">更多设置</string>
|
<string name="more_settings">更多设置</string>
|
||||||
@@ -234,4 +234,9 @@
|
|||||||
<string name="kpm_install_confirm">确认安装吗?</string>
|
<string name="kpm_install_confirm">确认安装吗?</string>
|
||||||
<string name="kpm_install_success">安装kpm模块成功</string>
|
<string name="kpm_install_success">安装kpm模块成功</string>
|
||||||
<string name="kpm_install_failed">安装kpm模块失败</string>
|
<string name="kpm_install_failed">安装kpm模块失败</string>
|
||||||
|
<string name="home_kpm_version">KPM 版本: %s</string>
|
||||||
|
<string name="close_notice">关闭</string>
|
||||||
|
<string name="kernel_module_notice">以下内核模块功能由KernelPatch开发,经过修改后加入SukiSU Ultra的内核模块功能</string>
|
||||||
|
<string name="home_ContributionCard_kernelsu">SukiSU Ultra展望</string>
|
||||||
|
<string name="home_click_to_ContributionCard_kernelsu">SukiSU Ultra未来将会成为一个相对独立的KSU分支,但是依然感谢官方KernelSU和MKSU等做出的贡献</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name" translatable="false">SukiSU</string>
|
<string name="app_name" translatable="false">SukiSU Ultra</string>
|
||||||
<string name="home">Home</string>
|
<string name="home">Home</string>
|
||||||
<string name="home_not_installed">Not installed</string>
|
<string name="home_not_installed">Not installed</string>
|
||||||
<string name="home_click_to_install">Click to install</string>
|
<string name="home_click_to_install">Click to install</string>
|
||||||
@@ -181,7 +181,7 @@
|
|||||||
<string name="su_not_allowed">Granting superuser to %s is not allowed</string>
|
<string name="su_not_allowed">Granting superuser to %s is not allowed</string>
|
||||||
<string name="settings_disable_su">Disable su compatibility</string>
|
<string name="settings_disable_su">Disable su compatibility</string>
|
||||||
<string name="settings_disable_su_summary">Temporarily disable any applications from obtaining root privileges via the su command (existing root processes will not be affected).</string>
|
<string name="settings_disable_su_summary">Temporarily disable any applications from obtaining root privileges via the su command (existing root processes will not be affected).</string>
|
||||||
<string name="using_mksu_manager">You are using the MKSU third-party manager</string>
|
<string name="using_mksu_manager">You are using the SukiSU beta manager</string>
|
||||||
<string name="module_install_multiple_confirm">Are you sure you want to install the selected %d modules?</string>
|
<string name="module_install_multiple_confirm">Are you sure you want to install the selected %d modules?</string>
|
||||||
<string name="module_install_multiple_confirm_with_names">Sure you want to install the following %1$d modules? \n\n%2$s</string>
|
<string name="module_install_multiple_confirm_with_names">Sure you want to install the following %1$d modules? \n\n%2$s</string>
|
||||||
<string name="more_settings">more settings</string>
|
<string name="more_settings">more settings</string>
|
||||||
@@ -236,6 +236,11 @@
|
|||||||
<string name="kpm_install_confirm">Confirm installation?</string>
|
<string name="kpm_install_confirm">Confirm installation?</string>
|
||||||
<string name="kpm_install_success">Installation of kpm module successful</string>
|
<string name="kpm_install_success">Installation of kpm module successful</string>
|
||||||
<string name="kpm_install_failed">Installation of kpm module failed</string>
|
<string name="kpm_install_failed">Installation of kpm module failed</string>
|
||||||
<string name="kpm_args">kpm 参数</string>
|
<string name="kpm_args">kpm parameters</string>
|
||||||
<string name="kpm_control">kpm 控制</string>
|
<string name="kpm_control">kpm control</string>
|
||||||
|
<string name="home_kpm_version">KPM Version: %s</string>
|
||||||
|
<string name="close_notice">close</string>
|
||||||
|
<string name="kernel_module_notice">The following kernel module functions were developed by KernelPatch and modified to include the kernel module functions of SukiSU Ultra</string>
|
||||||
|
<string name="home_ContributionCard_kernelsu">SukiSU Ultra Look forward to</string>
|
||||||
|
<string name="home_click_to_ContributionCard_kernelsu">SukiSU Ultra will be a relatively independent branch of KSU in the future, but thanks to the official KernelSU and MKSU etc. for their contributions!</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -13,15 +13,38 @@
|
|||||||
#define CMD_KPM_CONTROL_MAX 7
|
#define CMD_KPM_CONTROL_MAX 7
|
||||||
|
|
||||||
// 控制代码
|
// 控制代码
|
||||||
#define SUKISU_KPM_LOAD 1
|
// prctl(xxx, 28, "PATH", "ARGS")
|
||||||
#define SUKISU_KPM_UNLOAD 2
|
// success return 0, error return -N
|
||||||
#define SUKISU_KPM_NUM 3
|
#define SUKISU_KPM_LOAD 28
|
||||||
#define SUKISU_KPM_LIST 4
|
|
||||||
#define SUKISU_KPM_INFO 5
|
|
||||||
#define SUKISU_KPM_CONTROL 6
|
|
||||||
#define SUKISU_KPM_PRINT 7
|
|
||||||
|
|
||||||
#define CONTROL_CODE(n) (CMD_KPM_CONTROL + n - 1)
|
// prctl(xxx, 29, "NAME")
|
||||||
|
// success return 0, error return -N
|
||||||
|
#define SUKISU_KPM_UNLOAD 29
|
||||||
|
|
||||||
|
// num = prctl(xxx, 30)
|
||||||
|
// error return -N
|
||||||
|
// success return +num or 0
|
||||||
|
#define SUKISU_KPM_NUM 30
|
||||||
|
|
||||||
|
// prctl(xxx, 31, Buffer, BufferSize)
|
||||||
|
// success return +out, error return -N
|
||||||
|
#define SUKISU_KPM_LIST 31
|
||||||
|
|
||||||
|
// prctl(xxx, 32, "NAME", Buffer[256])
|
||||||
|
// success return +out, error return -N
|
||||||
|
#define SUKISU_KPM_INFO 32
|
||||||
|
|
||||||
|
// prctl(xxx, 33, "NAME", "ARGS")
|
||||||
|
// success return KPM's result value
|
||||||
|
// error return -N
|
||||||
|
#define SUKISU_KPM_CONTROL 33
|
||||||
|
|
||||||
|
// prctl(xxx, 34, buffer, bufferSize)
|
||||||
|
// success return KPM's result value
|
||||||
|
// error return -N
|
||||||
|
#define SUKISU_KPM_VERSION 34
|
||||||
|
|
||||||
|
#define CONTROL_CODE(n) (n)
|
||||||
|
|
||||||
void print_usage(const char *prog) {
|
void print_usage(const char *prog) {
|
||||||
printf("Usage: %s <command> [args]\n", prog);
|
printf("Usage: %s <command> [args]\n", prog);
|
||||||
@@ -32,7 +55,7 @@ void print_usage(const char *prog) {
|
|||||||
printf(" list List loaded KPM modules\n");
|
printf(" list List loaded KPM modules\n");
|
||||||
printf(" info <name> Get info of a KPM module\n");
|
printf(" info <name> Get info of a KPM module\n");
|
||||||
printf(" control <name> <args> Send control command to a KPM module\n");
|
printf(" control <name> <args> Send control command to a KPM module\n");
|
||||||
printf(" print Print KPM module list to stdout\n");
|
printf(" version Print KPM Loader version\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
@@ -59,22 +82,25 @@ int main(int argc, char *argv[]) {
|
|||||||
// 获取模块列表
|
// 获取模块列表
|
||||||
char buffer[1024] = {0};
|
char buffer[1024] = {0};
|
||||||
ret = prctl(KSU_OPTIONS, CONTROL_CODE(SUKISU_KPM_LIST), buffer, sizeof(buffer), &out);
|
ret = prctl(KSU_OPTIONS, CONTROL_CODE(SUKISU_KPM_LIST), buffer, sizeof(buffer), &out);
|
||||||
if (ret >= 0) {
|
if (out >= 0) {
|
||||||
printf("%s", buffer);
|
printf("%s", buffer);
|
||||||
}
|
}
|
||||||
} else if (strcmp(argv[1], "info") == 0 && argc >= 3) {
|
} else if (strcmp(argv[1], "info") == 0 && argc >= 3) {
|
||||||
// 获取指定模块信息
|
// 获取指定模块信息
|
||||||
char buffer[256] = {0};
|
char buffer[256] = {0};
|
||||||
ret = prctl(KSU_OPTIONS, CONTROL_CODE(SUKISU_KPM_INFO), argv[2], buffer, &out);
|
ret = prctl(KSU_OPTIONS, CONTROL_CODE(SUKISU_KPM_INFO), argv[2], buffer, &out);
|
||||||
if (ret >= 0) {
|
if (out >= 0) {
|
||||||
printf("%s\n", buffer);
|
printf("%s\n", buffer);
|
||||||
}
|
}
|
||||||
} else if (strcmp(argv[1], "control") == 0 && argc >= 4) {
|
} else if (strcmp(argv[1], "control") == 0 && argc >= 4) {
|
||||||
// 控制 KPM 模块
|
// 控制 KPM 模块
|
||||||
ret = prctl(KSU_OPTIONS, CONTROL_CODE(SUKISU_KPM_CONTROL), argv[2], argv[3], &out);
|
ret = prctl(KSU_OPTIONS, CONTROL_CODE(SUKISU_KPM_CONTROL), argv[2], argv[3], &out);
|
||||||
} else if (strcmp(argv[1], "print") == 0) {
|
} else if (strcmp(argv[1], "version") == 0) {
|
||||||
// 在 stdout 输出 KPM 列表
|
char buffer[1024] = {0};
|
||||||
ret = prctl(KSU_OPTIONS, CONTROL_CODE(SUKISU_KPM_PRINT), NULL, NULL, &out);
|
ret = prctl(KSU_OPTIONS, CONTROL_CODE(SUKISU_KPM_VERSION), buffer, sizeof(buffer), &out);
|
||||||
|
if (out >= 0) {
|
||||||
|
printf("%s", buffer);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
print_usage(argv[0]);
|
print_usage(argv[0]);
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
Reference in New Issue
Block a user