Add cmd tool

This commit is contained in:
RikkaW
2021-03-21 16:24:30 +08:00
parent e9d2c641b6
commit ab19fc25ea
19 changed files with 532 additions and 80 deletions

5
.gitattributes vendored
View File

@ -1 +1,4 @@
*.sh text eol=lf
* text=auto eol=lf
*.bat text eol=crlf
*.jar binary

1
cmd/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

64
cmd/build.gradle Normal file
View File

@ -0,0 +1,64 @@
plugins {
id 'com.android.application'
}
android {
compileSdkVersion rootProject.ext.targetSdkVersion
ndkVersion rootProject.ext.ndkVersion
defaultConfig {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode rootProject.ext.versionCode
versionName rootProject.ext.versionName
}
buildTypes {
debug {
multiDexEnabled false
}
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
android.applicationVariants.all { variant ->
variant.outputs.all {
outputFileName = "shizuku-v${versionName}.apk"
def outDir = new File(rootDir, "out")
def mappingPath = new File(outDir, "mapping").absolutePath
def dexPath = new File(outDir, "cmd").absolutePath
variant.assembleProvider.get().doLast {
if (variant.getBuildType().isMinifyEnabled()) {
copy {
from variant.mappingFileProvider.get()
into mappingPath
rename { String fileName ->
mappingPath + File.separator + "cmd-v${variant.versionName}.txt"
}
}
}
copy {
def file = zipTree(file(outputFile)).matching { include 'classes*.dex' }.singleFile
from file
into dexPath
rename { String fileName ->
fileName.replace(file.getName(), "shizuku.dex")
}
}
}
}
}
dependencies {
implementation project(':api')
compileOnly project(':hidden-api-common')
implementation project(':hidden-api-common-bridge')
implementation project(':hidden-api-21-bridge')
}

3
cmd/proguard-rules.pro vendored Normal file
View File

@ -0,0 +1,3 @@
-keep class rikka.shizuku.cmd.ShizukuCmd {
public static void main(java.lang.String[]);
}

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="rikka.shizuku.cmd" />

View File

@ -0,0 +1,270 @@
package rikka.shizuku.cmd;
import android.app.IActivityManager;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Looper;
import android.os.Parcel;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.system.Os;
import android.text.TextUtils;
import android.util.Log;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import hidden.HiddenApiBridgeV23;
import rikka.shizuku.Shizuku;
public class ShizukuCmd {
private static void requestForBinder(String packageName) throws RemoteException {
Binder binder = new Binder() {
@Override
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
if (code == 1) {
verbose("Received reply");
IBinder binder = data.readStrongBinder();
if (binder != null) {
try {
Shizuku.onBinderReceived(binder, packageName);
} catch (Throwable e) {
abort("Please check if the current SHIZUKU_APPLICATION_ID, " + packageName + ", is correct");
}
}
return true;
}
return super.onTransact(code, data, reply, flags);
}
};
IBinder amBinder = ServiceManager.getService("activity");
IActivityManager am;
if (Build.VERSION.SDK_INT >= 26) {
am = IActivityManager.Stub.asInterface(amBinder);
} else {
am = HiddenApiBridgeV23.ActivityManagerNative_asInterface(amBinder);
}
Bundle data = new Bundle();
data.putBinder("binder", binder);
Intent intent = Intent.createChooser(
new Intent("rikka.shizuku.intent.action.REQUEST_BINDER")
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT)
.putExtra("data", data),
"Request binder from Shizuku"
);
verbose("Start activity...");
am.startActivityAsUser(null, packageName, intent, null, null, null, 0, 0, null, null, Os.getuid() / 100000);
}
public static void main(String[] args) {
if (BuildConfig.DEBUG) {
System.out.println("args: " + Arrays.toString(args));
}
if (args.length == 0) {
printHelp();
return;
}
for (String arg : args) {
switch (arg) {
case "--verbose":
verboseMessageAllowed = true;
break;
case "--help":
case "-h":
printHelp();
return;
case "--version":
case "-v":
System.out.println(BuildConfig.VERSION_NAME + " (" + BuildConfig.VERSION_CODE + ")");
return;
}
}
String packageName;
if (Os.getuid() == 2000) {
packageName = "com.android.shell";
} else {
packageName = System.getenv("SHIZUKU_APPLICATION_ID");
if (TextUtils.isEmpty(packageName)) {
abort("SHIZUKU_APPLICATION_ID is not set, set this environment variable to the id of current application (package name)");
}
}
Looper.prepareMainLooper();
verbose("Requesting binder from Shizuku app...");
verbose("If this never ends, please check:");
verbose("1. Shizuku app is install");
verbose("2. If your system or you are using third-party tools to prevent Shizuku app from running");
verbose("3. If this terminal app is in foreground (Android 10 background start activity limitation");
Shizuku.addBinderReceivedListener(() -> {
try {
preExec(args);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
try {
requestForBinder(packageName);
} catch (Throwable e) {
System.out.println(Log.getStackTraceString(e));
abort("Failed to request binder from Shizuku app");
}
Looper.loop();
}
private static void preExec(String[] args) throws InterruptedException {
if (Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED) {
doExec(args);
} else if (Shizuku.shouldShowRequestPermissionRationale()) {
abort("Permission denied, please check Shizuku app");
} else {
System.out.println("[ Requesting permission... ]");
Shizuku.addRequestPermissionResultListener(new Shizuku.OnRequestPermissionResultListener() {
@Override
public void onRequestPermissionResult(int requestCode, int grantResult) {
Shizuku.removeRequestPermissionResultListener(this);
if (grantResult == PackageManager.PERMISSION_GRANTED) {
try {
doExec(args);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
abort("Permission denied, please check Shizuku app");
}
}
});
Shizuku.requestPermission(0);
}
}
private static void doExec(String[] args) throws InterruptedException {
List<String> envList = new ArrayList<>();
for (Map.Entry<String, String> entry : System.getenv().entrySet()) {
envList.add(entry.getKey() + "=" + entry.getValue());
}
String[] env = envList.toArray(new String[0]);
String cwd = new File("").getAbsolutePath();
if (BuildConfig.DEBUG) {
System.out.println("[ " + cwd + " ]");
System.out.println("[ " + Arrays.toString(env) + " ]");
}
verbose("Starting command " + args[0] + "...");
Process process;
InputStream in;
InputStream err;
OutputStream out;
try {
process = Shizuku.newProcess(args, env, cwd);
in = process.getInputStream();
err = process.getErrorStream();
out = process.getOutputStream();
} catch (Throwable e) {
if (BuildConfig.DEBUG) {
e.printStackTrace();
}
abort(e.getMessage());
return;
}
CountDownLatch latch = new CountDownLatch(2);
new TransferThread(in, System.out, latch).start();
new TransferThread(err, System.out, latch).start();
new TransferThread(System.in, out, null).start();
int exitCode = process.waitFor();
latch.await();
verbose("Command " + args[0] + " exited with " + exitCode);
System.exit(exitCode);
}
private static class TransferThread extends Thread {
private final InputStream input;
private final OutputStream output;
private final CountDownLatch latch;
public TransferThread(InputStream input, OutputStream output, CountDownLatch latch) {
this.input = input;
this.output = output;
this.latch = latch;
}
@Override
public void run() {
byte[] buf = new byte[8192];
int len;
try {
while ((len = input.read(buf)) != -1) {
output.write(buf, 0, len);
output.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
if (latch != null) {
latch.countDown();
}
}
}
private static boolean verboseMessageAllowed = false;
private static void verbose(String message) {
if (!verboseMessageAllowed) return;
System.out.println("[ " + message + " ]");
System.out.flush();
}
private static void abort(String message) {
System.err.println("[ " + message + " ]");
System.err.flush();
System.exit(1);
}
private static void printHelp() {
System.out.println("usage: shizuku [OPTION]... [CMD]...\n" +
"Run command through Shizuku.\n\n" +
"Options:\n" +
"-h, --help print this help\n" +
"-v, --version print the version of the shizuku tool\n" +
"--verbose print more messages\n" +
"\n" +
"This file can be used in adb shell or terminal apps.\n" +
"For terminal apps, the environment variable SHIZUKU_APPLICATION_ID needs to be set to the first.");
}
}

View File

@ -51,6 +51,7 @@ android {
}
kotlinOptions {
jvmTarget = "1.8"
useIR = true
}
packagingOptions {
exclude '/META-INF/*.version'
@ -126,11 +127,6 @@ repositories {
includeGroup('com.github.topjohnwu.libsu')
}
}
maven { url 'https://dl.bintray.com/rikkaw/MaterialPreference'
content {
includeGroup('moe.shizuku.preference')
}
}
maven {
url 'https://dl.bintray.com/rikkaw/Libraries'
content {
@ -145,8 +141,8 @@ dependencies {
androidTestImplementation 'androidx.test:runner:1.3.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.2"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.2"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.3"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.3"
//compileOnly project(':hidden-api-common')
implementation project(':hidden-api-common-bridge')
@ -157,7 +153,7 @@ dependencies {
implementation 'androidx.browser:browser:1.3.0'
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.fragment:fragment-ktx:1.3.0'
implementation 'androidx.fragment:fragment-ktx:1.3.1'
implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.0'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.0'
@ -166,13 +162,13 @@ dependencies {
implementation 'com.github.topjohnwu.libsu:core:3.1.1'
implementation 'dev.rikka.rikkax.appcompat:appcompat:1.2.0-rc01'
implementation 'dev.rikka.rikkax.core:core:1.3.0'
implementation 'dev.rikka.rikkax.core:core:1.3.1'
implementation 'dev.rikka.rikkax.material:material:1.6.0'
implementation 'dev.rikka.rikkax.html:html-ktx:1.1.2'
implementation 'dev.rikka.rikkax.recyclerview:recyclerview-adapter:1.2.0'
implementation 'dev.rikka.rikkax.recyclerview:recyclerview-ktx:1.2.0'
implementation 'dev.rikka.rikkax.widget:borderview:1.0.1'
implementation 'dev.rikka.rikkax.preference:simplemenu-preference:1.0.1'
implementation 'dev.rikka.rikkax.preference:simplemenu-preference:1.0.2'
implementation 'rikka.ndk.thirdparty:boringssl:20200911'
implementation 'moe.shizuku.fontprovider:api:10'

View File

@ -67,6 +67,17 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name=".cmd.CmdRequestHandlerActivity"
android:directBootAware="true"
android:excludeFromRecents="true"
android:exported="true"
android:theme="@style/GrantPermissions">
<intent-filter>
<action android:name="rikka.shizuku.intent.action.REQUEST_BINDER" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name=".legacy.LegacyIsNotSupportedActivity"

View File

@ -2,9 +2,13 @@ package moe.shizuku.manager.authorization
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.os.Parcel
import moe.shizuku.manager.BuildConfig
import moe.shizuku.manager.Manifest
import moe.shizuku.manager.utils.Logger.LOGGER
import moe.shizuku.manager.utils.ShizukuSystemApis
import moe.shizuku.server.ServerConstants
import rikka.parcelablelist.ParcelableListSlice
import rikka.shizuku.Shizuku
import java.util.*
@ -14,24 +18,46 @@ object AuthorizationManager {
private const val FLAG_DENIED = 1 shl 2
private const val MASK_PERMISSION = FLAG_ALLOWED or FLAG_DENIED
fun getPackages(pmFlags: Int): List<PackageInfo> {
val allPackages: MutableList<PackageInfo> = ArrayList()
for (user in ShizukuSystemApis.getUsers(useCache = false)) {
private fun getApplications(userId: Int): List<PackageInfo> {
val data = Parcel.obtain()
val reply = Parcel.obtain()
return try {
data.writeInterfaceToken("moe.shizuku.server.IShizukuService")
data.writeInt(userId)
try {
allPackages.addAll(ShizukuSystemApis.getInstalledPackages(pmFlags or PackageManager.GET_PERMISSIONS, user.id))
Shizuku.getBinder()!!.transact(ServerConstants.BINDER_TRANSACTION_getApplications, data, reply, 0)
} catch (e: Throwable) {
LOGGER.w(e, "getInstalledPackages")
throw RuntimeException(e)
}
reply.readException()
@Suppress("UNCHECKED_CAST")
(ParcelableListSlice.CREATOR.createFromParcel(reply) as ParcelableListSlice<PackageInfo>).list!!
} finally {
reply.recycle()
data.recycle()
}
}
fun getPackages(): List<PackageInfo> {
val packages: MutableList<PackageInfo> = ArrayList()
for (pi in allPackages) {
if (pi.requestedPermissions == null) continue
for (p in pi.requestedPermissions) {
if (Manifest.permission.API_V23 == p) {
packages.add(pi)
break
if (Shizuku.isPreV11() || (Shizuku.getVersion() == 11 && Shizuku.getServerPatchVersion() < 3)) {
val allPackages: MutableList<PackageInfo> = ArrayList()
for (user in ShizukuSystemApis.getUsers(useCache = false)) {
try {
allPackages.addAll(ShizukuSystemApis.getInstalledPackages(PackageManager.GET_META_DATA or PackageManager.GET_PERMISSIONS, user.id))
} catch (e: Throwable) {
LOGGER.w(e, "getInstalledPackages")
}
}
for (pi in allPackages) {
if (BuildConfig.APPLICATION_ID == pi.packageName) continue
if (pi.applicationInfo?.metaData?.getBoolean("moe.shizuku.client.V3_SUPPORT") != true) continue
if (pi.requestedPermissions?.contains(Manifest.permission.API_V23) != true) continue
packages.add(pi)
}
} else {
packages.addAll(getApplications(-1))
}
return packages
}

View File

@ -34,7 +34,7 @@ class RequestPermissionActivity : AppActivity() {
}
}
private fun checkPermission(uid: Int, pid: Int, requestCode: Int): Boolean {
private fun checkSelfPermission(): Boolean {
val permission = Shizuku.checkRemotePermission("android.permission.GRANT_RUNTIME_PERMISSIONS") == PackageManager.PERMISSION_GRANTED
if (permission) return true
@ -55,8 +55,6 @@ class RequestPermissionActivity : AppActivity() {
dialog.show()
} catch (ignored: Throwable) {
}
setResult(uid, pid, requestCode, allowed = false, onetime = true)
return false
}
@ -68,10 +66,11 @@ class RequestPermissionActivity : AppActivity() {
val requestCode = intent.getIntExtra("requestCode", -1)
val ai = intent.getParcelableExtra<ApplicationInfo>("applicationInfo")
if (uid == -1 || pid == -1 || ai == null) {
finish()
return
}
if (!checkPermission(uid, pid, requestCode)) {
if (!checkSelfPermission()) {
setResult(uid, pid, requestCode, allowed = false, onetime = true)
return
}

View File

@ -0,0 +1,37 @@
package moe.shizuku.manager.cmd
import android.os.Bundle
import android.os.IBinder
import android.os.Parcel
import moe.shizuku.manager.app.AppActivity
import rikka.shizuku.Shizuku
class CmdRequestHandlerActivity : AppActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (intent.action != "rikka.shizuku.intent.action.REQUEST_BINDER") {
finish()
return
}
val binder = intent.getBundleExtra("data")?.getBinder("binder")
if (binder == null) {
finish()
return
}
val data = Parcel.obtain()
try {
data.writeStrongBinder(Shizuku.getBinder())
binder.transact(1, data, null, IBinder.FLAG_ONEWAY)
} catch (e: Throwable) {
e.printStackTrace()
} finally {
data.recycle()
}
finish()
}
}

View File

@ -40,9 +40,7 @@ class AppsViewModel(context: Context) : ViewModel() {
try {
val list: MutableList<PackageInfo> = ArrayList()
var count = 0
for (pi in AuthorizationManager.getPackages(PackageManager.GET_META_DATA)) {
if (packageName == pi.packageName) continue
if (pi?.applicationInfo?.metaData?.getBoolean("moe.shizuku.client.V3_SUPPORT") != true) continue
for (pi in AuthorizationManager.getPackages()) {
list.add(pi)
if (AuthorizationManager.granted(pi.packageName, pi.applicationInfo.uid)) count++
}
@ -62,8 +60,7 @@ class AppsViewModel(context: Context) : ViewModel() {
try {
val list: MutableList<PackageInfo> = ArrayList()
val packages: MutableList<String> = ArrayList()
for (pi in AuthorizationManager.getPackages(PackageManager.GET_META_DATA)) {
if (packageName == pi.packageName) continue
for (pi in AuthorizationManager.getPackages()) {
list.add(pi)
if (AuthorizationManager.granted(pi.packageName, pi.applicationInfo.uid)) packages.add(pi.packageName)
}

View File

@ -1,12 +0,0 @@
package android.util;
public class Base64 {
public static String encodeToString(byte[] input, int flags) {
return java.util.Base64.getEncoder().encodeToString(input);
}
public static byte[] decode(String str, int flags) {
return java.util.Base64.getDecoder().decode(str);
}
}

View File

@ -1,9 +0,0 @@
package android.util;
public class Log {
public static int d(String tag, String message) {
System.out.println(message);
return 0;
}
}

16
scripts/cmd.sh Normal file
View File

@ -0,0 +1,16 @@
#!/system/bin/sh
BASEDIR=$(dirname "$0")
DEX="$BASEDIR"/shizuku.dex
if [ ! -f "$DEX" ]; then
echo "Cannot find $DEX, please check post-install.sh"
exit 1
fi
if [ ! -r "$DEX" ]; then
echo "Cannot read $DEX, please check post-install.sh"
exit 1
fi
export SHIZUKU_APPLICATION_ID=""
/system/bin/app_process -Djava.class.path="$DEX" /system/bin --nice-name=sui_wrapper rikka.shizuku.cmd.ShizukuCmd "$@"

View File

@ -24,6 +24,7 @@ dependencies {
implementation "androidx.annotation:annotation:1.1.0"
implementation 'com.google.code.gson:gson:2.8.6'
api 'dev.rikka.rikkax.parcelablelist:parcelablelist:1.0.0'
implementation project(':aidl')
implementation project(':shared')

View File

@ -4,9 +4,11 @@ public class ServerConstants {
public static final int MANAGER_APP_NOT_FOUND = 50;
public static final int PATCH_VERSION = 2;
public static final int PATCH_VERSION = 3;
public static final String PERMISSION = "moe.shizuku.manager.permission.API_V23";
public static final String MANAGER_APPLICATION_ID = "moe.shizuku.privileged.api";
public static final String REQUEST_PERMISSION_ACTION = MANAGER_APPLICATION_ID + ".intent.action.REQUEST_PERMISSION";
public static final int BINDER_TRANSACTION_getApplications = 10001;
}

View File

@ -27,6 +27,7 @@ import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@ -47,6 +48,7 @@ import moe.shizuku.server.ktx.IContentProviderKt;
import moe.shizuku.server.utils.OsUtils;
import moe.shizuku.server.utils.UserHandleCompat;
import moe.shizuku.starter.ServiceStarter;
import rikka.parcelablelist.ParcelableListSlice;
import rikka.shizuku.ShizukuApiConstants;
import static moe.shizuku.server.ServerConstants.MANAGER_APPLICATION_ID;
@ -250,7 +252,7 @@ public class ShizukuService extends IShizukuService.Stub {
try {
process = Runtime.getRuntime().exec(cmd, env, dir != null ? new File(dir) : null);
} catch (IOException e) {
throw new RemoteException(e.getMessage());
throw new IllegalStateException(e.getMessage());
}
ClientRecord clientRecord = clientManager.findClient(Binder.getCallingUid(), Binder.getCallingPid());
@ -266,7 +268,7 @@ public class ShizukuService extends IShizukuService.Stub {
try {
return SELinux.getContext();
} catch (Throwable tr) {
throw new RemoteException(tr.getMessage());
throw new IllegalStateException(tr.getMessage());
}
}
@ -277,7 +279,7 @@ public class ShizukuService extends IShizukuService.Stub {
try {
return SystemProperties.get(name, defaultValue);
} catch (Throwable tr) {
throw new RemoteException(tr.getMessage());
throw new IllegalStateException(tr.getMessage());
}
}
@ -288,7 +290,7 @@ public class ShizukuService extends IShizukuService.Stub {
try {
SystemProperties.set(name, value);
} catch (Throwable tr) {
throw new RemoteException(tr.getMessage());
throw new IllegalStateException(tr.getMessage());
}
}
@ -746,33 +748,39 @@ public class ShizukuService extends IShizukuService.Stub {
}
}
private int getFlagsForUidInternal(int uid, int mask, boolean allowRuntimePermission) {
Config.PackageEntry entry = configManager.find(uid);
if (entry != null) {
return entry.flags & mask;
}
if (allowRuntimePermission && (mask & Config.MASK_PERMISSION) != 0) {
int userId = UserHandleCompat.getUserId(uid);
for (String packageName : SystemService.getPackagesForUidNoThrow(uid)) {
PackageInfo pi = SystemService.getPackageInfoNoThrow(packageName, PackageManager.GET_PERMISSIONS, userId);
if (pi == null || pi.requestedPermissions == null || !ArraysKt.contains(pi.requestedPermissions, PERMISSION)) {
continue;
}
try {
if (SystemService.checkPermission(PERMISSION, uid) == PackageManager.PERMISSION_GRANTED) {
return Config.FLAG_ALLOWED;
}
} catch (Throwable e) {
LOGGER.w("getFlagsForUid");
}
}
}
return 0;
}
@Override
public int getFlagsForUid(int uid, int mask) {
if (UserHandleCompat.getAppId(Binder.getCallingUid()) != managerAppId) {
LOGGER.w("updateFlagsForUid is allowed to be called only from the manager");
return 0;
}
Config.PackageEntry entry = configManager.find(uid);
if (entry != null) {
return entry.flags & mask;
}
int userId = UserHandleCompat.getUserId(uid);
for (String packageName : SystemService.getPackagesForUidNoThrow(uid)) {
PackageInfo pi = SystemService.getPackageInfoNoThrow(packageName, PackageManager.GET_PERMISSIONS, userId);
if (pi == null || pi.requestedPermissions == null || !ArraysKt.contains(pi.requestedPermissions, PERMISSION)) {
continue;
}
try {
if (SystemService.checkPermission(PERMISSION, uid) == PackageManager.PERMISSION_GRANTED) {
return Config.FLAG_ALLOWED;
}
} catch (Throwable e) {
LOGGER.w("getFlagsForUid");
}
}
return 0;
return getFlagsForUidInternal(uid, mask, true);
}
@Override
@ -834,6 +842,36 @@ public class ShizukuService extends IShizukuService.Stub {
record.setBinder(binder);
}
private ParcelableListSlice<PackageInfo> getApplications(int userId) {
List<PackageInfo> list = new ArrayList<>();
List<Integer> users = new ArrayList<>();
if (userId == -1) {
users = SystemService.getUserIdsNoThrow();
} else {
users.add(userId);
}
for (int user : users) {
for (PackageInfo pi : SystemService.getInstalledPackagesNoThrow(PackageManager.GET_META_DATA | PackageManager.GET_PERMISSIONS, user)) {
if (Objects.equals(MANAGER_APPLICATION_ID, pi.packageName)) continue;
if (pi.applicationInfo == null) continue;
int uid = pi.applicationInfo.uid;
int flags = getFlagsForUidInternal(uid, Config.MASK_PERMISSION, false);
if (flags != 0) {
list.add(pi);
} else if (pi.applicationInfo.metaData != null
&& pi.applicationInfo.metaData.getBoolean("moe.shizuku.client.V3_SUPPORT", false)
&& pi.requestedPermissions != null
&& ArraysKt.contains(pi.requestedPermissions, PERMISSION)) {
list.add(pi);
}
}
}
return new ParcelableListSlice<>(list);
}
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
//LOGGER.d("transact: code=%d, calling uid=%d", code, Binder.getCallingUid());
@ -841,6 +879,13 @@ public class ShizukuService extends IShizukuService.Stub {
data.enforceInterface(ShizukuApiConstants.BINDER_DESCRIPTOR);
transactRemote(data, reply, flags);
return true;
} else if (code == ServerConstants.BINDER_TRANSACTION_getApplications) {
data.enforceInterface(ShizukuApiConstants.BINDER_DESCRIPTOR);
int userId = data.readInt();
ParcelableListSlice<PackageInfo> result = getApplications(userId);
reply.writeNoException();
result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
return true;
}
return super.onTransact(code, data, reply, flags);
}

View File

@ -1,5 +1,5 @@
include ':hidden-api-common', ':hidden-api-common-bridge', ':hidden-api-21', ':hidden-api-21-bridge'
include ':server', ':starter'
include ':server', ':starter', ':cmd'
include ':manager'
def root = "api"