You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Studio中如何在已Root设备上绕过权限限制读写受保护目录的JSON文件

Android Studio中如何在已Root设备上绕过权限限制读写受保护目录的JSON文件

Great question! The core issue here is that standard FileWriter/FileReader operations run in your app's unprivileged user context—even if your app has been granted root access, these IO calls don't automatically escalate privileges. To write/read to restricted paths like /data/misc/com.crjase.systemuihook/properties.json on Android 15, you need to explicitly leverage root privileges via a su shell process.

Here's a step-by-step solution tailored to your existing code:

1. Create a Root File Utilities Class

First, build a helper class to handle file operations via root shell. This avoids repeating code and ensures safe handling of special characters in JSON content:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

public class RootFileUtils {
    private static final String TAG = "RootFileUtils";

    // Write content to a file using root privileges
    public static boolean writeFileWithRoot(String filePath, String content) {
        Process process = null;
        OutputStreamWriter outputStreamWriter = null;
        try {
            // Launch a su shell process
            process = Runtime.getRuntime().exec("su");
            outputStreamWriter = new OutputStreamWriter(process.getOutputStream());

            // Ensure parent directory exists (create with root if needed)
            String parentDir = filePath.substring(0, filePath.lastIndexOf('/'));
            outputStreamWriter.write("mkdir -p " + parentDir + "\n");

            // Write JSON content safely using cat (avoids issues with quotes/newlines)
            outputStreamWriter.write("cat > " + filePath + " <<EOF\n");
            outputStreamWriter.write(content);
            outputStreamWriter.write("\nEOF\n");
            outputStreamWriter.flush();

            // Exit the shell and verify success
            outputStreamWriter.write("exit\n");
            outputStreamWriter.flush();
            int exitCode = process.waitFor();
            return exitCode == 0;
        } catch (IOException | InterruptedException e) {
            android.util.Log.e(TAG, "Root write failed: " + e.getMessage());
            return false;
        } finally {
            // Clean up resources
            try {
                if (outputStreamWriter != null) outputStreamWriter.close();
                if (process != null) process.destroy();
            } catch (IOException e) {
                android.util.Log.e(TAG, "Resource cleanup error: " + e.getMessage());
            }
        }
    }

    // Read content from a file using root privileges
    public static String readFileWithRoot(String filePath) {
        Process process = null;
        BufferedReader bufferedReader = null;
        try {
            // Execute cat command via su shell
            process = Runtime.getRuntime().exec("su -c cat \"" + filePath + "\"");
            bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));

            // Read the output into a string
            StringBuilder contentBuilder = new StringBuilder();
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                contentBuilder.append(line).append("\n");
            }

            // Check if the command succeeded
            int exitCode = process.waitFor();
            if (exitCode != 0) {
                // Log error details from the shell's stderr
                BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
                StringBuilder errorMsg = new StringBuilder();
                String errorLine;
                while ((errorLine = errorReader.readLine()) != null) errorMsg.append(errorLine);
                android.util.Log.e(TAG, "Root read failed (exit code: " + exitCode + "): " + errorMsg);
                return null;
            }

            // Trim trailing newline
            if (contentBuilder.length() > 0) contentBuilder.setLength(contentBuilder.length() - 1);
            return contentBuilder.toString();
        } catch (IOException | InterruptedException e) {
            android.util.Log.e(TAG, "Root read failed: " + e.getMessage());
            return null;
        } finally {
            // Clean up resources
            try {
                if (bufferedReader != null) bufferedReader.close();
                if (process != null) process.destroy();
            } catch (IOException e) {
                android.util.Log.e(TAG, "Resource cleanup error: " + e.getMessage());
            }
        }
    }
}

2. Modify Your Existing Methods to Use Root Utilities

Update your saveProperties and loadProperties methods to rely on the root helper class instead of standard IO:

Updated Save Method

private static final String FILEPATH = "/data/misc/com.crjase.systemuihook/properties.json";
private final Gson gson = new Gson();
private static final String TAG = "PropertiesManager"; // Match your existing TAG

public void saveProperties(UIProperties properties) {
    // Serialize properties to a JSON string first
    String jsonContent = gson.toJson(properties);
    
    boolean writeSuccess = RootFileUtils.writeFileWithRoot(FILEPATH, jsonContent);
    if (writeSuccess) {
        android.util.Log.i(TAG, "UI Properties saved to " + FILEPATH);
    } else {
        android.util.Log.e(TAG, "Failed to save UI Properties to " + FILEPATH + " (root operation failed)");
    }
}

Updated Load Method

public UIProperties loadProperties() {
    String jsonContent = RootFileUtils.readFileWithRoot(FILEPATH);
    
    if (jsonContent == null) {
        android.util.Log.e(TAG, "Could not load UI properties from " + FILEPATH + " (root read failed)");
        return new UIProperties();
    }

    try {
        UIProperties properties = gson.fromJson(jsonContent, UIProperties.class);
        if (properties == null) {
            android.util.Log.e(TAG, "JSON file " + FILEPATH + " is empty or invalid. Returning new UIProperties.");
            return new UIProperties();
        }
        return properties;
    } catch (JsonSyntaxException e) {
        android.util.Log.e(TAG, "Invalid JSON syntax in " + FILEPATH);
        return new UIProperties();
    }
}

3. Critical Notes for Android 15 & Rooted Devices

  • Verify Root Access First: Before using these methods, add a check to confirm your app can obtain root privileges. For example, execute su -c id and verify the output contains uid=0(root).
  • SELinux Restrictions: Android 15 enforces strict SELinux policies even on rooted devices. If you still hit permission errors, you may need to temporarily disable SELinux (run su -c setenforce 0) or adjust the file's SELinux context (e.g., su -c chcon u:object_r:system_data_file:s0 " + FILEPATH). Note that disabling SELinux is not recommended for long-term use.
  • File Permissions: After writing the file, if other system processes (like SystemUI) need to read it, adjust permissions with su -c chmod 644 " + FILEPATH (add this line to the writeFileWithRoot method after the cat command).
  • Special Character Safety: Using cat <<EOF instead of echo ensures your JSON content (which may include quotes, newlines, or special symbols) is written correctly without corruption.

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 03:10:53