manager: supports grant root access to cross profile. close #271

This commit is contained in:
tiann
2023-04-18 17:38:48 +08:00
parent a3c72c22c1
commit 2bc84014c2
5 changed files with 144 additions and 4 deletions

View File

@@ -81,7 +81,9 @@ dependencies {
implementation("io.coil-kt:coil-compose:2.2.2") implementation("io.coil-kt:coil-compose:2.2.2")
implementation("me.zhanghai.android.appiconloader:appiconloader-coil:1.5.0") implementation("me.zhanghai.android.appiconloader:appiconloader-coil:1.5.0")
implementation("com.github.topjohnwu.libsu:core:5.0.3") val libsuVersion = "5.0.4"
implementation("com.github.topjohnwu.libsu:core:$libsuVersion")
implementation("com.github.topjohnwu.libsu:service:$libsuVersion")
implementation("com.github.alorma:compose-settings-ui-m3:0.22.0") implementation("com.github.alorma:compose-settings-ui-m3:0.22.0")
ksp("io.github.raamcosta.compose-destinations:ksp:$composeDestinationsVersion") ksp("io.github.raamcosta.compose-destinations:ksp:$composeDestinationsVersion")

View File

@@ -0,0 +1,9 @@
// IKsuInterface.aidl
package me.weishu.kernelsu;
import android.content.pm.PackageInfo;
import java.util.List;
interface IKsuInterface {
List<PackageInfo> getPackages();
}

View File

@@ -0,0 +1,79 @@
package me.weishu.kernelsu.ui;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.IBinder;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
import androidx.annotation.NonNull;
import com.topjohnwu.superuser.ipc.RootService;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import me.weishu.kernelsu.IKsuInterface;
/**
* @author weishu
* @date 2023/4/18.
*/
public class KsuService extends RootService {
private static final String TAG = "KsuService";
class Stub extends IKsuInterface.Stub {
@Override
public List<PackageInfo> getPackages() {
List<PackageInfo> list = getInstalledPackagesAll();
Log.i(TAG, "getPackages: " + list.size());
return list;
}
}
@Override
public IBinder onBind(@NonNull Intent intent) {
return new Stub();
}
List<Integer> getUserIds() {
List<Integer> result = new ArrayList<>();
UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
List<UserHandle> userProfiles = um.getUserProfiles();
for (UserHandle userProfile : userProfiles) {
int userId = userProfile.hashCode();
if (userId == 0) {
continue;
}
result.add(userProfile.hashCode());
}
return result;
}
ArrayList<PackageInfo> getInstalledPackagesAll() {
ArrayList<PackageInfo> packages = new ArrayList<>();
for (Integer userId : getUserIds()) {
Log.i(TAG, "getInstalledPackagesAll: " + userId);
packages.addAll(getInstalledPackagesAsUser(userId));
}
return packages;
}
List<PackageInfo> getInstalledPackagesAsUser(int userId) {
try {
PackageManager pm = getPackageManager();
Method getInstalledPackagesAsUser = pm.getClass().getDeclaredMethod("getInstalledPackagesAsUser", int.class, int.class);
return (List<PackageInfo>) getInstalledPackagesAsUser.invoke(pm, 0, userId);
} catch (Throwable e) {
Log.e(TAG, "err", e);
}
return new ArrayList<>();
}
}

View File

@@ -108,7 +108,7 @@ fun SuperUserScreen() {
val failMessage = stringResource(R.string.superuser_failed_to_grant_root) val failMessage = stringResource(R.string.superuser_failed_to_grant_root)
LazyColumn(Modifier.fillMaxSize()) { LazyColumn(Modifier.fillMaxSize()) {
items(viewModel.appList, key = { it.packageName }) { app -> items(viewModel.appList, key = { it.packageName + it.uid }) { app ->
var isChecked by rememberSaveable(app) { mutableStateOf(app.onAllowList) } var isChecked by rememberSaveable(app) { mutableStateOf(app.onAllowList) }
val dialogHost = LocalDialogHost.current val dialogHost = LocalDialogHost.current
val content = val content =

View File

@@ -1,8 +1,11 @@
package me.weishu.kernelsu.ui.viewmodel package me.weishu.kernelsu.ui.viewmodel
import android.content.ComponentName
import android.content.Intent
import android.content.ServiceConnection
import android.content.pm.ApplicationInfo import android.content.pm.ApplicationInfo
import android.content.pm.PackageInfo import android.content.pm.PackageInfo
import android.graphics.drawable.Drawable import android.os.IBinder
import android.os.SystemClock import android.os.SystemClock
import android.util.Log import android.util.Log
import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.derivedStateOf
@@ -10,13 +13,19 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import me.weishu.kernelsu.IKsuInterface
import me.weishu.kernelsu.Natives import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.ksuApp import me.weishu.kernelsu.ksuApp
import me.weishu.kernelsu.ui.KsuService
import me.weishu.kernelsu.ui.util.HanziToPinyin import me.weishu.kernelsu.ui.util.HanziToPinyin
import me.weishu.kernelsu.ui.util.KsuCli
import java.text.Collator import java.text.Collator
import java.util.* import java.util.*
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
class SuperUserViewModel : ViewModel() { class SuperUserViewModel : ViewModel() {
@@ -62,7 +71,44 @@ class SuperUserViewModel : ViewModel() {
} }
} }
private suspend inline fun connectKsuService(
crossinline onDisconnect: () -> Unit = {}
): Pair<IBinder, ServiceConnection> = suspendCoroutine {
val connection = object : ServiceConnection {
override fun onServiceDisconnected(name: ComponentName?) {
onDisconnect()
}
override fun onServiceConnected(name: ComponentName?, binder: IBinder?) {
it.resume(binder as IBinder to this)
}
}
val intent = Intent(ksuApp, KsuService::class.java);
val task = KsuService.bindOrTask(
intent,
Shell.EXECUTOR,
connection,
)
val shell = KsuCli.SHELL
task?.let { it1 -> shell.execTask(it1) }
}
private fun stopKsuService() {
val intent = Intent(ksuApp, KsuService::class.java);
KsuService.stop(intent)
}
suspend fun fetchAppList() { suspend fun fetchAppList() {
val result = connectKsuService {
Log.w(TAG, "KsuService disconnected")
}
val binder = result.first
val extraPackages = IKsuInterface.Stub.asInterface(binder).packages
stopKsuService()
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
isRefreshing = true isRefreshing = true
val pm = ksuApp.packageManager val pm = ksuApp.packageManager
@@ -71,7 +117,11 @@ class SuperUserViewModel : ViewModel() {
Log.i(TAG, "allowList: $allowList") Log.i(TAG, "allowList: $allowList")
Log.i(TAG, "denyList: $denyList") Log.i(TAG, "denyList: $denyList")
val start = SystemClock.elapsedRealtime() val start = SystemClock.elapsedRealtime()
apps = pm.getInstalledPackages(0).map {
val packages = pm.getInstalledPackages(0)
packages.addAll(extraPackages)
apps = packages.map {
val appInfo = it.applicationInfo val appInfo = it.applicationInfo
val uid = appInfo.uid val uid = appInfo.uid
AppInfo( AppInfo(