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

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

[复制链接]

12

主题

12

帖子

98

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
98
跳转到指定楼层
楼主
发表于 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, 下载次数: 15)

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

本版积分规则

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