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

@@ -3,6 +3,7 @@ package com.bintianqi.owndroid
import android.app.admin.DevicePolicyManager
import android.content.ComponentName
import android.content.Context
import android.os.Build
import android.os.Build.VERSION
import android.os.Bundle
import android.widget.Toast
@@ -40,7 +41,9 @@ import androidx.navigation.compose.rememberNavController
import com.bintianqi.owndroid.dpm.*
import com.bintianqi.owndroid.ui.Animations
import com.bintianqi.owndroid.ui.theme.OwnDroidTheme
import com.rosan.dhizuku.api.Dhizuku
import kotlinx.coroutines.flow.MutableStateFlow
import org.lsposed.hiddenapibypass.HiddenApiBypass
import java.util.Locale
var backToHomeStateFlow = MutableStateFlow(false)
@@ -54,6 +57,12 @@ class MainActivity : FragmentActivity() {
WindowCompat.setDecorFitsSystemWindows(window, false)
super.onCreate(savedInstanceState)
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)) {
showAuth.value = true
}

View File

@@ -1,14 +1,22 @@
package com.bintianqi.owndroid.dpm
import android.annotation.SuppressLint
import android.app.PendingIntent
import android.app.admin.DevicePolicyManager
import android.app.admin.IDevicePolicyManager
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.pm.PackageInstaller
import android.content.pm.PackageManager
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 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 java.io.IOException
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
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.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build.VERSION
import android.os.RemoteException
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.compose.animation.AnimatedVisibility
@@ -38,6 +40,8 @@ import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.Receiver
import com.bintianqi.owndroid.backToHomeStateFlow
import com.bintianqi.owndroid.ui.*
import com.rosan.dhizuku.api.Dhizuku
import com.rosan.dhizuku.api.DhizukuRequestPermissionListener
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@@ -88,12 +92,42 @@ private fun Home(localNavCtrl:NavHostController,listScrollState:ScrollState) {
val context = LocalContext.current
val dpm = context.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager
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)) {
Text(
text = stringResource(R.string.permission),
style = typography.headlineLarge,
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(
R.string.device_admin, stringResource(if(dpm.isAdminActive(receiver)) R.string.activated else R.string.deactivated),
operation = { localNavCtrl.navigate("DeviceAdmin") }