Java层文件系统监控简单实现

Java层文件系统监控简单实现

在阅读android 10的aosp源码 framework/base/core/java/android/app/ActivityThread.java时候,看到了AndroidOs这个新东西,发现是一个IO回调,挺有意思

aosp/libcore回调机制

比如File.delete函数

    public boolean delete() {
        SecurityManager security = System.getSecurityManager();
        if (security != null) {
            security.checkDelete(path);
        }
        if (isInvalid()) {
            return false;
        }
        return fs.delete(this);
    }

最终会调用至fs.delete

看看fs是啥玩意

public class File
    implements Serializable, Comparable<File>
{

    /**
     * The FileSystem object representing the platform's local file system.
     */
    private static final FileSystem fs = DefaultFileSystem.getFileSystem();
调试后发现fs其实是UniFileSystem

在这里插入图片描述

源码中也解释了这一点

class DefaultFileSystem {

    /**
     * Return the FileSystem object for Unix-based platform.
     */
    public static FileSystem getFileSystem() {
        return new UnixFileSystem();
    }
}

继续追踪UnixFileSystem.delete

    public boolean delete(File f) {
        // Keep canonicalization caches in sync after file deletion
        // and renaming operations. Could be more clever than this
        // (i.e., only remove/update affected entries) but probably
        // not worth it since these entries expire after 30 seconds
        // anyway.
        cache.clear();
        javaHomePrefixCache.clear();
        // BEGIN Android-changed: Access files through common interface.
        try {
            Libcore.os.remove(f.getPath());
            return true;
        } catch (ErrnoException e) {
            return false;
        }
        // END Android-changed: Access files through common interface.
    }

调用了Libcore.os.remove(File)

看看Libcore.java中的os赋值

/** @hide */
public final class Libcore {
    private Libcore() { }

    /**
     * Direct access to syscalls. Code should strongly prefer using {@link #os}
     * unless it has a strong reason to bypass the helpful checks/guards that it
     * provides.
     */
    public static final Os rawOs = new Linux();

    /**
     * Access to syscalls with helpful checks/guards.
     * For read access only; the only supported way to update this field is via
     * {@link #compareAndSetOs}.
     */
    @UnsupportedAppUsage
    public static volatile Os os = new BlockGuardOs(rawOs);

    public static Os getOs() {
        return os;
    }

    /**
     * Updates {@link #os} if {@code os == expect}. The update is atomic with
     * respect to other invocations of this method.
     */
    public static boolean compareAndSetOs(Os expect, Os update) {
        Objects.requireNonNull(update);
        if (os != expect) {
            return false;
        }
        synchronized (Libcore.class) {
            boolean result = (os == expect);
            if (result) {
                os = update;
            }
            return result;
        }
    }
}

赋值有两个地方。

1.class静态初始化时:public static volatile Os os = new BlockGuardOs(rawOs);

2.调用compareAndSetOs函数,将第二个参数设置为期望的os回调。从os = update就可以看出。

安卓系统就是调用了compareAndSetOs函数,设置了os回调。

所以AndroidOs最终通过ActivityThread->AndroidOs进行IO监控.

ActivityThread.java调用compareAndSetOs函数

//ActivityThread.java    
    public static void main(String[] args) {
        ........
        ........
        AndroidOs.install();//调用了AndroidOs.install
      
        ........
        ........
    }


    private static class AndroidOs extends ForwardingOs {
        public static void install() {
            .....
            .....
            do {
                def = Os.getDefault();
                //调用了上述所说的关键os赋值
            } while (!Os.compareAndSetDefault(def, new AndroidOs(def)));
        }

        private AndroidOs(Os os) {
            super(os);
        }
      
        ......
         ......
        ......
          
    }

ActivityThread.main函数是通过zygote进程起来后调用的第一个函数。从函数名public static void main就可以看出来。感兴趣的可以分析一下,细节不讲了. 提示大家参考 ActivityThrad.java作为函数入口点的代码,可以参考ActivityManagerService->boolean startProcessLocked函数.

boolean startProcessLocked(... ) {
    ....
    ....
            // Start the process.  It will either succeed and return a result containing
            // the PID of the new process, or else throw a RuntimeException.
            final String entryPoint = "android.app.ActivityThread";
            
    ....
    ....
}

通过动态代理AndroidOs,调用Os.compareAndSetDefault进行替换

AndroidOs 继承了ForwardingOs, 该类在aosp/libcore源码下面

/**
 * Subclass this if you want to override some {@link Os} methods but otherwise delegate.
 *
 * @hide
 */
@libcore.api.CorePlatformApi
public class ForwardingOs implements Os {

}

该类实现了libcore.io.Os.java接口,

/** @hide */
@libcore.api.CorePlatformApi
public interface Os {
    ....
    ....
    public boolean access(String path, int mode) throws ErrnoException;
    public InetAddress[] android_getaddrinfo(String node, StructAddrinfo hints, int netId) throws GaiException;
    public void bind(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException;
    public void chmod(String path, int mode) throws ErrnoException;
    public void chown(String path, int uid, int gid) throws ErrnoException;

    public String readlink(String path) throws ErrnoException;
    public String realpath(String path) throws ErrnoException;
    public void remove(String path) throws ErrnoException;
}

我们要实现的IO监控刚好是Os接口声明的,所以可以直接代理AndroidOs, 实现对open access remove等函数监控

如何拿到AndroidOs实例,并将代理设置为本进程的IO回调呢?

同样参考ActivityThread.java,

    private static class AndroidOs extends ForwardingOs {
        public static void install() {
            .....
            .....
            do {
                def = Os.getDefault();
                //调用了上述所说的关键os赋值
            } while (!Os.compareAndSetDefault(def, new AndroidOs(def)));
        }

        private AndroidOs(Os os) {
            super(os);
        }
      
        ......
         ......
        ......
          
    }
1.反射调用Os.getDefault拿到AndroidOs实例,直接创建一个proxy
            defObj = LbcoreOsGetDef.invoke(null, new Object[0]);
            List<Class<?>> interfaces = getAllInterfaces(Class.forName("libcore.io.Linux"));
            if (interfaces != null && interfaces.size() > 0) {
                Class[] ifs = interfaces.toArray(new Class[interfaces.size()]);
                newObj = Proxy.newProxyInstance(defObj.getClass().getClassLoader(),
                        ifs, new ForwardingOsProxy(defObj));
            }
            
    private static class ForwardingOsProxy implements InvocationHandler {
        private Object mOrigin;
        ForwardingOsProxy(Object origin) {
            mOrigin = origin;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Log.d(TAG, String.format("ForwardingOsProxy call %s %s",
                    method.getName(), Arrays.toString(args)));
            return method.invoke(mOrigin, args);
        }
    }
           
2.反射调用compareAndSetDefault函数,设置代理os
        RefUtils.MethodRef<Boolean> compareAndSetDefaultMethod =
                new RefUtils.MethodRef<Boolean>("libcore.io.Os",
                true, "compareAndSetDefault",
                        new Class[]{OsClass, OsClass});
        do {
            Log.d(TAG, "installOs try...");
        } while (!compareAndSetDefaultMethod.invoke(null, new Object[]{defObj, newObj}));
        Log.d(TAG, "installOs success!");

然后写一个demo测试,点击按钮,删除/data/data/pkg/test.txt

        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                new File(getApplicationInfo().dataDir, "test.txt").delete();
            }
        });
看一下log:
04-24 16:38:55.179  5182  5182 D Hook: ForwardingOsProxy call getuid null
04-24 16:38:55.180  5182  5182 D Hook: ForwardingOsProxy call getuid null
04-24 16:38:55.182  5182  5182 D Hook: ForwardingOsProxy call remove [/data/user/0/com.example.demo/test.txt]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java简单文件系统可以通过使用Java文件操作API和数据结构来实现。下面是一个简单实现步骤: 1. 设计文件系统的目录结构,可以使用树形结构来表示。 2. 使用Java的File类创建文件和目录。 3. 通过维护目录树和文件路径,来实现文件的读取、写入、删除等操作。 4. 为文件系统添加权限控制和安全机制,防止非法操作和数据泄露。 5. 为文件系统添加文件版本控制功能,可以实现文件的版本管理和回滚操作。 下面是一个简单Java文件系统实现的示例代码: ``` import java.io.*; import java.util.*; public class SimpleFileSystem { private File root; public SimpleFileSystem(String rootPath) { this.root = new File(rootPath); } public void createDirectory(String path) { File dir = new File(root, path); if (!dir.exists()) { dir.mkdir(); } } public void createFile(String path, String content) throws IOException { File file = new File(root, path); if (!file.exists()) { file.createNewFile(); } FileWriter writer = new FileWriter(file); writer.write(content); writer.close(); } public String readFile(String path) throws IOException { File file = new File(root, path); if (!file.exists()) { return null; } StringBuilder sb = new StringBuilder(); BufferedReader reader = new BufferedReader(new FileReader(file)); String line; while ((line = reader.readLine()) != null) { sb.append(line); } reader.close(); return sb.toString(); } public void deleteFile(String path) { File file = new File(root, path); if (file.exists()) { file.delete(); } } public void deleteDirectory(String path) { File dir = new File(root, path); if (dir.exists()) { for (File file : dir.listFiles()) { if (file.isDirectory()) { deleteDirectory(file.getPath()); } else { file.delete(); } } dir.delete(); } } public void renameFile(String oldPath, String newPath) { File oldFile = new File(root, oldPath); File newFile = new File(root, newPath); if (oldFile.exists()) { oldFile.renameTo(newFile); } } public List<String> listFiles(String path) { List<String> files = new ArrayList<>(); File dir = new File(root, path); if (dir.exists()) { for (File file : dir.listFiles()) { files.add(file.getName()); } } return files; } public static void main(String[] args) throws IOException { SimpleFileSystem fs = new SimpleFileSystem("/path/to/root"); fs.createDirectory("dir1"); fs.createFile("dir1/file1.txt", "Hello, world!"); System.out.println(fs.readFile("dir1/file1.txt")); fs.renameFile("dir1/file1.txt", "dir1/new-file1.txt"); System.out.println(fs.listFiles("dir1")); fs.deleteFile("dir1/new-file1.txt"); fs.deleteDirectory("dir1"); } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值