MuntashirAkon/AppManager · error · IOException
e.getMessage()
Error message
e.getMessage()
What it means
Xml.isBinaryXml() peeks the first 4 bytes of the stream to detect Android binary XML (AXML). When the stream is a FileInputStream it reads via Os.pread on the underlying file descriptor, and an ErrnoException from the kernel (bad fd, I/O error, permission) is rethrown as an IOException carrying the errno message. It signals that the file could not be read at the OS level, not that the XML is malformed.
Solutions
- Verify the file exists and is readable before opening: File.canRead() and length() >= 0.
- Ensure the FileInputStream is opened by the caller and not closed or reused after a previous parse; open a fresh stream per parse.
- If pread keeps failing, wrap the stream yourself in a BufferedInputStream so isBinaryXml takes the mark/reset path instead of the FD path.
- Catch IOException around resolvePullParser and surface the file path plus the errno message to diagnose the storage-level problem.
Example fix
// before
InputStream in = new FileInputStream(f);
XmlResourceParser p = Xml.resolvePullParser(in); // may throw IOException: pread errno
// after
File f = new File(path);
if (!f.canRead()) throw new IOException("Cannot read " + path);
InputStream in = new BufferedInputStream(new FileInputStream(f)); // avoids FD pread path
XmlResourceParser p = Xml.resolvePullParser(in); Defensive patterns
Strategy: try-catch
Validate before calling
if (!file.canRead() || file.length() < 4) throw new IOException("File missing or too small: " + file); Try / catch
try {
XmlResourceParser p = Xml.resolvePullParser(in);
} catch (IOException e) {
throw new IOException("Cannot read XML source: " + e.getMessage(), e);
} Prevention
- Open a fresh FileInputStream for each parse and never close it before parsing finishes.
- Check File.canRead()/length() before parsing.
- Wrap non-file streams in BufferedInputStream so the FD pread path is skipped.
When it happens
Trigger: Calling Xml.resolvePullParser() (which calls isBinaryXml) on a FileInputStream whose descriptor cannot be pread: closed FD, file deleted between open and read, EIO on a damaged filesystem, or a special file (pipe/device) that doesn't support positional reads.
Common situations: Parsing an APK entry extracted to a temp file that was deleted before parsing; opening a path obtained from another process whose FD was closed; storage corruption on SD card or /proc-style pseudo-files passed in directly.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- ADB command did not produce
- APK files backup is requested but no APK files have been…
- Backup failed for
- Backup failed for
- Content provider has crashed.
AI-assisted analysis of MuntashirAkon/AppManager@0152f468fc (2026-09-12).
Data as JSON: /api/errors/5d4445dd927d026c.
Report an issue: GitHub.
Appendix: source
Thrown at libcore/compat/src/main/java/io/github/muntashirakon/compat/xml/Xml.java:50
static {
boolean useAbx;
try {
useAbx = (boolean) Objects.requireNonNull(Class.forName("android.os.SystemProperties")
.getDeclaredMethod("getBoolean", String.class, boolean.class)
.invoke(null, "persist.sys.binary_xml", Build.VERSION.SDK_INT >= Build.VERSION_CODES.S));
} catch (Exception ignore) {
useAbx = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S;
}
ENABLE_BINARY_DEFAULT = useAbx;
}
public static boolean isBinaryXml(@NonNull InputStream in) throws IOException {
final byte[] magic = new byte[4];
if (in instanceof FileInputStream) {
try {
Os.pread(((FileInputStream) in).getFD(), magic, 0, magic.length, 0);
} catch (ErrnoException e) {
throw new IOException(e.getMessage(), e);
}
} else {
if (!in.markSupported()) {
in = new BufferedInputStream(in);
}
in.mark(8);
in.read(magic);
in.reset();
}
return Arrays.equals(magic, BinaryXmlSerializer.PROTOCOL_MAGIC_VERSION_0);
}
public static boolean isBinaryXml(@NonNull ByteBuffer buffer) {
final byte[] magic = new byte[4];
buffer.mark();
buffer.get(magic);
buffer.reset();
return Arrays.equals(magic, BinaryXmlSerializer.PROTOCOL_MAGIC_VERSION_0);View on GitHub (pinned to 0152f468fc)