Android原生测试随机磁盘I/O故障:File.mkdirs()创建目录失败求助
File.mkdirs() Failure on Rooted Android Devices I’ve run into similar flaky directory creation issues on rooted Android devices before, so let’s break down the possible causes and actionable fixes based on your observations:
Possible Root Causes
Root Permission Context Drift: Since your tests involve rooted devices, it’s common for test scripts or tools to switch to root UID temporarily. If the app process inherits this altered context (or if subsequent operations don’t switch back properly), it might lose the necessary permissions to write to its own
/data/user/0/com.company.app/filesdirectory. Even though the directory belongs to the app, a root context can sometimes interfere with standard app-level file system operations.SELinux Policy Conflicts: Many custom rooted ROMs modify SELinux policies or run in permissive mode inconsistently. Even with充足 storage, SELinux could block directory creation if the file context for the app’s data directory is misconfigured. This is especially likely if the issue only occurs on specific custom ROMs like those on Zenfone 2, S5/S7.
Race Conditions with Concurrent Processes: Your test suite might have multiple processes (test runner, app background services, or cleanup scripts) interacting with the app’s data directory simultaneously. For example, a cleanup step might delete the directory right before
mkdirs()is called, or another process could lock the parent directory temporarily, causing the creation to fail randomly.Custom ROM File System Restrictions: Some rooted ROMs implement extra protections for
/data/user/0directories—like read-only mounts, partition-level restrictions, or custom permission hooks—that can intermittently block directory creation, even when standard permissions seem correct.
Actionable Fixes & Debugging Steps
Add Detailed Error Logging
The first step is to get specific failure details instead of just knowingmkdirs()failed. Modify your code to capture the exact error and context:File appFilesDir = new File("/data/user/0/com.company.app/files"); if (!appFilesDir.exists()) { boolean isCreated = appFilesDir.mkdirs(); if (!isCreated) { Log.e("DirCreationError", "Failed to create: " + appFilesDir.getAbsolutePath()); Log.e("DirCreationError", "Parent dir exists? " + appFilesDir.getParentFile().exists()); Log.e("DirCreationError", "Parent dir permissions: " + Integer.toOctalString(appFilesDir.getParentFile().getPermissions())); Log.e("DirCreationError", "Current process UID: " + Process.myUid()); // Capture stack trace for context try { throw new IOException("Directory creation failed"); } catch (IOException e) { e.printStackTrace(); } } }This will tell you if it’s a permission issue, parent directory problem, or something else entirely.
Validate Root Context in Tests
If your test suite usessucommands, ensure you’re switching back to the app’s UID after root operations. For example, usesu -u <APP_UID>to run commands that need root without leaving the test environment in a root context. You can get the app’s UID withadb shell dumpsys package com.company.app | grep userId.Test with SELinux Disabled Temporarily
Runadb shell setenforce 0to switch SELinux to permissive mode, then run your tests. If the failures stop, the issue is SELinux-related. Fix it by setting the correct file context for the directory:adb shell chcon -R u:object_r:app_data_file:s0 /data/user/0/com.company.app/filesFor persistent fixes, you might need to add a custom SELinux policy module if the ROM doesn’t set the context correctly by default.
Mitigate Race Conditions
Add synchronization around directory creation in your test code, or ensure cleanup steps complete fully before attempting to create the directory. You can also add a short retry loop (with a delay) formkdirs()to handle transient locks:boolean created = false; int attempts = 3; while (!created && attempts > 0) { created = appFilesDir.mkdirs(); if (!created) { try { Thread.sleep(100); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } attempts--; } }Test on Stock Rooted ROMs
Try running your tests on a stock rooted ROM (e.g., Pixel device with official ROM and Magisk) to rule out custom ROM-specific issues. If the problem doesn’t occur there, you’ll need to adjust your test setup to account for the quirks of the affected custom ROMs.
内容的提问来源于stack exchange,提问作者Nikita Makarov

