- Properly escape file names in FIFO I/O streams
- Fix typo in
SuFile.length()
- Escape filenames of the
File
argument inSuFile.renameTo(File)
- On Android 5.0 and higher (API 21+), both
SuFileInputStream.open(...)
andSuFileOutputStream.open(...)
return I/O streams backed by FIFO (named pipes). This provides 100% native file I/O stream performance and stability. - On Android 4.4 and lower,
SuFileInputStream.open(...)
uses the old shell command backedInputStream
as it was stress tested and proven reliable. - On Android 4.4 and lower,
SuFileOutputStream.open(...)
will write all data to a temporary file in the application's cache folder, and will only actually output the data to the target location when the stream is closed. Please refer to Javadocs for more detail. - If the internal copying of
SuFileOutputStream.open(...)
is unacceptable,SuFileOutputStream.openNoCopy(...)
can be used to force the old implementation (shell command backedOutputStream
) on Android 4.4 and lower. However, according to stress test results, this implementation is error prone and I strongly recommend against using it. - If your
minSdkVersion
is 21 or higher (which most apps now are), these I/O stream changes basically improve performance and reliability for free without any complexities mentioned above. - The
:busybox
module is updated with new busybox binaries (1.32.1). It also adds the logic to workaround older Samsung device kernel restrictions.
- Fix unaligned shell input (the bug did not affect
SuFileInputStream
) SuFile
now properly escapes special characters of file names in internal implementations
- Deprecated APIs in 3.0.x is removed
- Creating instances of
SuFileInputStream
andSuFileOutputStream
is deprecated. Please use the staticSuFileInputStream.open(...)
andSuFileOutputStream.open(...)
methods instead.
- Fix regression that could cause crashes on older Android versions when getting application context internally
- Add more nullability annotations for better Kotlin integration
New major release, introducing root service support!
3.0.1 is fully source compatible with 2.6.0, but please migrate the deprecated methods as soon as possible as these shim will be removed soon.
- New module
:service
is added: introduceRootService
for remote root IPC SuFileInputStream
now fully supportmark(int)
,reset()
, andskip(long)
CallbackList
now support passing in a customExecutor
in its constructor to configure which threadonAddElement()
to run on
CallbackList
no longer synchronizes its baseList
internally (if provided). It is the developer's responsibility if synchronization is required
Shell.Builder
is now used to constructShell
objects. Each shell instance creation now has its own configurationsShell.enableVerboseLogging
is now used to toggle verbose logging throughout the frameworkShell.setDefaultBuilder(Shell.Builder)
is now used to configure the global shell instance
Shell.FLAG_VERBOSE_LOGGING
: useShell.enableVerboseLogging
Shell.Config
: customizeShell.Builder
and set it inShell.setDefaultBuilder(Shell.Builder)
Shell.newInstance(...)
: createShell.Builder
and useShell.Builder.build(...)
- New APIs to allow users to customize which thread to dispatch when returning results via callbacks
Shell.getShell(Executor, GetShellCallback)
Shell.Job.submit(Executor, GetShellCallback)
Shell.su/sh(...).submit(...)
will no longer switch back to the main thread internally, reducing unnecessary thread hopping
- The bundled BusyBox now utilizes "Standalone Mode ASH", which forces all commands to use BusyBox applets.
For more info please read the Javadoc for
BusyBoxInstaller
. - The bundled BusyBox now supports full SELinux features
- All deprecated APIs in 2.5.2 are removed
- Be more conservative with synchronizing internally
- Use a more efficient SerialExecutorService implementation
- Allow users to set their own ExecutorService for libsu (
Shell.EXECUTOR
) - Some minor optimizations
- All deprecated methods/fields/classes will be removed in the next release
ShellUtils.pump(InputStream, OutputStream)
ShellUtils.noFlushPump(InputStream, OutputStream)
ShellUtils.checkSum(String, File, String)
Shell.FLAG_USE_MAGISK_BUSYBOX
Shell.Config.addInitializers(...)
Shell.Config.getFlags()
SuProcessFileInputStream
SuProcessFileOutputStream
SuFile.getParent()
no longer cause NPE when no parent exists- The
libsu:busybox
module now includes prebuilt busybox binaries as native libraries. This properly conforms with Play Store rules to ship executables along with APKs. All 4 ABIs (armeabi-v7a, arm64-v8a, x86, x86_64) are included; utilize app bundles for smaller app download sizes. - More nullability annotations for better Kotlin integration.
- Some minor internal implementation improvements
ShellUtils.genRandomAlphaNumString(int)
is removed
SuFile
will now follow symbolic links (as it always should)SuFile.length()
will no longer report block total size on block devices (as it shouldn't in the first place)SuFileInputStream
andSuFileOutputStream
now supports I/O on all file formats, including character files (e.g. files in/sys
and/proc
), and also outputs to block devices correctly
- Make
SuFile.isBlock()
,SuFile.isCharacter()
,SuFile.isSymlink()
public
- Tons internal optimizations to improve performance
- Rewrite shell backed I/O from scratch
- Added more detailed Javadoc for
SuFile
SuFile
is no longer a wrapper class aroundFile
. Calling the constructor directly will directly open a shell backedFile
instance. This change is due to the fact thatFile
wrapper class causes some issues in methods likeFile.renameTo(File)
.
- Introduce new helper methods:
SuFile.open(...)
: depending on whether the global shell has root access or not, these methods will return either a normalFile
instance orSuFile
. This is the same behavior as the previousSuFile
constructor (the only difference is thatSuFile
used to wrap around the instance).
- Update proguard rules to support R8 full mode
- Update gradle scripts to build proper Javadoc with links to Android reference
- Fix a possible NPE in
SuFile
- Publish aggregated Javadoc
- Strip out all deprecated APIs
Starting from 2.3.0, you shall stop using Shell.Container
, including ContainerApp
.
- Fix
Shell.Initializer
NPE on old API levels
Shell.Config.setContainer()
is deprecated. libsu will handle the global shell without any configurationsContainerApp
is deprecated. The class is now just a stockApplication
- When using high level APIs (
Shell.su
,Shell.sh
,Shell.rootAccess()
),NoShellException
is now silently suppressed to prevent unexpected crashes. Should no shell is possible to be created,Shell.su/sh
will immediately return aShell.Result
with no output and show failure;Shell.rootAccess()
will simply returnfalse
.
Starting from this release, libsu
is modularized into 3 parts: core
, io
, and busybox
.
If you only use the shell implementation, you just need com.github.topjohnwu.libsu:core
. com.github.topjohnwu.libsu:io
and com.github.topjohnwu.libsu:busybox
are optional: include the former to use the I/O wrapper classes, and the latter to bundle the prebuilt busybox binaries with your app. The old com.github.topjohnwu:libsu
can still be used, but all 3 components will be pulled in.
- Clean up potential garbage output before testing shell
- Prevent possible
Shell.waitAndClose(int, TimeUnit)
race conditions
- Add support for multiple
Shell.Initializer
s: new methodsvoid Shell.Config.setInitializers(...)
andvoid Shell.Config.addInitializers(...)
are added;void Shell.Config.setInitializer(Initializer.class)
is deprecated.
- Remove the class
BusyBox
. To install the prebuilt busybox, addcom.github.topjohnwu.libsu:busybox
as a dependency, and registerBusyBoxInstaller
as an initializer (Shell.Config.addInitializers(BusyBoxInstaller.class);
) - Introduce a new flag:
Shell.FLAG_USE_MAGISK_BUSYBOX
. With this flag set,/sbin/.magisk/busybox
will be prepended toPATH
, so the shell will use Magisk's internal busybox.
- Fix a bug that could cause
new SuFile(parent, name)
to fail
- When creating
SuFileInputStream
/SuFileOutputStream
/SuRandomAccessFile
with a character file, it will throwFileNotFoundException
instead of failing silently. Character file I/O is not possible with shells, useShell.su("cat <chr_file>").exec().getOut()
instead.
- Add
boolean Shell.waitAndClose(long, TimeUnit)
andvoid Shell.waitAndClose()
. You can now wait for all tasks to finish before closing the shell instance. - Add
Shell.Config.setTimeout(long)
. Use it to set the maximum time for waiting a new shell construction. The default value is 20 seconds.
Shell.isAlive()
method is updated to get process status directly via reflection rather than the traditionalProcess.exitValue()
exception handling. This optimization significantly reduces the overhead when switching between Shell tasks.
- The 1.x version APIs are completely removed
- Retrolambda is removed, you should start using AGP 3.0.0+ which comes with official Java 8 desugaring
- Return proper list in
Shell.Result.getErr()
- Calling
submit
inPendingJob
used to end up calling the overriddenexec
instead ofexec
inJobImpl
. Proxy through a private method inJobImpl
to prevent changed behavior ofJobImpl
subclasses. - Even though the parameters of
Shell.Job.add(...)
is labeled@NonNull
, it is still possible that developers still pass innull
and cause NPE. Checknull
before proceed any further. - Fix a bug that constructed shell instances weren't cached in the container when created using fallback methods (e.g. no root -> fallback to non-root shell). This would cause infinite loop when no root is available.
- Prevent
IllegalStateException
if the user provide a filter accepting.
or..
inSuFile.list()
family methods.