Android开发:针对系统文件目录 /system目录下进行的文件操作

Android的/system目录是安卓的系统目录,里面存放的都是系统文件,主要有以下文件夹:

更加具体的文件结构,有兴趣的读者可以安装一个RE文件管理器去查看,在这里我们只关注/system目录下文件的操作问题。 

  • /system/app/ : 一些系统APP
  • /system/bin/ : Linux自带组件
  • /system/build.prop :系统的属性信息
  • /system/fonts/ : 存放目录root后下载的TTF格式字体替换原字体,达到修改系统字体效果
  • /system/framework/ : 系统核心文件、框架层
  • /system/lib : 存放几乎所有共享库的.so文件
  • /system/media :系统提示音、系统铃声
  • /system/media/audio : Android默认铃声(alarms:闹铃提示;notification:短信或提示音;ringtones:来电铃声;ui:界面音效)
  • /system/usr/ :用户配置文件,包括键盘布局、共享、时区文件等

有时候我们在做一些开发工作的时候,业务上需要修改/system目录下的相关文件,于是当你兴致勃勃着手去修改文件时,结果发现困难重重,主要的困难是我们发现/system目录下的文件 只允许只读权限,不可读写,也就意味着我们根本无法下手去修改,当然重要的系统文件怎么可能允许外部随意更改!

到底有什么办法可以修改/system目录下的文件呢?答案只有一个,修改/system目录的文件操作权限,把只读改成可读写。我们很快就想到使用 adb命令,用root身份登录,赋予/system 777权限,修改它的文件操作权限改为可读写,这样我们就可以愉快的进行文件操作了。例如下面的adb命令:

1、  adb shell ,进入shell界面

2、mount -o remount rw /system/

3、chmod 777 /system

关于adb 修改/system文件权限,网上的例子有很多,这里不再进行细致的讲解。

当然,我们今天的主题绝不会是将这种泛滥的东西,下面开始具体的问题探讨:

我们该如何在代码中,去操作/system目录下的文件?

问题一:该在哪里执行adb命令来修改文件操作权限?

就像是之前提到过的RE文件管理器,给予它root权限,你会发现它可以随意的修改系统目录下的文件,包括创建,添加,删除,移动等等。用户在使用RE文件管理器的时候,只是给它了Root权限,并不是说又亲自去执行了adb命令修改掉了/system的文件操作权限,再者也不可能,我们开发人员可以很轻易的执行adb命令,但是一个普通用户来说这是不现实的,所以最终执行adb命令的还是在代码中。 

问题二:

修改过文件操作权限之后,你认为终于可以操作系统文件了吧,错,还是不能。为什么?

因为Android整个开发处于应用层,在这一层根本触及不到系统底层的东西,应用层只能操作 /data/data/应用安装包 下的文件和 sd卡文件, 其它文件没有权限,所以在应用层你还是无法去修改系统底层文件,不信你可以去尝试一下,你会发现尽管你已经通过adb命令修改了/system目录的文件操作权限,但是还是会报IO错误:open failed: EROFS (Read-only file syste。

这下就很尴尬了!明明权限都已经修改了还是行不通,这就是因为你所处的开发层面是应用层,根本无法触及到系统底层的文件。那怎么办?

首先我们要明确的是,在应用层一定是可以对/system系统底层文件做出操作的,要不然RE文件管理器是怎么实现的?既然RE文件管理器可以实现对底层文件的操作,那么一定有办法可以,只不过不是寻常做法,只能采用取巧的特殊方式。

解决思路:

既然应用层没有权限去操作系统底层文件,那么我们就需要找到一位可以操作系统底层文件的家伙,然后在应用层发布相应的命令去指挥它修改相应的系统底层文件即可,那么这个家伙是谁呢?很快,我们就锁定了关键人物:adb命令。

应用层在它可以触及的文件操作权限范围内,操作一个文件;操作完成后,我们命令adb把操作完成的文件给“搬”到系统底层文件中,这样达到在应用层修改系统底层文件的目的!

下面就开始让我们按照这个思路进行尝试吧:

尝试:在/system目录内新建一个文件,文件名为“test.txt”,文件内容:testing,,,,,

博主的代码:

//创建文件
File file=new File(getExternalCacheDir(),"test.txt");
         
       try { 
            //判断文件是否存在
            if (file.exists()){
                file.delete();
            }
            file.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            //开始向文件中写内容
            FileWriter fileWriter=new FileWriter(file);
            fileWriter.write("testing,,,,");
            fileWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

这一段代码相信大家都不陌生,很普通的文件输入输出流操作。

首先声明了文件的储存路径和文件名,然后创建文件,接着就开始向文件中写入内容。

这里有几点需要大家注意,其中这个文件保存的路径为应用关联缓存目录,调用getExternalCacheDir()方法获得该目录,是SD卡中专门用于存放当前应用缓存数据的位置。

下面我们就需要一个具体的adb命令的翻译者和执行者。我们平常在做开发的时候,执行adb命令都是在命令提示符中,而在这里,我们需要在代码中执行adb命令,毕竟普通用户他们没有办法去执行adb命令。

自定义的adb命令执行者代码如下:

package com.example.xposedtest;

import android.util.Log;

import java.io.DataOutputStream;

/**
 * Created by 王将 on 2018/7/23.
 */

public class RootCmd {
    
    //翻译并执行相应的adb命令
    public static boolean exusecmd(String command) {
        Process process = null;
        DataOutputStream os = null;
        try {
            process = Runtime.getRuntime().exec("su");
            os = new DataOutputStream(process.getOutputStream());
            os.writeBytes(command + "\n");
            os.writeBytes("exit\n");
            os.flush();
            Log.e("updateFile", "======000==writeSuccess======");
            process.waitFor();
        } catch (Exception e) {
            Log.e("updateFile", "======111=writeError======" + e.toString());
            return false;
        } finally {
            try {
                if (os != null) {
                    os.close();
                }
                if (process != null) {
                    process.destroy();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return true;
    }

    //移动文件
    public static void moveFileToSystem(String filePath, String sysFilePath) {
        exusecmd("mount -o rw,remount /system");
        exusecmd("chmod 777 /system");
        exusecmd("cp  " + filePath + " " + sysFilePath);
    }

  
}

代码中exusecmd()负责去翻译并执行传进来的adb命令,这里的adb命令以String字符串的形式进行解析执行。关于具体在程序代码中执行adb命令的相关知识,这里不再做细致的讲解,有兴趣的读者可以自行搜索相关的资料文档。

我们具体看下面的moveFileToSystem()方法。首先有两个String型参数,分别是filePath和sysFilePath,其中filePath指的是你想要操作的文件的所处路径,sysFilePath指的是你想要操作的系统文件路径。往下看它的执行逻辑,是不是很熟悉?没错,这里先执行了两句adb命令,第一句是修改/system为可读写权限,第二句是赋予/system 777权限,然后执行的文件拷贝命令,把处于应用层的文件拷贝到系统底层文件路径。

然后我们在主活动中执行moveFileToSystem()方法:

 RootCmd.moveFileToSystem(file.getAbsolutePath(),"/system");

把我们文件的路径和系统文件路径传进去,就这样我们成功的在/system目录下新建了一个文件!

去看一下运行效果,打开RE文件管理器:

Android开发:针对系统文件目录 /system目录下进行的文件操作_第1张图片

 成功创建!

我们接下来继续下面一个问题:既然能够创建文件,同样也需要可以删除文件,怎么删除系统文件呢?

同理,我们还是使用adb命令去执行删除。

代码如下:

 public static void deleteFileToSystem(String filePath){
        exusecmd("mount -o rw,remount /system");
        exusecmd("rm "+filePath);
    }

注意:这里的deleteFileToSystem静态方法,同样是位于我们自定义的RootCmd操作类中。

我们从代码可以看到:我们传递了一个String类型的参数,它代表的是你想删除的文件的路径,方法体中,同样首先执行了一条修改/system文件操作权限的命令,改为可读写,然后下面就是一条文件删除命令,删除的文件路径为我们传递进来的参数。

接着我们在主活动中调用这个方法,代码如下:

RootCmd.deleteFileToSystem("/system/test.txt");

这里我们删除的是刚才我们创建的测试文件:test.txt。

程序运行完成后,我们打开RE文件管理器去看一下:

Android开发:针对系统文件目录 /system目录下进行的文件操作_第2张图片

 test.txt文件被成功删除!

这里我们关于系统文件/system目录的文件操作已经讲解完毕,其中关键的有两点:

1.应用层负责创建文件,2.adb命令负责文件的操作。

接下来你或许还有一个问题,如果是修改系统文件/system目录下某个文件的内容,该怎么去修改??

例如,/system目录下的build.prop文件,这个文件里面存放的都是系统设备的相关信息,比如设备序列号,手机型号等等。下面业务要求我们去修改build.prop文件里的相关信息,具体修改思路如下:

首先在应用层我们创建一个文件名也是build.prop的文件,文件里面的内容和/system目录下的build.prop文件内容大致相同,只是其中我们需要修改的地方信息不同。例如,这里我们修改build.prop文件中手机型号信息,原本信息为“huawei”,在我们应用层创建的build.prop文件中,手机型号信息改为“oppo R11”。

下面使用adb命令操作,首先删除/system目录下的build.prop文件,接着把我们创建的新的build.prop文件复制到/system目录下,替换原先build.prop文件,以此达到修改build.prop文件的目的。

这里不再进行演示,具体操作请读者自己尝试。

还有相应的文件移动,文件复制等等一系列的操作 大家可以自行探索,主要是adb命令的使用。

本文到此结束,如引用本文,请标明出处。

你可能感兴趣的:(Android开发:针对系统文件目录 /system目录下进行的文件操作)