(5.3.0 release notes are merged into 6.0.0)
- [core] New API
Shell.Builder.setCommands(String...) - [core] New API
Shell.submitTask(Task) - [core] New API
Shell.Task.shellDied() - [core] New internal task scheduling implementation
- [core] Remove deprecated
Shell.sh/sumethods - [core] Deprecate
FLAG_REDIRECT_STDERR - [service] Fix support on pre-6.0 devices
- [service] Fix crashes on some LG devices
- Usage of
Shell.sh/sumethods should be directly replaced withShell.cmd. If you only want to run certain jobs when the shell is root, manually check withShell.isRoot()before creating the job. - The behavior of
FLAG_REDIRECT_STDERRchanged and its usage is deprecated. SettingFLAG_REDIRECT_STDERRinShell.Builder.setFlags(int)will internally enableShell.enableLegacyStderrRedirectionas a best-effort backwards compatibility emulation to support the old behavior. Please note that the newShell.enableLegacyStderrRedirectionflag controls the behavior of the entire program, NOT on a per-shell basis as it used to be. If you want to redirect STDERR to STDOUT, please switch over to setting the same output list for both STDOUT and STDERR withShell.Job.to(List, List), and do not rely onFLAG_REDIRECT_STDERRorShell.enableLegacyStderrRedirection.
- [service] Disable
dex2oatwhen loading trampoline JAR
- [service] Fix issue on OnePlus devices when using
Contextinternally.
- [core] Shell status code
Shell.ROOT_MOUNT_MASTERis no longer returned as there is no way to reliably determine this information.
- [core] New API
Shell.Job.enqueue()which returnsFuture<Shell.Result>in case you need to retrive asynchronous results without using callbacks - [service] Workaround more broken LG system framework
- [service] Properly support multiuser/work profile
- [nio] Optimize internal implementation
- [service] Fix incompatibility with old Linux kernels
- [service] Workaround broken framework implementations in some LG ROMs
- [core] Fix
ShellUtils.escapedString(String) - [service] Prevent root process leaks when client process crashed before establishing connection
- [service] Resolve
/proc/self/exeto possibly fix some old Samsung kernel restrictions
- [nio] Update the remote file system's I/O stream implementation with stream specific optimizations. The throughput is improved 2.5x.
- [nio] Properly annotate nullability of
ExtendedFile'snewInputStream()/newOutputStream(...) - The
busyboxmodule is removed. Pin thebusyboxmodule to version5.0.0if you cannot remove its usage immediately
Check the updated Javadoc and the example app for details on how to use the remote file system in the new nio module.
- Introduce a new module:
nio- Includes file system implementations for local and remote processes
- New
FileSystemManagerclass to access either local or remote file system implementations - New
ExtendedFileclass to extend functionality of the old JavaFileAPI
- [core] New API
Shell.isAppGrantedRoot()returns a nullableBoolean:trueif a root shell has been createdfalseif it has been determined that root access is impossible to getnullif the library has not, or could not determine the current root grant state. Future invocations of this method may return a non-null value if the library gained more information during shell creation.
- [core] New API
Shell.Builder.setContext(context): allow the developer to explicitly provide aContextobject - [io]
SuFileis updated to also extendExtendedFile, which adds some new features and APIs
- Version
5.0.0will be the final release of thebusyboxmodule. If you cannot remove the usage of the module, you can pin thebusyboxmodule to version5.0.0, as it is updated to be fully self contained, making it guaranteed to work with futurelibsuversions. - Usage of
SuFile/SuFileOutputStream/SuFileInputStream/SuRandomAccessFileis discouraged. Although these APIs will remain for the foreseeable future, please migrate to useRootService+ theniomodule for all root I/O operations. Shell.rootAccess()is deprecated. Please switch to use the more accurateShell.isAppGrantedRoot()API
- [core] Ensure exactly one main shell will be created
- [core] Ensure the asynchronous
Shell.getShell(callback)never blocks - [service] Reduce one IPC back and forth during the initial binding
- [core] Fix possible incorrect root status reporting
- [core] Workaround root shell mount namespace issues on older Magisk versions
- [service] Prevent a possible race condition
- [service] Add multiuser support
- [service] Add new APIs returning
Shell.Taskto allow launching root processes with yourShellinstance of choice. - [core] Prevent a possible deadlock
- [core] Support creating
Shellinstances with customProcess - [io] Support setting a
Shellinstance toSuFile. This shell will also be used if theSuFileis passed to openSuFileInputStreamandSuFileOutputStreamstreams.
- [service] The way how "Daemon Mode" services work has changed. This change is required to work with multiuser. Please check the Javadoc of
RootServicefor instructions on how to launch daemon services and more information about its behavior. - [core]
Shell.rootAccess()no longer requires the main shell, so it is now non-blocking. Replaced with a best-effort heuristic that guarantees no false negatives. Please check its Javadoc for more details.
- [core] The core module now requires at least API level 19
- [io] The I/O module now requires at least API level 21
- [io]
SuFileOutputStream.openNoCopy(...)APIs removed as those are irrelevant on API 21+ - [io]
SuFileInputStreamandSuFileOutputStreamconstructors removed. Please use the correspondingopen(...)static methods. - [service]
RootService.attachBaseContext(Context)is madefinalto prevent breakage.onAttach(Context)is provided as an alternative.
- [core] I have received too many feedback that the
Shell.su/sh(...)APIs are extremely confusing. Those APIs are now all deprecated, replaced withShell.cmd(...).Shell.cmd(...)is 100% the same as the originalShell.sh(...); the API is just renamed to a less misleading name. - [service]
RootService.createBindTask(...). Replaced withRootService.bindOrTask(...). Will be removed in the next release.
- [service] Add new API
RootService.createBindTask(...). Check Javadoc for more details.
- [service] All
RootServices of a single app now run in the same root process. Each root service no longer runs in its own separate process. - [service] The
BroadcastReceiverused internally for receiving theIBinderreference now uses random UUID as action, effectively making it private and unique per-session. This prevents malicious external apps from injecting its own services into your app. - [busybox] Update the prebuilt BusyBox executable to 1.34.1
- Properly escape file names in FIFO I/O streams
- Fix typo in
SuFile.length() - Escape filenames of the
Fileargument 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 backedInputStreamas 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
minSdkVersionis 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
:busyboxmodule 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) SuFilenow properly escapes special characters of file names in internal implementations
- Deprecated APIs in 3.0.x is removed
- Creating instances of
SuFileInputStreamandSuFileOutputStreamis 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
:serviceis added: introduceRootServicefor remote root IPC SuFileInputStreamnow fully supportmark(int),reset(), andskip(long)CallbackListnow support passing in a customExecutorin its constructor to configure which threadonAddElement()to run on
CallbackListno longer synchronizes its baseListinternally (if provided). It is the developer's responsibility if synchronization is required
Shell.Builderis now used to constructShellobjects. Each shell instance creation now has its own configurationsShell.enableVerboseLoggingis 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.enableVerboseLoggingShell.Config: customizeShell.Builderand set it inShell.setDefaultBuilder(Shell.Builder)Shell.newInstance(...): createShell.Builderand 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_BUSYBOXShell.Config.addInitializers(...)Shell.Config.getFlags()SuProcessFileInputStreamSuProcessFileOutputStream
SuFile.getParent()no longer cause NPE when no parent exists- The
libsu:busyboxmodule 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
SuFilewill 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)SuFileInputStreamandSuFileOutputStreamnow supports I/O on all file formats, including character files (e.g. files in/sysand/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
SuFileis no longer a wrapper class aroundFile. Calling the constructor directly will directly open a shell backedFileinstance. This change is due to the fact thatFilewrapper 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 normalFileinstance orSuFile. This is the same behavior as the previousSuFileconstructor (the only difference is thatSuFileused 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.InitializerNPE on old API levels
Shell.Config.setContainer()is deprecated. libsu will handle the global shell without any configurationsContainerAppis deprecated. The class is now just a stockApplication
- When using high level APIs (
Shell.su,Shell.sh,Shell.rootAccess()),NoShellExceptionis now silently suppressed to prevent unexpected crashes. Should no shell is possible to be created,Shell.su/shwill immediately return aShell.Resultwith 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.Initializers: 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:busyboxas a dependency, and registerBusyBoxInstalleras an initializer (Shell.Config.addInitializers(BusyBoxInstaller.class);) - Introduce a new flag:
Shell.FLAG_USE_MAGISK_BUSYBOX. With this flag set,/sbin/.magisk/busyboxwill 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/SuRandomAccessFilewith a character file, it will throwFileNotFoundExceptioninstead 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
submitinPendingJobused to end up calling the overriddenexecinstead ofexecinJobImpl. Proxy through a private method inJobImplto prevent changed behavior ofJobImplsubclasses. - Even though the parameters of
Shell.Job.add(...)is labeled@NonNull, it is still possible that developers still pass innulland cause NPE. Checknullbefore 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
IllegalStateExceptionif the user provide a filter accepting.or..inSuFile.list()family methods.