查看: 582|回复: 0
打印 上一主题 下一主题

通过全志SystemMix可扩展接口为app提供root权限

[复制链接]

11

主题

11

帖子

81

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
81
跳转到指定楼层
楼主
发表于 2018-10-13 11:03:10 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
一、SystemMix接口说明

在android/frameworks/base/swextend/systemmix目录下,全志提供了一套用于访问底层高权限信息的接口,用户可以参照里面的做法来扩展SystemMix类的功能。

1. systemmix目录结构:


2. 该机制使用了Android上使用广泛的 客户端<--->服务端 机制去实现,调度流程如下:


3. 该SystemMix.java文件为用户提供了如下几个示例接口:
  1. /**
  2. ? ?? ???* mount device or other
  3. ? ?? ???*/
  4. ? ?? ???public static int Mount(String source, String mountPoint, String fs, int flags, String options){
  5. ? ?? ?? ?? ?? ? return nativeMount(source, mountPoint, fs, flags, options);? ?? ???
  6. ? ?? ???}
  7. ? ?? ???
  8. ? ?? ???/**
  9. ? ?? ???* umount device or other
  10. ? ?? ???*/
  11. ? ?? ???public static int Umount(String mountPoint){
  12. ? ?? ?? ?? ?? ? return nativeUmount(mountPoint);? ?? ???
  13. ? ?? ???}
  14. ? ?? ???
  15. ? ? /**
  16. ? ? * get a property's value
  17. ? ? */
  18. ? ?? ???public static String getProperty(String key){
  19. ? ?? ?? ?? ?return nativeGetProperty(key);
  20. ? ?? ???}

  21. ? ? /**
  22. ? ? * set a property's value
  23. ? ? */
  24. ? ?? ???public static void setProperty(String key, String value){
  25. ? ?? ?? ?? ?? ? if(key != null && value != null){
  26. ? ?? ?? ?? ?? ?? ?? ?? ?nativeSetProperty(key,value);
  27. ? ?? ?? ?? ?? ? }
  28. ? ?? ???}
  29. ? ?? ???
  30. ? ?? ???/**
  31. ? ?? ???* get command para in /proc/cmdline
  32. ? ?? ???*/
  33. ? ?? ???public static String getCmdPara(String name){
  34. ? ?? ?? ?? ?HashMap paraMap = mapPara();
  35. ? ?? ?? ?? ?return paraMap.get(name);? ?
  36. ? ?? ???}
  37. ? ?? ???
  38. ? ?? ???@SuppressWarnings("null")
  39. ? ?? ???private static HashMap mapPara(){
  40. ? ?? ?? ?? ?HashMap paraMap = new HashMap();
  41. ? ?? ?? ?? ?? ? String cmdline = getCmdLine();
  42. ? ?? ?? ?? ?? ? Log.d(TAG,"getCmdLine = " + cmdline);
  43. ? ?? ?? ?? ?? ? if(cmdline != null){
  44. ? ?? ?? ?? ?? ?? ?? ?? ?String[] list = cmdline.split(" ");
  45. ? ?? ?? ?? ?? ?? ?? ?? ?if(list != null){
  46. ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???for(int i = 0; i < list.length; i++){
  47. ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? String[] map = list[i].split("=");
  48. ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? if(map == null || map.length != 2){
  49. ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?continue;
  50. ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? }
  51. ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? paraMap.put(map[0], map[1]);
  52. ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???}
  53. ? ?? ?? ?? ?? ?? ?? ?? ?}
  54. ? ?? ?? ?? ?? ? }
  55. ? ?? ?? ?? ?? ? return paraMap;
  56. ? ?? ???}
  57. ? ?? ???
  58. ? ?? ???private static String getCmdLine(){
  59. ? ?? ?? ?? ?byte[] desData = new byte[256];
  60. ? ?? ?? ?? ?int ret = nativeGetFileData(desData, desData.length, "/proc/cmdline");
  61. ? ?? ?? ?? ?String str = null;
  62. ? ?? ?? ?? ?if(ret > 0){
  63. ? ?? ?? ?? ?? ? str = new String(desData);? ?
  64. ? ?? ?? ?? ?}
  65. ? ?? ?? ?? ?return str;
  66. ? ?? ???}
复制代码
用户在扩展该SystemMix接口的时候,可以参考getCmdPara()方法的调度流程,同时对java端、jni端,client端,server端做出相应的扩展。

二、扩展SystemMix接口,让app执行shell命令

在SystemMix中添加runShell操作接口,为app提供root权限来执行shell命令。

1. SystemMix接口扩展

我们按照java端(SystemMix.java)、jni端(com_softwinner_SystemMix.cpp),client端(ISystemMixService.h, ISystemMixService.cpp),server端(SystemMixService.h, SystemMixService.cpp)的顺序修改android/frameworks/base/swextend/systemmix目录下的文件,增加runShell操作接口。


关键代码如下:

1.1. SystemMix.java
  1. ? ?? ???private static native String nativeRunShell(String cmd);
  2. ? ?? ???
  3. ? ?? ???/**
  4. ? ?? ???* run shell command
  5. ? ?? ???*/? ?? ???
  6. ? ?? ???public static String runShell(String cmd){
  7. ? ?? ?? ?? ?? ? return nativeRunShell(cmd);? ?? ?? ?? ?? ?? ?
  8. ? ?? ???}
复制代码

1.2. com_softwinner_SystemMix.cpp
  1. static jstring runShell_native(JNIEnv *env, jobject clazz, jstring jcmd) {
  2. ? ?? ???jstring value = NULL;
  3. ? ?? ???if (systemmixService == NULL || jcmd == NULL) {
  4. ? ?? ?? ?? ?? ? throw_NullPointerException(env, "systemmix service has not start, or shell cmd is null!");
  5. ? ?? ???}
  6. ? ?? ???const char *cmd = env->GetStringUTFChars(jcmd, NULL);
  7. ? ?? ???char *cvalue = new char[MAX_BUFFER_SIZE];
  8. ? ?? ???if (cvalue == NULL) {
  9. ? ?? ?? ?? ?? ? env->ReleaseStringUTFChars(jcmd, cmd);
  10. ? ?? ?? ?? ?? ? throw_NullPointerException(env, "runshell_native() fail to allocate memory for value");
  11. ? ?? ???}

  12. ? ?? ???int ret = systemmixService->runShell(cmd, cvalue);
  13. ? ?? ???value = env->NewStringUTF(cvalue);
  14. ? ?? ???if (value == NULL) {
  15. ? ?? ?? ?? ?? ? ALOGE("Fail in creating java string with %s", cvalue);
  16. ? ?? ???}
  17. ? ?? ???delete[] cvalue;
  18. ? ?? ???env->ReleaseStringUTFChars(jcmd, cmd);
  19. ? ?? ???return value;
  20. }

  21. static JNINativeMethod method_table[] = {
  22. ? ? { "nativeInit", "()V", (void*)init_native},
  23. ? ? { "nativeSetProperty", "(Ljava/lang/String;Ljava/lang/String;)I", (void*)setProperty_native },
  24. ? ? { "nativeGetProperty", "(Ljava/lang/String;)Ljava/lang/String;", (void*)getProperty_native },
  25. ? ? { "nativeGetFileData", "([BILjava/lang/String;)I", (void*)getFileData_native },
  26. ? ? { "nativeMount", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;)I", (void*)mount_native },
  27. ? ? { "nativeUmount", "(Ljava/lang/String;)I", (void*)umount_native },
  28. ? ? { "nativeRunShell", "(Ljava/lang/String;)Ljava/lang/String;", (void*)runShell_native },
  29. };
复制代码

1.3. ISystemMixService.h
  1. // defind max buffer size for runshell
  2. #define MAX_BUFFER_SIZE 1024
复制代码

1.4. ISystemMixService.cpp
  1. enum {
  2. ? ?? ???GET_PROPERTY = IBinder::FIRST_CALL_TRANSACTION,
  3. ? ?? ???GET_FILEDATA,
  4. ? ?? ???MOUNT,
  5. ? ?? ???UMOUNT,
  6. ? ?? ???RUN_SHELL,
  7. ? ?? ???SET_PROPERTY = IBinder::LAST_CALL_TRANSACTION
  8. };

  9. ? ?? ???int runShell(const char *cmd, char *result) {
  10. ? ?? ?? ?? ?? ? if (DEBUG) {
  11. ? ?? ?? ?? ?? ?? ?? ?? ?ALOGV("ISystemMixService::runShell()??cmd = %s", cmd);
  12. ? ?? ?? ?? ?? ? }
  13. ? ?? ?? ?? ?? ? Parcel data, reply;
  14. ? ?? ?? ?? ?? ? data.writeInterfaceToken(ISystemMixService::getInterfaceDescriptor());
  15. ? ?? ?? ?? ?? ? data.writeCString(cmd);

  16. ? ?? ?? ?? ?? ? remote()->transact(RUN_SHELL, data, &reply);
  17. ? ?? ?? ?? ?? ? int ret = reply.readInt32();
  18. ? ?? ?? ?? ?? ? ALOGD("ISystemMixService::runShell() ret = %d", ret);
  19. ? ?? ?? ?? ?? ? const char* rpy = reply.readCString();
  20. ? ?? ?? ?? ?? ? int len = (int)strlen(rpy);
  21. ? ?? ?? ?? ?? ? if(MAX_BUFFER_SIZE > len){
  22. ? ?? ?? ?? ?? ?? ?? ?? ?strcpy(result, rpy);
  23. ? ?? ?? ?? ?? ? }else{
  24. ? ?? ?? ?? ?? ?? ?? ?? ?strncpy(result, rpy, MAX_BUFFER_SIZE);
  25. ? ?? ?? ?? ?? ?? ?? ?? ?result[MAX_BUFFER_SIZE - 1] = '\0';
  26. ? ?? ?? ?? ?? ? }
  27. ? ?? ?? ?? ?? ? //ALOGD("ISystemMixService::runShell() result=\n%s??rpy=\n%s", result, rpy);
  28. ? ?? ?? ?? ?? ? return ret;
  29. ? ?? ???}

  30. IMPLEMENT_META_INTERFACE(SystemMixService, "com.softwinner.ISystemMixService");

  31. status_t BnSystemMixService::onTransact(
  32. ? ?? ???uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){

  33. ? ?? ???switch(code){
  34. ? ?? ???case SET_PROPERTY:{
  35. ? ?? ?? ?? ?? ? CHECK_INTERFACE(ISystemMixService, data, reply);
  36. ? ?? ?? ?? ?? ? const char *key = data.readCString();
  37. ? ?? ?? ?? ?? ? const char *value = data.readCString();
  38. ? ?? ?? ?? ?? ? reply->writeInt32(setProperty(key, value));
  39. ? ?? ?? ?? ?? ? return NO_ERROR;
  40. ? ?? ???}break;
  41. ? ?? ???case GET_PROPERTY:{
  42. ? ?? ?? ?? ?? ? CHECK_INTERFACE(ISystemMixService, data, reply);
  43. ? ?? ?? ?? ?? ? const char *key = data.readCString();
  44. ? ?? ?? ?? ?? ? char *value = new char[PROPERTY_VALUE_MAX];
  45. ? ?? ?? ?? ?? ? ALOGD("BnSystemMixService::getProperty() key=%s", key);
  46. ? ?? ?? ?? ?? ? int ret = getProperty(key, value);
  47. ? ?? ?? ?? ?? ? ALOGD("BnSystemMixService::getProperty() value=%s, ret=%d", value, ret);
  48. ? ?? ?? ?? ?? ? reply->writeInt32(ret);
  49. ? ?? ?? ?? ?? ? if(ret > 0){
  50. ? ?? ?? ?? ?? ?? ?? ?? ?reply->writeCString(value);
  51. ? ?? ?? ?? ?? ? }
  52. ? ?? ?? ?? ?? ? delete[] value;
  53. ? ?? ?? ?? ?? ? return NO_ERROR;
  54. ? ?? ???}break;
  55. ? ?? ???case GET_FILEDATA:{
  56. ? ?? ?? ?? ?? ? CHECK_INTERFACE(ISystemMixService, data, reply);
  57. ? ?? ?? ?? ?? ? int count = data.readInt32();
  58. ? ?? ?? ?? ?? ? const char *filePath = data.readCString();
  59. ? ?? ?? ?? ?? ? int8_t *d = new int8_t[count];
  60. ? ?? ?? ?? ?? ? memset(d, 0, count * sizeof(int8_t));
  61. ? ?? ?? ?? ?? ? int ret = getFileData(d, count, filePath);
  62. ? ?? ?? ?? ?? ? ALOGD("BnSystemMixService::getFileData() read data is %s", d);
  63. ? ?? ?? ?? ?? ? reply->writeInt32(ret);
  64. ? ?? ?? ?? ?? ? reply->write(d, count * sizeof(int8_t));
  65. ? ?? ?? ?? ?? ? delete[] d;
  66. ? ?? ?? ?? ?? ? return NO_ERROR;
  67. ? ?? ???}break;
  68. ? ?? ???case MOUNT:{
  69. ? ?? ?? ?? ?? ? CHECK_INTERFACE(ISystemMixService, data, reply);
  70. ? ?? ?? ?? ?? ? const char *src = data.readCString();
  71. ? ?? ?? ?? ?? ? const char *mountpoint = data.readCString();
  72. ? ?? ?? ?? ?? ? const char *fs = data.readCString();
  73. ? ?? ?? ?? ?? ? unsigned int flag = data.readInt32();
  74. ? ?? ?? ?? ?? ? const char *options = data.readCString();
  75. ? ?? ?? ?? ?? ? reply->writeInt32(mountDev(src, mountpoint, fs, flag, options));
  76. ? ?? ?? ?? ?? ? return NO_ERROR;
  77. ? ?? ???}break;
  78. ? ?? ???case UMOUNT:{
  79. ? ?? ?? ?? ?? ? CHECK_INTERFACE(ISystemMixService, data, reply);
  80. ? ?? ?? ?? ?? ? const char *umountpoint = data.readCString();
  81. ? ?? ?? ?? ?? ? reply->writeInt32(umountDev(umountpoint));
  82. ? ?? ?? ?? ?? ? return NO_ERROR;
  83. ? ?? ???}break;
  84. ? ?? ???case RUN_SHELL: {
  85. ? ?? ?? ?? ?? ? CHECK_INTERFACE(ISystemMixService, data, reply);
  86. ? ?? ?? ?? ?? ? const char *cmd = data.readCString();
  87. ? ?? ?? ?? ?? ? char *result = new char[MAX_BUFFER_SIZE];
  88. ? ?? ?? ?? ?? ? memset(result, 0, MAX_BUFFER_SIZE);
  89. ? ?? ?? ?? ?? ? reply->writeInt32(runShell(cmd, result));
  90. ? ?? ?? ?? ?? ? //ALOGD("BnSystemMixService::runShell() result is %s", result);
  91. ? ?? ?? ?? ?? ? reply->writeCString(result);
  92. ? ?? ?? ?? ?? ? delete[] result;
  93. ? ?? ?? ?? ?? ? return NO_ERROR;
  94. ? ?? ???}break;
  95. ? ?? ???default:
  96. ? ?? ?? ?? ?? ? return BBinder::onTransact(code, data, reply, flags);
  97. ? ?? ???}
  98. }
复制代码

1.5. SystemMixService.h
  1. class SystemMixService:public BnSystemMixService{

  2. public:
  3. ? ?? ???static void instantiate();

  4. ? ?? ???virtual int getProperty(const char *key, char *value);
  5. ? ?? ???virtual int setProperty(const char *key, const char *value);
  6. ? ?? ???virtual int getFileData(int8_t *data, int count, const char *filePath);
  7. ? ?? ???virtual int mountDev(const char *src, const char *mountPoint, const char *fs,
  8. ? ?? ?? ?? ?? ? unsigned int flag, const char *options);
  9. ? ?? ???virtual int umountDev(const char *mountPoint);
  10. ? ?? ???virtual int runShell(const char *cmd, char *result);

  11. private:
  12. ? ?? ???SystemMixService();
  13. ? ?? ???virtual ~SystemMixService();
  14. };
复制代码

1.6. SystemMixService.cpp
  1. int SystemMixService::runShell(const char *cmd, char *result) {
  2. ? ?? ???if (DEBUG) {
  3. ? ?? ?? ?? ?? ? ALOGD("SystemMixService::runshell() cmd = %s", cmd);
  4. ? ?? ???}

  5. ? ?? ???char buffer[MAX_BUFFER_SIZE] = {0};
  6. ? ?? ???FILE *fp;
  7. ? ?? ???int ret = 0;

  8. ? ?? ???// write command to buffer, %s 2>&1
  9. ? ?? ???snprintf(buffer, sizeof(buffer), "%s\n", cmd);
  10. ? ?? ???fp = popen(buffer, "r");
  11. ? ?? ???if (fp != NULL){
  12. ? ?? ?? ?? ?? ? int remainder = MAX_BUFFER_SIZE;
  13. ? ?? ?? ?? ?? ? int len = 0;
  14. ? ?? ?? ?? ?? ? memset(buffer, 0, MAX_BUFFER_SIZE);
  15. ? ?? ?? ?? ?? ? while (fgets(buffer, MAX_BUFFER_SIZE, fp) != NULL){
  16. ? ?? ?? ?? ?? ?? ?? ?? ?len = strlen(buffer);
  17. ? ?? ?? ?? ?? ?? ?? ?? ?if (remainder > len){
  18. ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???strcat(result, buffer);
  19. ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???remainder -= len;
  20. ? ?? ?? ?? ?? ?? ?? ?? ?}else{
  21. ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???if (remainder > 1){
  22. ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? strncat(result, buffer, remainder - 1);
  23. ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? remainder = 0;
  24. ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? break;
  25. ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???}
  26. ? ?? ?? ?? ?? ?? ?? ?? ?}
  27. ? ?? ?? ?? ?? ?? ?? ?? ?//ALOGD("%s", buffer);
  28. ? ?? ?? ?? ?? ? }

  29. ? ?? ?? ?? ?? ? ret = pclose(fp);
  30. ? ?? ?? ?? ?? ? if (ret == -1){
  31. ? ?? ?? ?? ?? ?? ?? ?? ?ALOGD("SystemMixService::runshell() pclose() failed\n");
  32. ? ?? ?? ?? ?? ?? ?? ?? ?return -1;
  33. ? ?? ?? ?? ?? ? }

  34. ? ?? ?? ?? ?? ? if (WIFEXITED(ret)){
  35. ? ?? ?? ?? ?? ?? ?? ?? ?ALOGD("SystemMixService::runshell() subprocess exited, exit code: %d\n", WEXITSTATUS(ret));
  36. ? ?? ?? ?? ?? ?? ?? ?? ?if (0 != WEXITSTATUS(ret)){
  37. ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???ALOGD("SystemMixService::runshell() command failed: %s\n", strerror(WEXITSTATUS(ret)));
  38. ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???return WEXITSTATUS(ret);
  39. ? ?? ?? ?? ?? ?? ?? ?? ?}
  40. ? ?? ?? ?? ?? ? }else{
  41. ? ?? ?? ?? ?? ?? ?? ?? ?ALOGD("SystemMixService::runshell() subprocess exit failed\n");
  42. ? ?? ?? ?? ?? ?? ?? ?? ?return -1;
  43. ? ?? ?? ?? ?? ? }
  44. ? ?? ???}else{
  45. ? ?? ?? ?? ?? ? ALOGD("SystemMixService::runshell() popen() %s error\n", cmd);
  46. ? ?? ?? ?? ?? ? return -1;
  47. ? ?? ???}

  48. ? ?? ???//ALOGD("SystemMixService::runshell()??result = %s", result);
  49. ? ?? ???return 0;
  50. }
复制代码

2. 启动文件说明

SystemMix接口实现的关键在于系统启动的时候以root身份加载了systemmix服务,详见android/device/softwinner/wing-common/init.rc文件:

  1. # start system mix service
  2. service property /system/bin/systemmixservice
  3. ? ?? ???class main
  4. ? ?? ???user root
  5. ? ?? ???group root audio camera graphics inet net_bt net_bt_admin net_raw
  6. ? ?? ???ioprio rt 4
  7. ? ?? ???oneshot
复制代码

3. app项目中的使用方法

runShell操作接口扩展完毕后重新编译Android系统,会在android/out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/目录下生成classes.jar,classes-full-debug.jar(带调试信息)文件。


拷贝classes.jar库文件到你AndroidStudio工程的app\libs目录下(如果没有libs文件夹,请新建一个),然后点击Project Structure,


在弹出的界面上选择Dependencies选项卡,


点击右侧+按钮,在弹出的菜单中选择 2??Jar dependency,


弹出Select Path界面,选择libs目录下的classes.jar文件,点击OK,将库文件加入到工程中。



如果提示库文件冲突,导入失败,请打开classes.jar包,删除有冲突的目录。可以只保留META-INF和com目录,删除com下除softwinner以外的其它目录。

在你的代码中引用SystemMix:import com.softwinner.SystemMix,在需要执行shell命令的地方使用SystemMix.runShell("shell command")即可,shell command为Android所支持的shell命令。

提示:可以使用am start启动app,使用pm install静默安装apk。

代码示例(显示根目录下的文件结构):
  1. String cmd, str;
  2. cmd = "ls -l /";
  3. str = SystemMix.runShell(cmd);
  4. Log.d(TAG, String.format("Run shell result:\n %s", str));
复制代码

4. 项目源码

SWExtend.rar (28.75 MB, 下载次数: 12)

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表