B4A Library SuperUser: Acquiring root permissions, the easy way.

version 2.4
Introduction

We all have seen various apps asking for superuser permissions to do weird things with our devices and many times we wondered how they do it. Well, with SupeUser, accessing a rooted device is as simple as a function call!

Latest package (library files and samples)
https://www.dropbox.com/s/f8gy3levkrtknt8/superuser.zip

Precompiled samples (APK)
Tutorial, KitKat ScreenRecorder with Audio
The ScreenRecorder does not work in the emulator. Use a real device instead.



upload_2014-7-28_22-17-41.png



Getting started
  • Extract the contents of the package anywhere in your hard disk.
  • Copy the superuser.jar and superuser.xml to your B4A libraries folder
  • Open the tutorial project located in the samples folder

The core of the library is the SuShell class. There are 2 ways using it. The simple and the advanced way. Let's take a look at the tutorial project.

The simple way (SuShellSimple sample)

First of all, we add the appropriate permission in our manifest file
B4X:
AddPermission("android.permission.ACCESS_SUPERUSER")

Whenever you need to do something with root permissions, you can just execute a superuser command and wait for the result (without blocking) in a single line of code. Keep in mind that each time you call the SuShell.Execute method, root permissions will be requested.
B4X:
Dim Su As SuShell
Su.Execute("ls").WaitForCompletion

You can also check before executing the command if the device is rooted and proceed accordingly.
B4X:
Dim Su As SuShell
If Su.DeviceRooted Then
    If Su.ExecuteWithEvent("ls", "Su").WaitForCompletion Then
        Msgbox("Done!", "")
    Else
        Msgbox("Permissions error!", "")
    End If
Else
    Msgbox("Device not rooted!", "")
End If

There is also the possibility to receive events by using the SuShell.ExecuteWithEvent method. The raised events are: Start, Command, Stop
B4X:
Sub BtnExecute_Click
    Dim Su As SuShell
    Su.ExecuteWithEvent("ls", "Su").WaitForCompletion
End Sub

Sub Su_Start
    Log("Su: Start")
End Sub

Sub Su_Command(Command As String, Response() As String)
    Dim Lines As String
    For i=0 To Response.Length-1
        Lines = Lines & Response(i) & CRLF
    Next
    Msgbox(Lines.Trim, Command)
End Sub

Sub Su_Stop(Result As Boolean)
    Log("Su: Stop=" & Result)
End Sub


Some examples:
B4X:
'Reboot the device
Su.Execute("reboot")
Su.Execute("reboot recovery")
Su.Execute("reboot bootloader")

'Restart the GUI by executing 2 commands at once, causing a so called fast-reboot
Su.ExecuteMultiple(Array As String("stop", "start"))


The advanced way (SuShellAdvanced sample)

SuShell is driven by a multi-threaded core that allows you to have complete control of the spawned process. A typical example is this:

Declare an SuShell and an SuProcess object in Sub Process_Globals
B4X:
Sub Process_Globals
    Dim Su As SuShell
    Dim Process As SuProcess
End Sub

Acquire root permissions in Sub Activity_Resume and open a command pipe that can be used at any time without requesting permissions again.
B4X:
If Su.DeviceRooted Then
    Process = Su.Acquire("Su")
End If

If Process.Acquired Then
    Log("root access granted")
Else
    Log("root access denied")
End If

Whenever is needed, execute a superuser command using the SuProcess object
B4X:
If Process.Acquired Then
    Process.Execute(EdCmd.Text)
Else
    Msgbox("Permissions error!", "")
End If

You can also use the methods of the SuProcess class to control it.


Additional Classes

The library currently contains few more classes that are utilizing the superuser core system.

1. SuApk

Can be used to silently install/uninstall apks. Once your app gets permanent root permissions, it will be able to silently install/uninstall any apk.

B4X:
Dim Apk As SuApk
Dim Result As Boolean = Apk.Install(File.DirAssets, "tutorial.apk")
B4X:
Dim Apk As SuApk
Dim Result As Boolean = Apk.Uninstall("com.datasteam.b4a.xtraviews.dialogview.tutorial")


2. SuBrowser

Can be used to offer a Root Explorer similar functionality.

Create an SuBrowser object in Sub Globals
B4X:
Sub Globals
    Dim Browser As SuBrowser
End Sub

In Activity_Resume initialize the object
B4X:
Sub Activity_Resume
    Browser.Initialize
End Sub

Call the SuBrowser.ListFolder to get the folder contents. Pass the desired folder name as a parameter. Use "" to get the root contents. The method returns a List object that contains SuBrowserFileInfo objects.
B4X:
Dim Contents as List = Browser.ListFolder(Folder)

Now you can traverse the Contents object.
B4X:
Contents.SortType("Type", True)
For Each FileInfo As SuBrowserFileInfo In Contents
    Dim SubTitle As String
    If FileInfo.IsFolder Then
        SubTitle = "folder"
    Else
        SubTitle = FileInfo.Size & " byte(s)"
    End If
    LvBrowser.AddTwoLines2(FileInfo.Name, SubTitle, FileInfo)
Next


3. SuRecorder

This class can be used to create a fully functional screen recorder with audio.
A separate tutorial is on its way


Please test it with your devices and post your feedback!

--

That's all for now folks! :D

Version history

2.4
  • Correctly detecting if the device is rooted
2.1

  • Stream optimizations and various bugfixes
2.0
  • Complete refactoring and package renamed to SuperUser
1.2
  • Added: InstallApk and UninstallApk methods. Can be used to silently install/uninstall apks
1.1
  • Added: KeepAlive property. If set to true, the first command will keep the connection with superuser process open without the need of asking for permissions again until the app process is killed or KeepAlive property is set back to false.
1.0
  • Initial version
 
Last edited:

ivan.tellez

Active Member
Licensed User
Longtime User
Wow, amazing. Just tested the recorder and works great on a Galaxy S4 Android 4.4.2

The Recorder can be used to take Screenshots? or that is a different option? thanks
 

Periklis Koutsogiannis

Active Member
Licensed User
Longtime User
Nope. It can only record video for now but it may be extended to take screenshots as well :)
 

Periklis Koutsogiannis

Active Member
Licensed User
Longtime User
Hola @dune3000

Sure. You can do this:
B4X:
Dim Su as SuShell
Dim Process as SuProcess = Su.Execute("logcat -d")

Process.WaitForCompletion

If Process.Success Then
    For i=0 To Process.Response.Length-1
        'Process.Response(i) contains each line that can be saved to a file
    Next
End if

Download the latest version that fixes a bug which caused the process to hang.

:D
 
Last edited:

dune3000

Member
Licensed User
Longtime User
Hola @dune3000

Sure. You can do this:
B4X:
Dim Su as SuShell
Dim Process as SuProcess = Su.Execute("logcat -d")

Process.WaitForCompletion

If Process.Success Then
    For i=0 To Process.Response.Length-1
        'Process.Response(i) contains each line that can be saved to a file
    Next
End if

Download the latest version that fixes a bug which caused the process to hang.

:D

It didn't work on my 4.1.2 rooted phone, looks like hang on the process.
 

Periklis Koutsogiannis

Active Member
Licensed User
Longtime User
Ok then. Lets see ...

I did a silent update (2.2).

Redownload the package and reload the lib in B4a.

Run this in DEBUG mode
B4X:
Dim su As SuShell
Dim Process As SuProcess = su.Execute("logcat -d")

Process.WaitForCompletion

Copy and paste the last b4a logs view (just the last view and not the whole list) here so that I can see why it hangs
 

dune3000

Member
Licensed User
Longtime User
B4X:
>> (in) read: V/AlarmManager(  326): sending alarm Alarm{42dfb200 type 0 com.fg114.main}


>> (in) read: D/PowerManagerService(  326): acquireWakeLock flags=0x1 tag=AlarmManager
>> (in) read: I/executeReportErrorTask(16406): 上传错误报告
>> (in) read: I/PowerManagerService(  326): mLocks.size=2:
>> (in) read: I/PowerManagerService(  326): PARTIAL_WAKE_LOCK              'ActivityManager-Launch' activated (minState=0, uid=1000, pid=326)
>> (in) read: I/PowerManagerService(  326): PARTIAL_WAKE_LOCK              'AlarmManager' activated (minState=0, uid=1000, pid=326)
>> (in) read: D/PowerManagerService(  326): releaseWakeLock flags=0x1 tag=AlarmManager
>> (in) read: I/B4A    (29035): >> (in) read: D/PowerManagerService(  326): releaseWakeLock flags=0x1 tag=AudioOut_5
>> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/PowerManagerService(  326): PARTIAL_WAKE_LOCK              'pushagentPoxy' activated (minState=0, uid=10038, pid=651)
>> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/PowerManagerService(  326): SCREEN_BRIGHT_WAKE_LOCK        'KEEP_SCREEN_ON_FLAG' activated (minState=3, uid=1000, pid=326)
>> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/ActivityManager(  326): Start proc com.eshore.ezone for broadcast com.eshore.ezone/.receiver.InstallReceiver: pid=29095 uid=10103 gids={3003, 1015, 1028}
>> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/BroadcastQueue(  326): There are ordered broadcasts stay in queue, should schedule next Broadcasts.
>> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: D/PowerManagerService(  326): releaseWakeLock flags=0x1 tag=pushagentPoxy
>> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: D/PowerManagerService(  326): releaseWakeLock flags=0x1 tag=AudioOut_5
>> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: V/AlarmManager(  326): set: Alarm{422df1f8 type 0 com.android.vending}
>> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: V/AlarmManager(  326): Adding alarm Alarm{422df1f8 type 0 com.android.vending} at 1
>> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/ActivityManager(  326): Start proc com.huawei.appmarket for broadcast com.huawei.appmarket/.installer.InstallerReceiver: pid=29122 uid=10076 gids={2001, 3003, 1015, 1007, 1028}
>> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/ActivityManager(  326): No longer want com.android.email (pid 27562): hidden #16
>> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/ActivityManager(  326): No longer want com.google.android.apps.uploader (pid 27857): hidden #16


>> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/BroadcastQueue(  326): There are ordered broadcasts stay in queue, should schedule next Broadcasts.
>> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/ActivityManager(  326): No longer want com.android.quicksearchbox (pid 28414): hidden #16
>> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/BroadcastQueue(  326): There are ordered broadcasts stay in queue, should schedule next Broadcasts.
>> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/BroadcastQueue(  326): There are ordered broadcasts stay in queue, should schedule next Broadcasts.
>> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: D/PhoneStatusBar(  442): addNotification score=0
>> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: D/NotificationService(  326): new notification:  numberDiff: 1 ticker: “Get Logcat”未发现安全风险,点击打开 pkg: com.qihoo360.mobilesafe id: 178919 tag: null
>> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: D/NotificationService(  326): ANS send cat: 0 number: 1 msg: “Get Logcat”未发现安全风险,点击打开
>> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/PowerManagerService(  326): PARTIAL_WAKE_LOCK              'ActivityManager-Launch' activated (minState=0, uid=1000, pid=326)
>> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/PowerManagerService(  326): SCREEN_BRIGHT_WAKE_LOCK        'KEEP_SCREEN_ON_FLAG' activated (minState=3, uid=1000, pid=326)
>> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/PowerManagerService(  326): PARTIAL_WAKE_LOCK              'pushagentPoxy' activated (minState=0, uid=10076, pid=29144)
>> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/ActivityManager(  326): Start proc com.google.android.gms for broadcast com.google.android.gms/.gcm.GcmPackageTracker$GcmPackageChangeReceiver: pid=29162 uid=10093 gids={2001, 3003, 1007, 3006, 1028, 1015, 1006, 3002, 3001}
>> (in) read: I/AlarmManager(  326): Wakeup alarm[0]  {2014 7 月 30 18:55:20 +0800} (com.fg114.main) repeatInterval: 0
>> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/ActivityManager(  326): No longer want com.skype.raider (pid 28599): hidden #16


>> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: W/InputMethodManagerService(  326): Window already focused, ignoring focus gain of: com.android.internal.view.IInputMethodClient$Stub$Proxy@42b37c50 attribute=null
>> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: D/PowerManagerService(  326): releaseWakeLock flags=0x1 tag=ActivityManager-Launch
>> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/ActivityManager(  326): No longer want com.google.android.gsf.login (pid 28702): hidden #16
>> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: D/PowerManagerService(  326): reactivateScreenLocksLocked mProxIgnoredBecauseScreenTurnedOff=false
>> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: D/PowerManagerService(  326): releaseWakeLock flags=0x2000000a tag=KEEP_SCREEN_ON_FLAG
>> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: D/PowerManagerService(  326): reactivateScreenLocksLocked mProxIgnoredBecauseScreenTurnedOff=false
>> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: E/dalvikvm(29035): GC_CONCURRENT freed 1829K, 15% free 12090K/14151K, paused 13ms+12ms, total 75ms
>> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: W/ActivityManager(  326): Scheduling restart of crashed service com.skype.raider/com.skype.android.service.AccountService in 5000ms
>> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/BroadcastQueue(  326): There are ordered broadcasts stay in queue, should schedule next Broadcasts.
>> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/B4A    (29035): >> (in) read: I/BroadcastQueue(  326): There are ordered broadcasts stay in queue, should schedule next Broadcasts.
>> (in) read: V/AlarmManager(  326): set: Alarm{42b3ae10 type 0 com.fg114.main}
java.util.concurrent.TimeoutException
---->> end read: logcat -d
close+++
<< (out) write: exit

Here is the last log view
 

Periklis Koutsogiannis

Active Member
Licensed User
Longtime User
Last edited:

dune3000

Member
Licensed User
Longtime User
Hi, Periklis
When I run the tutorial on my 4.2.2 rooted tablet, after click on "advanced" button, the asking for superuser permissions window didn't appear, and it said "root access denied", but click on "SuBrowser", it asked for superuser permissions, and work normally.
please fix this issue.
 
Top