manager: supports grant root access to cross profile. close #271
This commit is contained in:
@@ -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")
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// IKsuInterface.aidl
|
||||||
|
package me.weishu.kernelsu;
|
||||||
|
|
||||||
|
import android.content.pm.PackageInfo;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
interface IKsuInterface {
|
||||||
|
List<PackageInfo> getPackages();
|
||||||
|
}
|
||||||
@@ -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<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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 =
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
Reference in New Issue
Block a user