Integrate Dhizuku server

This commit is contained in:
BinTianqi
2025-05-24 19:36:43 +08:00
parent b547c8add8
commit ef800fd6bd
14 changed files with 299 additions and 12 deletions

View File

@@ -0,0 +1,147 @@
package com.bintianqi.owndroid
import android.content.ComponentName
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.size
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.google.accompanist.drawablepainter.rememberDrawablePainter
import com.rosan.dhizuku.aidl.IDhizukuClient
import com.rosan.dhizuku.aidl.IDhizukuRequestPermissionListener
import com.rosan.dhizuku.server_api.DhizukuProvider
import com.rosan.dhizuku.server_api.DhizukuService
import com.rosan.dhizuku.shared.DhizukuVariables
import kotlinx.coroutines.delay
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
private const val TAG = "DhizukuServer"
const val DHIZUKU_CLIENTS_FILE = "dhizuku_clients.json"
class MyDhizukuProvider(): DhizukuProvider() {
override fun onCreateService(client: IDhizukuClient): DhizukuService? {
Log.d(TAG, "Creating MyDhizukuService")
return if (SharedPrefs(context!!).dhizukuServer) MyDhizukuService(context!!, MyAdminComponent, client) else null
}
}
class MyDhizukuService(context: Context, admin: ComponentName, client: IDhizukuClient) :
DhizukuService(context, admin, client) {
override fun checkCallingPermission(func: String?, callingUid: Int, callingPid: Int): Boolean {
if (!SharedPrefs(mContext).dhizukuServer) return false
val pm = mContext.packageManager
val packageInfo = pm.getPackageInfo(
pm.getNameForUid(callingUid) ?: return false,
if (Build.VERSION.SDK_INT >= 28) PackageManager.GET_SIGNING_CERTIFICATES else PackageManager.GET_SIGNATURES
)
val file = mContext.filesDir.resolve(DHIZUKU_CLIENTS_FILE)
val clients = Json.decodeFromString<List<DhizukuClientInfo>>(file.readText())
val signature = getPackageSignature(packageInfo)
val hasPermission = DhizukuClientInfo(callingUid, signature, true) in clients
Log.d(TAG, "UID $callingUid, PID $callingPid, has permission: $hasPermission")
return hasPermission
}
override fun getVersionName() = "1.0"
}
class DhizukuActivity : ComponentActivity() {
@OptIn(ExperimentalStdlibApi::class)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (!SharedPrefs(this).dhizukuServer) {
finish()
return
}
val bundle = intent.extras ?: return
val uid = bundle.getInt(DhizukuVariables.PARAM_CLIENT_UID, -1)
if (uid == -1) return
val binder = bundle.getBinder(DhizukuVariables.PARAM_CLIENT_REQUEST_PERMISSION_BINDER) ?: return
val listener = IDhizukuRequestPermissionListener.Stub.asInterface(binder)
val packageName = packageManager.getPackagesForUid(uid)?.first() ?: return
val packageInfo = packageManager.getPackageInfo(
packageName,
if (Build.VERSION.SDK_INT >= 28) PackageManager.GET_SIGNING_CERTIFICATES else PackageManager.GET_SIGNATURES
)
val appInfo = packageManager.getApplicationInfo(packageName, 0)
val icon = appInfo.loadIcon(packageManager)
val label = appInfo.loadLabel(packageManager).toString()
fun close(grantPermission: Boolean) {
val file = filesDir.resolve(DHIZUKU_CLIENTS_FILE)
val clients = Json.decodeFromString<MutableList<DhizukuClientInfo>>(file.readText())
val index = clients.indexOfFirst { it.uid == uid }
val clientInfo = DhizukuClientInfo(uid, getPackageSignature(packageInfo), grantPermission)
if (index == -1) clients += clientInfo
else clients[index] = clientInfo
file.writeText(Json.encodeToString(clients))
finish()
listener.onRequestPermission(
if (grantPermission) PackageManager.PERMISSION_GRANTED else PackageManager.PERMISSION_DENIED
)
}
setContent {
AlertDialog(
icon = {
Image(rememberDrawablePainter(icon), null, Modifier.size(35.dp))
},
title = {
Text(stringResource(R.string.request_permission))
},
text = {
Text("$label\n($packageName)")
},
confirmButton = {
var time by remember { mutableIntStateOf(3) }
LaunchedEffect(Unit) {
(1..3).forEach {
delay(1000)
time -= 1
}
}
TextButton({
close(true)
}, enabled = time == 0) {
val append = if (time > 0) " (${time}s)" else ""
Text(stringResource(R.string.allow) + append)
}
},
dismissButton = {
TextButton({
close(false)
}) {
Text(stringResource(R.string.reject))
}
},
onDismissRequest = {
finish()
}
)
}
}
}
@Serializable
data class DhizukuClientInfo(
val uid: Int,
val signature: String?,
val allow: Boolean
)