Dhizuku API是Dhizuku的API。你可以通过Dhizuku API调用系统接口,完成共享设备所有者功能(Device Owner)。
def dhizuku_version = "version of api"
implementation "io.github.iamr0s:Dhizuku-API:$dhizuku_version"
执行如下代码从而初始化Dhizuku-API,如果初始化失败(Dhizuku不存在、未激活)就开始调用其余API会抛出错误
Dhizuku.init(context) // return boolean
某些API接口需要先请求权限才能运行
if (Dhizuku.isPermissionGranted()) return
Dhizuku.requestPermission(new DhizukuRequestPermissionListener() {
@Override
public void onRequestPermission(int grantResult) throws RemoteException {
if (grantResult == PackageManager.PERMISSION_GRANTED) {
// do success code
}else {
// do failure code
}
}
});
会向Dhizuku服务器发起一个请求,用于开启UserService,类似于Android系统本身的Service,但是是基于AIDL。
具体实现请参考 Demo UserService。
如果你用过 Shizuku 的UserService,那么你应该可以很好的理解这个功能,但是他们之间也存在着一些不同,请仔细阅读下列内容
一般的使用步骤为:
- 首先自定义一个UserService AIDL文件
请注意,20及以内的transact code是保留给未来的Dhizuku APi使用的,您不能轻易使用它,你的自定义操作应该从21开始
-
Build你的项目,使得Android Studio生成对应于AIDL的Stub子类
-
实现这个Stub类型,即 UserService
你有两种构造器函数实现可选,即带Context参数或不带,当你两种构造器都存在时,有限选择带构造器的。
注意:
- Context无法调用Android的四大组件
- UserService的生命周期与发起者有关,当所有发起者的进程处于死亡状态时,UserService自动退出
- 当UserService被Dhizuku关闭或被强制退出时,UserService的onDestory方法不保证一定调用,
- 享用一个带有设备所有者权限的 Service
String[] cmd = new String[]{"whoami"};
String[] env = null;
File dir = null;
try {
Process process = Dhizuku.newProcess(cmd, env, dir);
process.waitFor();
InputStream input = process.getInputStream();
InputStream err = process.getErrorStream();
byte[] bytes = new byte[input.available()];
input.read(bytes);
Log.e("dhizuku-api", "input " + new String(bytes));
bytes = new byte[err.available()];
Log.e("dhizuku-api", "error " + new String(bytes));
} catch (InterruptedException | IOException e) {
throw new RuntimeException(e);
}
应用与应用之间、应用与系统服务之间的交流主要通过IBinder完成,Dhizuku支持代理IBinder。如果你用过Shizuku的api,我相信你能很好的理解这个接口。
直接使用IBinder、IInterface
IPackageManager packageManager = IPackageManager.Stub.asInterface(Dhizuku.binderWrapper(ServiceManager.getService("package")));
IPackageInstaller packageInstaller = IPackageInstaller.Stub.asInterface(Dhizuku.binderWrapper(packageManager.getPackageInstaller().asBinder()));
// packageInstaller.uninstall(...) // do some code, use the IInterface
间接使用IBinder、IInterface
当然我更喜欢这种方法去使用binderWrapper。比如系统的PackageManager本质上是对IPackageManager的封装,因此我们完全可以替换其中的IPackageManager对象为我们代理过的,从而实现几乎无痛代理。
PackageInstaller packageInstaller = context.getPackageManager().getPakageInstaller();
PackageInstallerHelper.proxy(packageInstaller);
// packageInstaller.uninstall(...) // do some code, just like you are Device Owner
比如UserManager,也是针对IUserManager的封装,同样的方法替换它的mService为经过代理的。
需要注意,Google在Android P之后对部分接口做出了限制(@hide),禁止普通应用调用(禁止反射),需要通过AndroidHiddenApiBypass解除限制。