initialize Dhizuku, get DevicePolicyManager using binder wrapper

This commit is contained in:
BinTianqi
2024-07-20 19:07:25 +08:00
parent 7adac7a11d
commit b6d7844732
9 changed files with 103 additions and 0 deletions

View File

@@ -106,6 +106,8 @@ dependencies {
implementation(libs.androidx.navigation.compose) implementation(libs.androidx.navigation.compose)
implementation(libs.shizuku.provider) implementation(libs.shizuku.provider)
implementation(libs.shizuku.api) implementation(libs.shizuku.api)
implementation(libs.dhizuku.api)
implementation(libs.androidx.biometric) implementation(libs.androidx.biometric)
implementation(libs.androidx.fragment) implementation(libs.androidx.fragment)
implementation(libs.hiddenApiBypass)
} }

View File

@@ -0,0 +1,13 @@
package android.app.admin;
import android.os.Binder;
import android.os.IBinder;
import android.os.IInterface;
public interface IDevicePolicyManager extends IInterface {
abstract class Stub extends Binder implements IDevicePolicyManager {
public static IDevicePolicyManager asInterface(IBinder obj) {
throw new UnsupportedOperationException();
}
}
}

View File

@@ -3,6 +3,7 @@ package com.bintianqi.owndroid
import android.app.admin.DevicePolicyManager import android.app.admin.DevicePolicyManager
import android.content.ComponentName import android.content.ComponentName
import android.content.Context import android.content.Context
import android.os.Build
import android.os.Build.VERSION import android.os.Build.VERSION
import android.os.Bundle import android.os.Bundle
import android.widget.Toast import android.widget.Toast
@@ -40,7 +41,9 @@ import androidx.navigation.compose.rememberNavController
import com.bintianqi.owndroid.dpm.* import com.bintianqi.owndroid.dpm.*
import com.bintianqi.owndroid.ui.Animations import com.bintianqi.owndroid.ui.Animations
import com.bintianqi.owndroid.ui.theme.OwnDroidTheme import com.bintianqi.owndroid.ui.theme.OwnDroidTheme
import com.rosan.dhizuku.api.Dhizuku
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import org.lsposed.hiddenapibypass.HiddenApiBypass
import java.util.Locale import java.util.Locale
var backToHomeStateFlow = MutableStateFlow(false) var backToHomeStateFlow = MutableStateFlow(false)
@@ -54,6 +57,12 @@ class MainActivity : FragmentActivity() {
WindowCompat.setDecorFitsSystemWindows(window, false) WindowCompat.setDecorFitsSystemWindows(window, false)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
val sharedPref = applicationContext.getSharedPreferences("data", Context.MODE_PRIVATE) val sharedPref = applicationContext.getSharedPreferences("data", Context.MODE_PRIVATE)
if (sharedPref.getBoolean("dhizuku", false)) {
if (VERSION.SDK_INT >= 28) HiddenApiBypass.setHiddenApiExemptions("")
if(!Dhizuku.init(applicationContext)) {
Toast.makeText(applicationContext, R.string.failed_to_init_dhizuku, Toast.LENGTH_SHORT).show()
}
}
if(sharedPref.getBoolean("auth", false)) { if(sharedPref.getBoolean("auth", false)) {
showAuth.value = true showAuth.value = true
} }

View File

@@ -1,14 +1,22 @@
package com.bintianqi.owndroid.dpm package com.bintianqi.owndroid.dpm
import android.annotation.SuppressLint
import android.app.PendingIntent import android.app.PendingIntent
import android.app.admin.DevicePolicyManager import android.app.admin.DevicePolicyManager
import android.app.admin.IDevicePolicyManager
import android.content.ComponentName import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageInstaller import android.content.pm.PackageInstaller
import android.content.pm.PackageManager
import android.os.Build.VERSION import android.os.Build.VERSION
import androidx.activity.ComponentActivity.CONTEXT_IGNORE_SECURITY
import androidx.activity.ComponentActivity.DEVICE_POLICY_SERVICE
import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.ActivityResultLauncher
import com.bintianqi.owndroid.PackageInstallerReceiver import com.bintianqi.owndroid.PackageInstallerReceiver
import com.rosan.dhizuku.api.Dhizuku
import com.rosan.dhizuku.api.Dhizuku.binderWrapper
import com.rosan.dhizuku.api.DhizukuBinderWrapper
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import java.io.IOException import java.io.IOException
import java.io.InputStream import java.io.InputStream
@@ -46,3 +54,26 @@ fun installPackage(context: Context, inputStream: InputStream) {
val pendingIntent = PendingIntent.getBroadcast(context, sessionId, intent, PendingIntent.FLAG_IMMUTABLE).intentSender val pendingIntent = PendingIntent.getBroadcast(context, sessionId, intent, PendingIntent.FLAG_IMMUTABLE).intentSender
session.commit(pendingIntent) session.commit(pendingIntent)
} }
@SuppressLint("PrivateApi")
fun binderWrapperDevicePolicyManager(appContext: Context): DevicePolicyManager {
try {
val context = appContext.createPackageContext(Dhizuku.getOwnerComponent().packageName, CONTEXT_IGNORE_SECURITY)
val manager = context.getSystemService(DEVICE_POLICY_SERVICE) as DevicePolicyManager
val field = manager.javaClass.getDeclaredField("mService")
field.isAccessible = true
val oldInterface = field[manager] as IDevicePolicyManager
if (oldInterface is DhizukuBinderWrapper) return manager
val oldBinder = oldInterface.asBinder()
val newBinder = binderWrapper(oldBinder)
val newInterface = IDevicePolicyManager.Stub.asInterface(newBinder)
field[manager] = newInterface
return manager
} catch (e: NoSuchFieldException) {
throw RuntimeException(e)
} catch (e: IllegalAccessException) {
throw RuntimeException(e)
} catch (e: PackageManager.NameNotFoundException) {
throw RuntimeException(e)
}
}

View File

@@ -6,7 +6,9 @@ import android.content.ActivityNotFoundException
import android.content.ComponentName import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build.VERSION import android.os.Build.VERSION
import android.os.RemoteException
import android.widget.Toast import android.widget.Toast
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
@@ -38,6 +40,8 @@ import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.Receiver import com.bintianqi.owndroid.Receiver
import com.bintianqi.owndroid.backToHomeStateFlow import com.bintianqi.owndroid.backToHomeStateFlow
import com.bintianqi.owndroid.ui.* import com.bintianqi.owndroid.ui.*
import com.rosan.dhizuku.api.Dhizuku
import com.rosan.dhizuku.api.DhizukuRequestPermissionListener
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -88,12 +92,42 @@ private fun Home(localNavCtrl:NavHostController,listScrollState:ScrollState) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager val dpm = context.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager
val receiver = ComponentName(context, Receiver::class.java) val receiver = ComponentName(context, Receiver::class.java)
val sharedPref = LocalContext.current.getSharedPreferences("data", Context.MODE_PRIVATE)
var dhizukuStatus by remember { mutableStateOf(sharedPref.getBoolean("dhizuku", false)) }
Column(modifier = Modifier.fillMaxSize().verticalScroll(listScrollState)) { Column(modifier = Modifier.fillMaxSize().verticalScroll(listScrollState)) {
Text( Text(
text = stringResource(R.string.permission), text = stringResource(R.string.permission),
style = typography.headlineLarge, style = typography.headlineLarge,
modifier = Modifier.padding(top = 8.dp, bottom = 5.dp, start = 15.dp) modifier = Modifier.padding(top = 8.dp, bottom = 5.dp, start = 15.dp)
) )
SwitchItem(
R.string.dhizuku, "", null,
{ dhizukuStatus },
{
if(!it) {
sharedPref.edit().putBoolean("dhizuku", false).apply()
dhizukuStatus = sharedPref.getBoolean("dhizuku", false)
return@SwitchItem
}
Dhizuku.init(context)
if(Dhizuku.isPermissionGranted()) {
sharedPref.edit().putBoolean("dhizuku", true).apply()
dhizukuStatus = sharedPref.getBoolean("dhizuku", false)
} else {
Dhizuku.requestPermission(object: DhizukuRequestPermissionListener() {
@Throws(RemoteException::class)
override fun onRequestPermission(grantResult: Int) {
if(grantResult == PackageManager.PERMISSION_GRANTED) {
sharedPref.edit().putBoolean("dhizuku", true).apply()
dhizukuStatus = sharedPref.getBoolean("dhizuku", false)
} else {
Toast.makeText(context, R.string.permission_not_granted, Toast.LENGTH_SHORT).show()
}
}
})
}
}
)
SubPageItem( SubPageItem(
R.string.device_admin, stringResource(if(dpm.isAdminActive(receiver)) R.string.activated else R.string.deactivated), R.string.device_admin, stringResource(if(dpm.isAdminActive(receiver)) R.string.activated else R.string.deactivated),
operation = { localNavCtrl.navigate("DeviceAdmin") } operation = { localNavCtrl.navigate("DeviceAdmin") }

View File

@@ -99,6 +99,9 @@
<string name="onDisabled">OwnDroid: Devre Dışı</string> <string name="onDisabled">OwnDroid: Devre Dışı</string>
<string name="create_work_profile_success">OwnDroid: İş Profili Başarıyla Oluşturuldu</string> <string name="create_work_profile_success">OwnDroid: İş Profili Başarıyla Oluşturuldu</string>
<!--Dhizuku-->
<string name="permission_not_granted">Permission not granted</string> <!--TODO-->
<string name="failed_to_init_dhizuku">Failed to initialize Dhizuku</string> <!--TODO-->
<!--Shizuku--> <!--Shizuku-->
<string name="check_shizuku">İzni Kontrol Et</string> <string name="check_shizuku">İzni Kontrol Et</string>
<string name="list_owners">Sahipleri Listele</string> <string name="list_owners">Sahipleri Listele</string>

View File

@@ -94,6 +94,9 @@
<string name="onDisabled">OwnDroid已禁用</string> <string name="onDisabled">OwnDroid已禁用</string>
<string name="create_work_profile_success">OwnDroid创建工作资料成功</string> <string name="create_work_profile_success">OwnDroid创建工作资料成功</string>
<!--Dhizuku-->
<string name="permission_not_granted">未授权</string>
<string name="failed_to_init_dhizuku">Dhizuku初始化失败</string>
<!--Shizuku--> <!--Shizuku-->
<string name="check_shizuku">检查Shizuku</string> <string name="check_shizuku">检查Shizuku</string>
<string name="list_owners">列出Owners</string> <string name="list_owners">列出Owners</string>

View File

@@ -101,6 +101,10 @@
<string name="onDisabled">OwnDroid: Disabled</string> <string name="onDisabled">OwnDroid: Disabled</string>
<string name="create_work_profile_success">OwnDroid: Create work profile success</string> <string name="create_work_profile_success">OwnDroid: Create work profile success</string>
<!--Dhizuku-->
<string name="dhizuku" translatable="false">Dhizuku</string>
<string name="permission_not_granted">Permission not granted</string>
<string name="failed_to_init_dhizuku">Failed to initialize Dhizuku</string>
<!--Shizuku--> <!--Shizuku-->
<string name="shizuku" translatable="false">Shizuku</string> <string name="shizuku" translatable="false">Shizuku</string>
<string name="check_shizuku">Check permission</string> <string name="check_shizuku">Check permission</string>

View File

@@ -10,6 +10,8 @@ accompanist-drawablepainter = "0.35.0-alpha"
shizuku = "13.1.5" shizuku = "13.1.5"
biometric = "1.2.0-alpha05" biometric = "1.2.0-alpha05"
fragment = "1.8.0-beta01" fragment = "1.8.0-beta01"
dhizuku = "2.5.2"
hiddenApiBypass = "4.3"
[libraries] [libraries]
androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activity-compose" } androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activity-compose" }
@@ -23,6 +25,8 @@ androidx-biometric = { group = "androidx.biometric", name = "biometric", version
shizuku-provider = { module = "dev.rikka.shizuku:provider", version.ref = "shizuku" } shizuku-provider = { module = "dev.rikka.shizuku:provider", version.ref = "shizuku" }
shizuku-api = { module = "dev.rikka.shizuku:api", version.ref = "shizuku" } shizuku-api = { module = "dev.rikka.shizuku:api", version.ref = "shizuku" }
dhizuku-api = { module = "io.github.iamr0s:Dhizuku-API", version.ref = "dhizuku" }
hiddenApiBypass = { module = "org.lsposed.hiddenapibypass:hiddenapibypass", version.ref = "hiddenApiBypass" }
androidx-fragment = { group = "androidx.fragment", name = "fragment", version.ref = "fragment" } androidx-fragment = { group = "androidx.fragment", name = "fragment", version.ref = "fragment" }
[plugins] [plugins]