Git Product home page Git Product logo

shizuku-api's Introduction

Shizuku-API

Shizuku API is the API provided by Shizuku and Sui. With Shizuku API, you can call your Java/JNI code with root/shell (ADB) identity.

Requirements

To use Shizuku APIs, you need to guide the user to install Shizuku or Sui first. Both of them require Android 6.0+.

Shizuku

Shizuku is a standard Android application. You can guide the users to download Shizuku from https://shizuku.rikka.app/download/. Shizuku works for both rooted and non-rooted devices.

On non-rooted devices, Shizuku needs to be manually restarted with adb every time on boot. Before Android 11, a computer is required to run adb. Android 11 and above have built-in wireless debugging support, and users can start Shizuku directly on the device.

Sui

Sui is a Magisk module. Magisk requires an unlocked bootloader.

No additional setup is required except for the installation. You can guide the rooted users (searching su in PATH is enough) to download Sui from Magisk or https://github.com/RikkaApps/Sui.

Demo

A demo project is provided. See demo for more.

Guide

I'll say the difficult words first, using Shizuku APIs is similar to framework or system app development, some experience in developing common applications may not be enough. You have to get used to digging into Android source code to find out how things work, cs.android.com and AndroidXref sites will be your best friend.

Add dependency

Maven Central

def shizuku_version = (the version above)
implementation "dev.rikka.shizuku:api:$shizuku_version"

// Add this line if you want to support Shizuku
implementation "dev.rikka.shizuku:provider:$shizuku_version"

Acquire the Binder

The first step is to acquire the Binder from Shizuku or Sui.

Shizuku class provides listeners, Shizuku#addBinderReceivedListener() and Shizuku.addBinderDeadListener(), that allows you to track the life of the binder. You should call methods in Shizuku class when the binder is alive or you will get an IllegalStateException.

The steps to get a Binder from Sui and Shizuku are different.

Sui

Call Sui.init(packageName) before using Shizuku class. This method only needs to be called once. If this method returns true, means Sui is installed and available.

For multi-process applications, call this method in every process that needs to use Shizuku API.

Note, request the binder for Sui only requires two times of binder IPC, this is significantly cheaper than initialize Shizuku which uses ContentProvider. Sui.init(packageName) can be used in main thread, you don't need to worry about performance.

Shizuku

Add ShizukuProvider to AndroidManifest.xml.

<provider
    android:name="rikka.shizuku.ShizukuProvider"
    android:authorities="${applicationId}.shizuku"
    android:multiprocess="false"
    android:enabled="true"
    android:exported="true"
    android:permission="android.permission.INTERACT_ACROSS_USERS_FULL" />

<!-- android:permission="android.permission.INTERACT_ACROSS_USERS_FULL" is to protect this provider from accessing by normal apps -->

For multi-process applications, you need to call ShizukuProvider.enableMultiProcessSupport() in every process which needs to use Shizuku API.

Starting from v12.1.0, Sui is initialized automatically in ShizukuProvider. You can opt-out this behavior by calling ShizukuProvider#disableAutomaticSuiInitialization() before ShizukuProvider#onCreate() is called. Unless there are special reasons, apps that support Shizuku should also support Sui, otherwise it will cause user confusion.

Request permission

Requesting permission is similar to requesting runtime permissions.

A simple example of requesting permission:

private void onRequestPermissionsResult(int requestCode, int grantResult) {
    boolean granted = grantResult == PackageManager.PERMISSION_GRANTED;
    // Do stuff based on the result and the request code
}

private final Shizuku.OnRequestPermissionResultListener REQUEST_PERMISSION_RESULT_LISTENER = this::onRequestPermissionsResult;

@Override
protected void onCreate(Bundle savedInstanceState) {
    // ...
    Shizuku.addRequestPermissionResultListener(REQUEST_PERMISSION_RESULT_LISTENER);
    // ...
}

@Override
protected void onDestroy() {
    // ...
    Shizuku.removeRequestPermissionResultListener(REQUEST_PERMISSION_RESULT_LISTENER);
    // ...
}

private boolean checkPermission(int code) {
  if (Shizuku.isPreV11()) {
    // Pre-v11 is unsupported
    return false;
  }

  if (Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED) {
    // Granted
    return true;
  } else if (Shizuku.shouldShowRequestPermissionRationale()) {
    // Users choose "Deny and don't ask again"
    return false;
  } else {
    // Request the permission
    Shizuku.requestPermission(code);
    return false;
  }
}

Differents of the privilege betweent ADB and ROOT

Shizuku can be started with ADB or ROOT, and Sui is a Magisk module, so the privilege could be ADB or ROOT. You can use Shizuku#getUid() to check your privilege, for ROOT it returns 0, for ADB is 2000.

What ADB can do is significantly different from ROOT:

  • In the Android world, the privilege is determined by Android permissions. See AndroidManifest of Shell, all the permission granted to Shell (ADB) are listed here. Be aware, the permission changes under different Android versions.

  • In Linux world, the privilege is determined by Shell's uid, capabilities, SELinux context, etc. For example, Shell (ADB) cannot access other apps' data files /data/user/0/<package>.

Remote binder call

This is a relatively simple way, but what you can do is limited to Binder calls. Therefore, this is only suitable for simple applications.

Shizuku API provides rikka.shizuku.ShizukuBinderWrapper class which forward Binder calls to Shizuku service which has ADB or ROOT privilege.

UserService

User Service is like Bound services which allows you to run Java or native codes (through JNI). The difference is that the service runs in a different process and as the identity (Linux UID) of root (UID 0) or shell (UID 2000, if the backend is Shizuku and user starts Shizuku with adb).

There are no restrictions on non-SDK APIs in the user service process. However, the User Service process is not a valid Android application process. Therefore, even if you can acquire a Context instance, many APIs, such as Context#registerReceiver and Context#getContentResolver will not work. You will need to dig into Android source code to find out how things work.

Be aware that, to let the service to use the latest code, "Run/Debug configurations" - "Always install with package manager" in Android Studio should be checked.

  • Start the User Service

    Use bindUserService method. This method has two parameters, UserServiceArgs and ServiceConnection.

    UserServiceArgs is like Intent in Bound services, which decides which service will be started and some options.

    ServiceConnection is same as Bound services, but only onServiceConnected and onServiceDisconnected are used.

    Unlike Bound service, the service class must implement IBinder interface. The usual usage is public class YourService extends IYouAidlInterface.Stub.

    The service class can have two constructors, one is default constructor, another is with Context parameter available from Shizuku v13. Shizuku v13 will try the constructor with Context parameter first. Older Shizuku will always use the default constructor. Beaware that the Context does not work as same as Context in normal Android application. See "Use Android APIs in user service" below.

    Shizuku uses tag from UserServiceArgs to determine if the User Service is same. If tag is not set, class name will be uses, but class name is unstable after ProGuard/R8. If version from UserServiceArgs mismatches, a new User Service will be start and "destroy" method (see below) will be called for the old.

  • Stop the User Service

    Use unbindUserService method. However, the user service process will NOT be killed automatically. You need to implement a "destroy" method in your service. The transaction code for that method is 16777115 (use 16777114 in aidl). In this method, you can do some cleanup jobs and call System.exit() in the end.

The use of non-SDK interfaces

For "Remote binder call", as the APIs are accessed from the app's process, you may need to use AndroidHiddenApiBypass or any ways you want to bypass restrictions on non-SDK interfaces.

We also provides HiddenApiRefinePlugin to help you to programing with hidden APIs conveniently.

Changelog

13.1.5

  • Fix ShizukuProvider#requestBinderForNonProviderProcess crash on Android 14 (for apps targeting Android 14)

13.1.4

  • Ask the server to remove ShizukuServiceConnection if the server is new enough

13.1.3

  • Fix the problem that Shizuku#unbindUserService(remove=false) does not actually remove the callback

13.1.2

  • Avoid the use of CopyOnWriteArrayList#removeIf, as using it with coreLibraryDesugaring enabled will crash on Android 8+

13.1.1

  • Fix Shizuku#removeXXXListener will crash on Android 7.1 and earlier versions

    This is caused by CopyOnWriteArrayList#removeIf is not supported (throw an UnsupportedOperationException) before Android 8.0. Please note, using coreLibraryDesugaring will NOT fix this issue at least in version 2.0.3.

  • Prepare to remove Shizuku#newProcess, developers should have to use UserService instead

    First, this is already announced two years ago.

    For those who don't understand, UserService gives the developer the ability to run their own codes in a different process with root or shell privilege. This is much more powerful than just executing a command. UserService can replace newProcess in all cases.

    Also, newProcess uses texts to communicate , which is not efficient and unreliable. If there are apps that only uses newProcess to implement its functions, it loses most of the advantage of using Shizuku.

    Finally, newProcess lacks tty support, it is not possible to implement an interactive shell with it. And we already has rish that allows users to run an interactive shell with privilege in any terminal app they like.

13.1.0

  • Breaking change: desugaring is required if min API of your app is 23
  • Listeners now has an optional Handler parameter that determines which thread will the listener be called from

13.0.0

  • The constructor of UserService can have a Context parameter which value is the Context used to create the instance of UserService

12.2.0

  • Fix onServiceDisconnected is not called if the UserService is stopped by Shizuku#unbindUserService

12.1.0

  • Automatically initialize Sui if you are using Shizuku

    You can opt-out this behavior by calling ShizukuProvider#disableAutomaticSuiInitialization() before ShizukuProvider#onCreate() is called

  • Added a lot more detailed document for most APIs

  • Drop pre-v11 support

    You don't need to worry about this problem, just show a "not supported" message if the user really uses pre-v11.

    • Sui was born after API v11, Sui users are not affected at all.
    • For Shizuku, according to Google Play statistics, more than 95% of users are on v11+. Shizuku drops Android 5 support from v5, many of the remaining 5% are such people who are stuck at super old versions.
    • A useful API, UserService, is added from v11 and stable on v12. I believe that many Shizuku apps already have a "version > 11" check.
    • I really want to drop pre-v11 support since a possible system issue that may cause system soft reboot (system server crash) on uninstalling Shizuku.

12.0.0

  • Add Shizuku#peekUserService that allows you to check if a specific user service is running
  • Add Shizuku.UserServiceArgs#daemon that allows you to control if the user service should be run in the "Daemon mode"

Migration guide for existing applications use Shizuku pre-v11

Click to expand

Changes

  • Dependency changed (see Guide below)
  • Self-implemented permission is used from v11, the API is the same to runtime permission (see the demo, and existing runtime permission still works)
  • Package name was renamed to rikka.shizuku (replace all moe.shizuku.api. to rikka.shizuku.)
  • ShizukuService class is renamed to Shizuku
  • Methods in Shizuku class now throw RuntimeException on failure rather than RemoteException like other Android APIs
  • Listeners are moved from ShizukuProvider class to Shizuku class

Add support for Sui

  • Call Sui#init()
  • It's better to use check Sui with Sui#isSui before using Shizuku only methods in ShizukuProvider

shizuku-api's People

Contributors

fengyuecanzhu avatar hamza417 avatar haruue avatar pranavpurwar avatar rikkaw avatar ryuunoakaihitomi avatar vvb2060 avatar yorick-ryu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

shizuku-api's Issues

请问如何调用非SDK系统API

我尝试以以下方式调用非SDK系统API,但是不起作用。

public static final Singleton<IPowerManager> POWER_MANAGER = new Singleton<IPowerManager>() {
        @Override
        protected IPowerManager create() {
            return IPowerManager.Stub.asInterface(new ShizukuBinderWrapper(SystemServiceHelper.getSystemService(Context.POWER_SERVICE)));
        }
    };
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {

  //这个不是隐藏api,可以访问到值
    HiddenApiBypass.invoke(IPowerManager::class.java, ShizukuSystemServerApi.POWER_MANAGER.get(), "isPowerSaveMode", true);
  //这个是隐藏api,调用后没有反应
    HiddenApiBypass.invoke(IPowerManager::class.java, ShizukuSystemServerApi.POWER_MANAGER.get(), "setPowerSaveModeEnabled", true);
}

请问如果我要调用PowerManager里的隐藏方法我应该如何操作呢?

Demo project needs to be updated

I got a compilation error:

Manifest merger failed : uses-sdk:minSdkVersion 23 cannot be smaller than version 24 declared in library [:api] C:\StudioProjects\Shizuku-API\api\build\intermediates\merged_manifest\debug\AndroidManifest.xml as the library might be using APIs not available in 23
	Suggestion: use a compatible library with a minSdk of at most 23,
		or increase this project's minSdk version to at least 24,
		or use tools:overrideLibrary="rikka.shizuku.api" to force usage (may lead to runtime failures)

如何通过Shizuku调用Shell

因为项目需要,故要调用以下Shell:
/system/xbin/bstk/su
mount /system -o remount,rw
但看了半天开发文档还是摸不着头脑,故发个issue求解答

初始化时无法获得binder

Shizuku.OnBinderReceivedListener 事件接收不到,请求权限就会抛出异常,问题出现在rikka.sui.SuiIBinder received = reply.readStrongBinder();receivednull
步骤:

  1. 添加依赖,添加provider,添加FreeReflection
  2. 添加Application,调用Sui.init(BuildConfig.APPLICATION_ID);
  3. Activity 绑定事件

一些第三方工具(测试了Tasker和MacroDroid)无法调用Shizuku的rish

没打完字就提交了,按错了,在编辑 已编辑完成

测试的Shizuku版本为v12.6.2

测试过程中使用了TaskerMacroDroid,均已经修改了RISH_APPLICATION_ID(MacroDroid需要使用MD-Helper,因为高版本Android受到Google Play政策限制MD无法申请到存储空间权限)。

将rish与dex文件释放在/storage/emulated/0/shizuku文件夹,根据文档提示,在两者的shell脚本任务中尝试执行命令。

sh /storage/emulated/0/shizuku/rish -c "ls"

但没有任何的输出,具体表现为命令卡在了这里,没有任何的输出,设定的超时时间之后执行中断。

我不太确定是否是我对这个工具的一些使用理解上出了一些问题,能否提示一些调试这个功能有关的细节以便我分析问题?谢谢

How to call the system settings api in UserService?

Settings.Secure.putString(resolver,
                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
                String.format("%s/%s",packageName,serviceName));
        Settings.Secure.putInt(resolver,
                Settings.Secure.ACCESSIBILITY_ENABLED, 1);

The "resolver" object here cannot be obtained from UserService.

没看懂demo,求大佬指点一下

我想在授权shizuku后执行shell命令,但是在demo没有翻到此类的操作,看了其他issue有提到,是需在service里执行命令吗?然后在bindservice后调用?

How to add fallback in case the calling to the reflected API fails?

I hope I'm asking this in the correct place. Couldn't find a forum for this...

About my question, suppose you reach the PackageManager class function to disable some app.
If for some reason this API changes in some Android version, can I use Shizuku to call more official commands like on adb?

Meaning in adb it's :

adb shell pm disable PACKAGE_NAME

Is the same thing possible via Shizuku?

Does rish work when the system in Doze(sleeping)?

This is a great tool for non-root systems. Everything is working well when in screen on state. however after screen off with 5 minutes, we get no response when executing the shell scripts. So may know if it supports? Thanks!

coreLibraryDesugaring导致的问题

启用coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs_nio:2.0.2'对高版本API进行脱糖后,List的removeIf方法会被替换成调用iterator遍历,然后调用remove删除。
巧的是CopyOnWriteArrayList.COWIterator不支持remove方法,这导致Shizuku类里面几个调用removeIf的方法都会报错。
修改建议是把字段类型均改成CopyOnWriteArrayListCompat而不是List:

private static final CopyOnWriteArrayListCompat<ListenerHolder<OnBinderReceivedListener>> RECEIVED_LISTENERS = new CopyOnWriteArrayListCompat<>();
private static final CopyOnWriteArrayListCompat<ListenerHolder<OnBinderDeadListener>> DEAD_LISTENERS = new CopyOnWriteArrayListCompat<>();
private static final CopyOnWriteArrayListCompat<ListenerHolder<OnRequestPermissionResultListener>> PERMISSION_LISTENERS = new CopyOnWriteArrayListCompat<>();

`UnsatisfiedLinkError: No implementation found` when attempting to use native code loaded via a DexClassLoader

I'm attempting to load an APK using DexClassLoader within the Shizuku service. It all seems to work well and I can call methods (and have also got LSPlant working via Aliucord's Hook library too), but when trying to call JNI from within the APK, it seems to stop working.

My intentions are to try to run the recognition code for Ambient Music within Shell, which in theory would work - I've already got a PoC working as a system app (no Xposed or model loading needed as LSPlant can stop the framework calls and instead trigger it manually), but the ultimate goal is to get it working with just Shizuku. Shell has access to record audio using the hotword mic, but simply recording the audio and sending it back to a client isn't sufficient as there's also something in the recognition (not this crash) that requires being a system app.

Minimal setup:

val context = Class.forName("android.app.ActivityThread")
	.getMethod("currentApplication")
	.invoke(null) as Context

val apkPath = File("/data/local/tmp", "aiai.apk").absolutePath
val sourceDir = context.packageManager.getApplicationInfo(BuildConfig.APPLICATION_ID, 0).sourceDir
var librarySearchPath: String = sourceDir.toString() + "!/lib/" + Build.SUPPORTED_ABIS[0]
val systemLibrarySearchPath = System.getProperty("java.library.path")
if (!TextUtils.isEmpty(systemLibrarySearchPath)) {
	librarySearchPath += File.pathSeparatorChar.toString() + systemLibrarySearchPath
}
val classLoader = DexClassLoader(apkPath, ".", librarySearchPath, ClassLoader.getSystemClassLoader())

System.loadLibrary("sense")

val lfr = classLoader.loadClass("lfr").getDeclaredConstructor().apply {
	isAccessible = true
}.newInstance()

val nnfpRecognizer = classLoader.loadClass("com.google.audio.ambientmusic.NnfpRecognizer")
	.getConstructor(lfr::class.java, Array<String>::class.java, Array<String>::class.java)
	.newInstance(lfr, emptyArray<String>(), emptyArray<String>())
  • Run the project, you will get an exception:
04-22 01:46:26.851 22051 22074 E com.kieronquinn.app.shizukutest:shizuku: No implementation found for long com.google.audio.ambientmusic.NnfpRecognizer.init(java.lang.String[], java.lang.String[], byte[]) (tried Java_com_google_audio_ambientmusic_NnfpRecognizer_init and Java_com_google_audio_ambientmusic_NnfpRecognizer_init___3Ljava_lang_String_2_3Ljava_lang_String_2_3B)
04-22 01:46:26.851 22051 22074 E JavaBinder: *** Uncaught remote exception!  (Exceptions are not yet supported across processes.)
04-22 01:46:26.851 22051 22074 E JavaBinder: java.lang.reflect.InvocationTargetException
04-22 01:46:26.851 22051 22074 E JavaBinder:    at java.lang.reflect.Constructor.newInstance0(Native Method)
04-22 01:46:26.851 22051 22074 E JavaBinder:    at java.lang.reflect.Constructor.newInstance(Constructor.java:343)
04-22 01:46:26.851 22051 22074 E JavaBinder:    at com.kieronquinn.app.shizukutest.ShizukuService.start(ShizukuService.kt:77)
04-22 01:46:26.851 22051 22074 E JavaBinder:    at com.kieronquinn.app.shizukutest.IShizukuService$Stub.onTransact(IShizukuService.java:59)
04-22 01:46:26.851 22051 22074 E JavaBinder:    at android.os.Binder.execTransactInternal(Binder.java:1179)
04-22 01:46:26.851 22051 22074 E JavaBinder:    at android.os.Binder.execTransact(Binder.java:1143)
04-22 01:46:26.851 22051 22074 E JavaBinder: Caused by: java.lang.UnsatisfiedLinkError: No implementation found for long com.google.audio.ambientmusic.NnfpRecognizer.init(java.lang.String[], java.lang.String[], byte[]) (tried Java_com_google_audio_ambientmusic_NnfpRecognizer_init and Java_com_google_audio_ambientmusic_NnfpRecognizer_init___3Ljava_lang_String_2_3Ljava_lang_String_2_3B)
04-22 01:46:26.851 22051 22074 E JavaBinder:    at com.google.audio.ambientmusic.NnfpRecognizer.init(Native Method)
04-22 01:46:26.851 22051 22074 E JavaBinder:    at com.google.audio.ambientmusic.NnfpRecognizer.<init>(PG:2)
04-22 01:46:26.851 22051 22074 E JavaBinder:    ... 6 more

I've made the code identical to how Shizuku starts the Java code from a shell service, other than loading the source directory using PackageManager.

I've also tried:

  • Using PathClassLoader
  • Loading the library from /data/local/tmp
  • Using a different version of the APK
  • Loading the library in static {}
  • Loading the Application fully (ie. creating an instance of the Application class where it loads libsense normally)
  • Disabling selinux, although that kind of defeats the whole point of using Shizuku!

None of these make any difference, the exception is identical.

I've also verified that the function in the library is exported:

image

There's no other relevant logcat output either.

What's really strange is that using Hook does work, even though it also uses native libraries in exactly the same way. Those are loaded fine, and methods are hooked without a problem.

Obviously this is quite a specific edge case, so if there's something that prevents this working in the system that simply isn't surfacing in the logcat, I'll happily move on and make the mod require a Magisk module to make it a system app.

Thanks!

rish的stderr问题

rish/src/main/java/rikka/rish/RishTerminal.java
这行写错了吧:
ttyFd = start(tty, getFd(stdin, 1), getFd(stdout, 0), getFd(stdout, 0));

API Compatibility question

Hi

I can't seem to find any info about APP - API version compatibility other than the "preV11" check

Will the current version of the API (12.1.0) continue to work correctly with newer versions of Shizuku e.g. when shizuku 14 and shizuku-api 14 come out? Is compatibility guaranteed until a specific version?

Hello, Can I use shizuku api Send System Broadcast?

I want send system broadcast

adb shell settings put global airplane_mode_on 0/1

# and send broadcast android.intent.action.AIRPLANE_MODE

Can it complete?

Thanks!

I'm try

<uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL"
        tools:ignore="ProtectedPermissions" />
SystemServiceHelper.getSystemService(Context.CONNECTIVITY_SERVICE);

but error...

How to turn request permission callback into coroutine

I want to try some other strategies if shizuku setup fail, so I try to make this into coroutine. The shizuku permision dialog appeared and i clicked yes, but onRequestPermissionResult never called. It works well without coroutine. Any one know why.

suspend fun tryShizuku() = runCatching {
    suspendCoroutine { cont ->
        Log.d(TAG, "try shizuki")                             // <-- this called

        Shizuku.addRequestPermissionResultListener(
            object : OnRequestPermissionResultListener {
                override fun onRequestPermissionResult(requestCode: Int, grantResult: Int) {

                    Log.d(TAG, "onRequestPermissionResult")   // <--- this not called

                    Shizuku.removeRequestPermissionResultListener(this)

                    if (grantResult != PERMISSION_GRANTED) {
                        cont.resumeWithException(Exception())
                        return
                    }
                    val userServiceArgs = UserServiceArgs(
                        ComponentName(
                            BuildConfig.LIBRARY_PACKAGE_NAME.replace(".task", ".host"),
                            shizukiServiceClass.getName()
                        )
                    )
                        .daemon(false)
                        .processNameSuffix("service")
                        .debuggable(BuildConfig.DEBUG)
                        .version(1)
                    Shizuku.bindUserService(userServiceArgs, RootServiceConnection())
                    cont.resume(Unit)
                }
            })
        Shizuku.requestPermission(0)
    }
}

rish or sh rish

I am confused about why i dont get rish use without preceeding it with sh.
Sh wouldnt work termix previously. Now it worka without really working and rish doesnt work on its own.

Request service to run as shell (when Shizuku has been started by root)

This is a massive edge case, but I've found a scenario that it's needed. Not sure if it's a "bug" in the Manager or an API feature request, so I've put it here, but feel free to move it.

Basically, if you start Shizuku on a rooted device, subsequent calls to getCallingUid() (when not handling a transaction from the app) will return 0, root. If the Shizuku service has been started by ADB, it will return 2000 (com.android.shell). This is expected, as the service has been started by those UIDs originally.

However, there are some cases (eg. the launcherapps and shortcut system services), where root is worse than shell, and the system service will actually reject calls from root, but take them from shell. Here's an example:

ILauncherApps.aidl (you'll also need to create the stubs for ParceledListSlice + its parent and ShortcutQueryWrapper, sorry - I can provide more if needed)

package android.content.pm;

import android.os.UserHandle;
import android.content.pm.ParceledListSlice;
import android.content.pm.ShortcutQueryWrapper;

interface ILauncherApps {
    ParceledListSlice getShortcuts(String callingPackage, in ShortcutQueryWrapper query, in UserHandle user) = 13;
}

In a Shizuku service:

private val launcherApps by lazy {
    val launcherAppsProxy = SystemServiceHelper.getSystemService("launcherapps")
    ILauncherApps.Stub.asInterface(launcherAppsProxy)
}

//context is the system context, get it however you prefer
private fun getUserHandle(): UserHandle {
	return Context::class.java.getMethod("getUser").invoke(context) as UserHandle
}

override fun getShortcuts(query: ShortcutQueryWrapper) {
	val token = clearCallingIdentity()
	Log.d("TTSS", "getShortcuts ${getCallingUid()}")
	val shortcuts = launcherApps.getShortcuts("com.android.shell", query, getUserHandle()) as ParceledListSlice<ShortcutInfo>
	Log.d("TTSS", "Got shortcuts! Size ${shortcuts.list.size}")
	restoreCallingIdentity(token)
}

For the query you can use the generic:

val query = ShortcutQueryWrapper(LauncherApps.ShortcutQuery().apply {
	setQueryFlags(LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC or LauncherApps.ShortcutQuery.FLAG_MATCH_MANIFEST)
})

When running from Shizuku started with root, the call will result in a crash:

11-09 00:14:12.617 30021 30021 E AndroidRuntime: Process: com.kieronquinn.app.taptap, PID: 30021
11-09 00:14:12.617 30021 30021 E AndroidRuntime: java.lang.SecurityException: Calling package name mismatch
11-09 00:14:12.617 30021 30021 E AndroidRuntime:        at android.os.Parcel.createExceptionOrNull(Parcel.java:2425)
11-09 00:14:12.617 30021 30021 E AndroidRuntime:        at android.os.Parcel.createException(Parcel.java:2409)
11-09 00:14:12.617 30021 30021 E AndroidRuntime:        at android.os.Parcel.readException(Parcel.java:2392)
11-09 00:14:12.617 30021 30021 E AndroidRuntime:        at android.os.Parcel.readException(Parcel.java:2334)
11-09 00:14:12.617 30021 30021 E AndroidRuntime:        at com.kieronquinn.app.taptap.shizuku.ITapTapShizukuService$Stub$Proxy.getShortcuts(ITapTapShizukuService.java:151)

When running from Shizuku started with ADB, the call will work fine and a list of shortcuts will be returned.

We can trace the crash back to here:

void verifyCallingPackage(String callingPackage) {
	int packageUid = -1;
	try {
		packageUid = AppGlobals.getPackageManager().getPackageUid(callingPackage,
				PackageManager.MATCH_DIRECT_BOOT_AWARE
						| PackageManager.MATCH_DIRECT_BOOT_UNAWARE
						| PackageManager.MATCH_UNINSTALLED_PACKAGES,
				UserHandle.getUserId(getCallingUid()));
	} catch (RemoteException ignore) {
	}
	if (packageUid < 0) {
		Log.e(TAG, "Package not found: " + callingPackage);
	}
	if (packageUid != injectBinderCallingUid()) {
		throw new SecurityException("Calling package name mismatch");
	}
}

//...

int injectBinderCallingUid() {
	return getCallingUid();
}

Which as you can see is checking the calling UID against the one found for the package name. It's worth noting that passing "android" as the package name does not work here either, and there's no package name for root, so it will always fail with that.

Just for the sake of it you can also prove this in the shell:

When running as shell:

raven:/ $ service call launcherapps 13 s16 com.android.shell
Result: Parcel(
  0x00000000: fffffffc 00000067 00740041 00650074 '....g...A.t.t.e.'
  0x00000010: 0070006d 00200074 006f0074 00690020 'm.p.t. .t.o. .i.'
  0x00000020: 0076006e 006b006f 00200065 00690076 'n.v.o.k.e. .v.i.'
  0x00000030: 00740072 00610075 0020006c 0065006d 'r.t.u.a.l. .m.e.'
  0x00000040: 00680074 0064006f 00270020 006e0069 't.h.o.d. .'.i.n.'
  0x00000050: 00200074 006e0061 00720064 0069006f 't. .a.n.d.r.o.i.'
  0x00000060: 002e0064 0073006f 0055002e 00650073 'd...o.s...U.s.e.'
  0x00000070: 00480072 006e0061 006c0064 002e0065 'r.H.a.n.d.l.e...'
  0x00000080: 00650067 00490074 00650064 0074006e 'g.e.t.I.d.e.n.t.'
  0x00000090: 00660069 00650069 00280072 00270029 'i.f.i.e.r.(.).'.'

(etc., it's passed the package name check that's what matters)

When running as root:

raven:/ # service call launcherapps 13 s16 com.android.shell
Result: Parcel(
  0x00000000: ffffffff 0000001d 00610043 006c006c '........C.a.l.l.'
  0x00000010: 006e0069 00200067 00610070 006b0063 'i.n.g. .p.a.c.k.'
  0x00000020: 00670061 00200065 0061006e 0065006d 'a.g.e. .n.a.m.e.'
  0x00000030: 006d0020 00730069 0061006d 00630074 ' .m.i.s.m.a.t.c.'
  0x00000040: 00000068 00000000                   'h.......        ')

My suggestion for getting around this would be to simply run the start command from the manager as shell, with su -l 2000 - if that is possible with how Shizuku works (admittedly I've not checked). If possible, to maintain compatibility, it could also be an API option (hence making the issue here).

If you need any more code, I can send a WIP version of Tap, Tap that has this issue.

Cheers

Add `removeAllListeners` if possible

While using lambda to add listener in Kotlin, it seems that the listener cannot be removed in this case.

For example,

Shizuku.addRequestPermissionResultListener { _, _ -> doSomething() }

There is no way to remove this particular listener. Since I only added this one listener, it would be better to remove them all at once.

Maybe we can add a function named removeAllListeners in a easy case.

public static void removeAllListeners() {
    RECEIVED_LISTENERS.clear();
    DEAD_LISTENERS.clear();
    PERMISSION_LISTENERS.clear();
}

or divide this function into 3 cases

n

adb shell pm grant com.arumcomm.crashlogviewer android.permission.PACKAGE_USAGE_STATS
adb shell pm grant com.arumcomm.crashlogviewer android.permission.READ_LOGS

Kill all running instances of Shizuku service

I'm working on moving DarQ [I think you suggested I move it a long time ago and it was rejected due to libsuperuser being more suited to the task, which with the advent of local ADB is no longer the case] to use a hybrid of Shizuku for ADB and libsu's bound services for root, and it's working well - except that I need the service to outlast the Application.

libsu handles this gracefully by allowing services to be daemons (see here), which seems to be similarly possible with Shizuku by simply not unbinding the service.

However, when the app needs to bind the service again (for example when the user launches the settings for config), Shizuku doesn't have a way of cleaning up the running daemon service to start a new one for binding. I can do it easily with libsu using RootService.stop(...), which removes any remote services with that intent, but the Shizuku.unbindUserService() method expects a service connection which I no longer have - and passing a dummy one doesn't remove the remote service. This means that when I call RootService.bindUserService it starts a new one and I end up with two running.

Could a similar stop() method to libsu's be added please?

[bug] One of RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED should be specified when a receiver isn't being registered exclusively for system broadcasts

context.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
BinderContainer container = intent.getParcelableExtra(EXTRA_BINDER);
if (container != null && container.binder != null) {
Log.i(TAG, "binder received from broadcast");
Shizuku.onBinderReceived(container.binder, context.getPackageName());
}
}
}, new IntentFilter(ACTION_BINDER_RECEIVED));

https://developer.android.com/about/versions/14/behavior-changes-14?hl=zh-cn#runtime-receivers-exported

Question: are there limitations of using Shizuku?

I've noticed that the demo shows only about getting the instance via SystemServiceHelper.getSystemService .

But what about other types of classes? For example Singleton classes like Runtime , which you need to reach its instance via a static function (Runtime.getRuntime() ) ?

image

And what about classes that need to be instantiated by the library, including those that have multiple arguments for the CTOR (such as ProcessBuilder, which is created via Runtime.getRuntime().exec )?

Are both of these possible to reach?

關於rish調用方法

Shizuku API 拿到權限后,需要怎麽樣才能調用 adb 的指令?
請求各位大佬指點。

对于没有在公共SDK中导出AIDL的类,如何调用比较方便

image

如图,希望调用ActivityManager的getRunningAppProcesses方法,但是ActivityManager的AIDL没有在公共sdk中导出,因此好像不好通过IActivityManager.Stub.asInterface来构造Singleton。这种情况有没有什么比较方便的解决办法?
(倒是好像可以靠写UserService解决,但是那里面在api13以下没有context,又不好拿ActivityManager)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.