MuntashirAkon/AppManager · error · ErrnoException

ENOSYS

ENOSYS

Error message

splice

What it means

FileUtils.splice() invokes Os.splice() reflectively (required for API 28+). If the reflective lookup of the method or its invocation fails with ReflectiveOperationException, the method throws ErrnoException("splice", ENOSYS) — 'function not implemented'. This translates a reflection/environment problem into an errno so callers can fall back to a non-splice path.

Source

Thrown at libcore/io/src/main/java/io/github/muntashirakon/io/FileUtils.java:154

    }

    @RequiresApi(api = 28)
    static long splice(
            FileDescriptor fdIn, Int64Ref offIn,
            FileDescriptor fdOut, Int64Ref offOut,
            long len, int flags) throws ErrnoException {
        try {
            if (splice == null) {
                splice = Os.class.getMethod("splice",
                        FileDescriptor.class, Int64Ref.class,
                        FileDescriptor.class, Int64Ref.class,
                        long.class, int.class);
            }
            return (long) splice.invoke(null, fdIn, offIn, fdOut, offOut, len, flags);
        } catch (InvocationTargetException e) {
            throw (ErrnoException) e.getTargetException();
        } catch (ReflectiveOperationException e) {
            throw new ErrnoException("splice", ENOSYS);
        }
    }

    @SuppressWarnings("deprecation")
    @SuppressLint("NewApi")
    static long sendfile(
            FileDescriptor outFd, FileDescriptor inFd,
            MutableLong inOffset, long byteCount) throws ErrnoException {
        if (Build.VERSION.SDK_INT >= 28) {
            Int64Ref off = inOffset == null ? null : new Int64Ref(inOffset.value);
            long result = Os.sendfile(outFd, inFd, off, byteCount);
            if (off != null)
                inOffset.value = off.value;
            return result;
        } else {
            try {
                if (os == null) {
                    os = Class.forName("libcore.io.Libcore").getField("os").get(null);

View on GitHub (pinned to 0152f468fc)

Solutions

  1. Update the OS/ROM or test on a device with API >= 28 and an unmodified framework
  2. Catch ErrnoException with errno == ENOSYS and fall back to the read/write loop path (the library's FORCE_NO_SPLICE fallback pattern)
  3. Set the library's no-splice option (e.g. FORCE_NO_SPLICE) to bypass splice entirely

Example fix

// before
long n = FileUtils.splice(fdIn, offIn, fdOut, offOut, len, 0);
// after
try {
    n = FileUtils.splice(fdIn, offIn, fdOut, offOut, len, 0);
} catch (ErrnoException e) {
    if (e.errno == OsConstants.ENOSYS) {
        n = fallbackCopy(fdIn, offIn, fdOut, offOut, len); // manual read/write loop
    } else throw e;
}
Defensive patterns

Strategy: fallback

Validate before calling

if (Build.VERSION.SDK_INT < 28) { /* skip splice path */ }

Try / catch

try { long n = FileUtils.splice(fdIn, offIn, fdOut, offOut, len, 0); } catch (ErrnoException e) { if (e.errno == OsConstants.ENOSYS) { /* manual copy fallback */ } else throw e; }

Prevention

When it happens

Trigger: Calling splice-based I/O (e.g. OpenFile.pread/read on API >= 28 paths that use FileUtils.splice) on a device/VM where Os.splice cannot be resolved reflectively or the invocation fails reflectively; custom ROMs or stripped frameworks missing the method; InvocationTargetException thrown from splice itself is rethrown as-is, so ENOSYS only comes from reflection failures.

Common situations: Running on emulators or modified Android builds lacking Os.splice; proguard/R8 renaming interfering with reflection when subclassing; testing splice paths on API < 28 without guards.

Understand the failure class

Background: "unsupported platform" / "not supported on this platform" errors: what they mean and how to fix them — this error's family across 47 libraries.

Related errors


AI-assisted analysis of MuntashirAkon/AppManager@0152f468fc (2026-09-12). Data as JSON: /api/errors/cca3466312d820c8. Report an issue: GitHub.