systemmixservice
Служба интерфейса Allwinner SystemMix
Тип файла: служба
Комментарии
https://blog.csdn.net/kezunhb/article/details/80138236
Предоставление root-прав для приложений через расширяемый интерфейс Allwinner SystemMix
Описание интерфейса SystemMix
В каталоге android / frameworks / base / swextend / systemmix Allwinner предоставляет набор интерфейсов для доступа к низкоуровневой информации с высокими привилегиями.
Пользователи могут обратиться к методам внутри, чтобы расширить функции класса SystemMix.
1. Структура каталогов Systemmix:
2. Этот механизм использует широко распространенный Android.Клиент <---> СерверМеханизм реализован, и процесс планирования выглядит следующим образом:
3. Файл SystemMix.java предоставляет пользователям следующие образцы интерфейсов:
/**
* mount device or other
*/
public static int Mount(String source, String mountPoint, String fs, int flags, String options){
return nativeMount(source, mountPoint, fs, flags, options);
}
/**
* umount device or other
*/
public static int Umount(String mountPoint){
return nativeUmount(mountPoint);
}
/**
* get a property's value
*/
public static String getProperty(String key){
return nativeGetProperty(key);
}
/**
* set a property's value
*/
public static void setProperty(String key, String value){
if(key != null && value != null){
nativeSetProperty(key,value);
}
}
/**
* get command para in /proc/cmdline
*/
public static String getCmdPara(String name){
HashMap<String, String> paraMap = mapPara();
return paraMap.get(name);
}
@SuppressWarnings("null")
private static HashMap<String, String> mapPara(){
HashMap<String, String> paraMap = new HashMap<String, String>();
String cmdline = getCmdLine();
Log.d(TAG,"getCmdLine = " + cmdline);
if(cmdline != null){
String[] list = cmdline.split(" ");
if(list != null){
for(int i = 0; i < list.length; i++){
String[] map = list[i].split("=");
if(map == null || map.length != 2){
continue;
}
paraMap.put(map[0], map[1]);
}
}
}
return paraMap;
}
private static String getCmdLine(){
byte[] desData = new byte[256];
int ret = nativeGetFileData(desData, desData.length, "/proc/cmdline");
String str = null;
if(ret > 0){
str = new String(desData);
}
return str;
}
При расширении интерфейса SystemMix пользователи могут ссылаться на процесс планирования метода getCmdPara () и делать соответствующие расширения для java, jni, клиента и сервера.
2. Расширьте интерфейс SystemMix и позвольте приложению выполнять команды оболочки.
Добавьте рабочий интерфейс runShell в SystemMix, чтобы предоставить приложению права root для выполнения команд оболочки.
1. Расширение интерфейса SystemMix
Изменяем android / frameworks / base / в порядке: сторона java (SystemMix.java), сторона jni (com_softwinner_SystemMix.cpp), сторона клиента (ISystemMixService.h, ISystemMixService.cpp), сторона сервера (SystemMixService.h, SystemMixService.cpp) Добавьте рабочий интерфейс runShell к файлам в каталоге swextend / systemmix.
Код ключа следующий:
SystemMix.java
private static native String nativeRunShell(String cmd);
/**
* run shell command
*/
public static String runShell(String cmd){
return nativeRunShell(cmd);
}
com_softwinner_SystemMix.cpp
static jstring runShell_native(JNIEnv *env, jobject clazz, jstring jcmd) {
jstring value = NULL;
if (systemmixService == NULL || jcmd == NULL) {
throw_NullPointerException(env, "systemmix service has not start, or shell cmd is null!");
}
const char *cmd = env->GetStringUTFChars(jcmd, NULL);
char *cvalue = new char[MAX_BUFFER_SIZE];
if (cvalue == NULL) {
env->ReleaseStringUTFChars(jcmd, cmd);
throw_NullPointerException(env, "runshell_native() fail to allocate memory for value");
}
int ret = systemmixService->runShell(cmd, cvalue);
value = env->NewStringUTF(cvalue);
if (value == NULL) {
ALOGE("Fail in creating java string with %s", cvalue);
}
delete[] cvalue;
env->ReleaseStringUTFChars(jcmd, cmd);
return value;
}
static JNINativeMethod method_table[] = {
{ "nativeInit", "()V", (void*)init_native},
{ "nativeSetProperty", "(Ljava/lang/String;Ljava/lang/String;)I", (void*)setProperty_native },
{ "nativeGetProperty", "(Ljava/lang/String;)Ljava/lang/String;", (void*)getProperty_native },
{ "nativeGetFileData", "([BILjava/lang/String;)I", (void*)getFileData_native },
{ "nativeMount", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;)I", (void*)mount_native },
{ "nativeUmount", "(Ljava/lang/String;)I", (void*)umount_native },
{ "nativeRunShell", "(Ljava/lang/String;)Ljava/lang/String;", (void*)runShell_native },
};
ISystemMixService.h
// defind max buffer size for runshell
#define MAX_BUFFER_SIZE 1024
ISystemMixService.cpp
enum {
GET_PROPERTY = IBinder::FIRST_CALL_TRANSACTION,
GET_FILEDATA,
MOUNT,
UMOUNT,
RUN_SHELL,
SET_PROPERTY = IBinder::LAST_CALL_TRANSACTION
};
int runShell(const char *cmd, char *result) {
if (DEBUG) {
ALOGV("ISystemMixService::runShell() cmd = %s", cmd);
}
Parcel data, reply;
data.writeInterfaceToken(ISystemMixService::getInterfaceDescriptor());
data.writeCString(cmd);
remote()->transact(RUN_SHELL, data, &reply);
int ret = reply.readInt32();
ALOGD("ISystemMixService::runShell() ret = %d", ret);
const char* rpy = reply.readCString();
int len = (int)strlen(rpy);
if(MAX_BUFFER_SIZE > len){
strcpy(result, rpy);
}else{
strncpy(result, rpy, MAX_BUFFER_SIZE);
result[MAX_BUFFER_SIZE - 1] = '\0';
}
//ALOGD("ISystemMixService::runShell() result=\n%s rpy=\n%s", result, rpy);
return ret;
}
IMPLEMENT_META_INTERFACE(SystemMixService, "com.softwinner.ISystemMixService");
status_t BnSystemMixService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){
switch(code){
case SET_PROPERTY:{
CHECK_INTERFACE(ISystemMixService, data, reply);
const char *key = data.readCString();
const char *value = data.readCString();
reply->writeInt32(setProperty(key, value));
return NO_ERROR;
}break;
case GET_PROPERTY:{
CHECK_INTERFACE(ISystemMixService, data, reply);
const char *key = data.readCString();
char *value = new char[PROPERTY_VALUE_MAX];
ALOGD("BnSystemMixService::getProperty() key=%s", key);
int ret = getProperty(key, value);
ALOGD("BnSystemMixService::getProperty() value=%s, ret=%d", value, ret);
reply->writeInt32(ret);
if(ret > 0){
reply->writeCString(value);
}
delete[] value;
return NO_ERROR;
}break;
case GET_FILEDATA:{
CHECK_INTERFACE(ISystemMixService, data, reply);
int count = data.readInt32();
const char *filePath = data.readCString();
int8_t *d = new int8_t[count];
memset(d, 0, count * sizeof(int8_t));
int ret = getFileData(d, count, filePath);
ALOGD("BnSystemMixService::getFileData() read data is %s", d);
reply->writeInt32(ret);
reply->write(d, count * sizeof(int8_t));
delete[] d;
return NO_ERROR;
}break;
case MOUNT:{
CHECK_INTERFACE(ISystemMixService, data, reply);
const char *src = data.readCString();
const char *mountpoint = data.readCString();
const char *fs = data.readCString();
unsigned int flag = data.readInt32();
const char *options = data.readCString();
reply->writeInt32(mountDev(src, mountpoint, fs, flag, options));
return NO_ERROR;
}break;
case UMOUNT:{
CHECK_INTERFACE(ISystemMixService, data, reply);
const char *umountpoint = data.readCString();
reply->writeInt32(umountDev(umountpoint));
return NO_ERROR;
}break;
case RUN_SHELL: {
CHECK_INTERFACE(ISystemMixService, data, reply);
const char *cmd = data.readCString();
char *result = new char[MAX_BUFFER_SIZE];
memset(result, 0, MAX_BUFFER_SIZE);
reply->writeInt32(runShell(cmd, result));
//ALOGD("BnSystemMixService::runShell() result is %s", result);
reply->writeCString(result);
delete[] result;
return NO_ERROR;
}break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
}
SystemMixService.h
class SystemMixService:public BnSystemMixService{
public:
static void instantiate();
virtual int getProperty(const char *key, char *value);
virtual int setProperty(const char *key, const char *value);
virtual int getFileData(int8_t *data, int count, const char *filePath);
virtual int mountDev(const char *src, const char *mountPoint, const char *fs,
unsigned int flag, const char *options);
virtual int umountDev(const char *mountPoint);
virtual int runShell(const char *cmd, char *result);
private:
SystemMixService();
virtual ~SystemMixService();
};
SystemMixService.cpp
int SystemMixService::runShell(const char *cmd, char *result) {
if (DEBUG) {
ALOGD("SystemMixService::runshell() cmd = %s", cmd);
}
char buffer[MAX_BUFFER_SIZE] = {0};
FILE *fp;
int ret = 0;
// write command to buffer, %s 2>&1
snprintf(buffer, sizeof(buffer), "%s\n", cmd);
fp = popen(buffer, "r");
if (fp != NULL){
int remainder = MAX_BUFFER_SIZE;
int len = 0;
memset(buffer, 0, MAX_BUFFER_SIZE);
while (fgets(buffer, MAX_BUFFER_SIZE, fp) != NULL){
len = strlen(buffer);
if (remainder > len){
strcat(result, buffer);
remainder -= len;
}else{
if (remainder > 1){
strncat(result, buffer, remainder - 1);
remainder = 0;
break;
}
}
//ALOGD("%s", buffer);
}
ret = pclose(fp);
if (ret == -1){
ALOGD("SystemMixService::runshell() pclose() failed\n");
return -1;
}
if (WIFEXITED(ret)){
ALOGD("SystemMixService::runshell() subprocess exited, exit code: %d\n", WEXITSTATUS(ret));
if (0 != WEXITSTATUS(ret)){
ALOGD("SystemMixService::runshell() command failed: %s\n", strerror(WEXITSTATUS(ret)));
return WEXITSTATUS(ret);
}
}else{
ALOGD("SystemMixService::runshell() subprocess exit failed\n");
return -1;
}
}else{
ALOGD("SystemMixService::runshell() popen() %s error\n", cmd);
return -1;
}
//ALOGD("SystemMixService::runshell() result = %s", result);
return 0;
}
2. Описание файла запуска.
Ключом к реализации интерфейса SystemMix является то, что служба systemmix загружается как root при запуске системы.
Подробнее см. Файл android/device/softwinner wing-common/init.rc:
# start system mix service
service property /system/bin/systemmixservice
class main
user root
group root audio camera graphics inet net_bt net_bt_admin net_raw
ioprio rt 4
oneshot
3. Как использовать в проекте приложения
Перекомпилируйте систему Android после того, как интерфейс работы runShell будет расширен, и файлы classes.jar и classes-full-debug.jar (с отладочной информацией) будут созданы в каталоге android / out / target / common / obj / JAVA_LIBRARIES / framework_intermediates /.
Скопируйте файл библиотеки classes.jar в каталог app \ libs вашего проекта AndroidStudio (если нет папки libs, создайте новую), а затем щелкните Структура проекта,
Выберите вкладку Зависимости во всплывающем интерфейсе,
Нажмите кнопку + справа и выберите из всплывающего меню2 Jar dependency,
Появится интерфейс выбора пути, выберите файл classes.jar в каталоге libs и нажмите OK, чтобы добавить файл библиотеки в проект.
Если появится сообщение о конфликте файла библиотеки и сбое импорта, откройте пакет classes.jar и удалите конфликтующий каталог. Вы можете сохранить только каталоги META-INF и com и удалить другие каталоги, кроме softwinner, в com.
Обратитесь к SystemMix в своем коде: импортируйте com.softwinner.SystemMix и используйте SystemMix.runShell («команда оболочки») там, где вам нужно выполнять команды оболочки. Команда оболочки - это команда оболочки, поддерживаемая Android.
Совет: вы можете использовать am start для запуска приложения и pm install для автоматической установки apk.
Пример кода (покажите файловую структуру в корневом каталоге):
String cmd, str;
cmd = "ls -l /";
str = SystemMix.runShell(cmd);
Log.d(TAG, String.format("Run shell result:\n %s", str));