Skip to content

Commit

Permalink
feat: Support for ops permissions
Browse files Browse the repository at this point in the history
Change-Id: I4fdc6d10c1b8b4ad5465d105704655875ae63035
  • Loading branch information
XayahSuSuSu committed Oct 27, 2024
1 parent 7a54674 commit c963d51
Show file tree
Hide file tree
Showing 26 changed files with 314 additions and 52 deletions.
3 changes: 3 additions & 0 deletions dex/app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
@Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed
plugins {
alias(libs.plugins.androidApplication)
alias(libs.plugins.refine)
}

android {
Expand Down Expand Up @@ -37,4 +38,6 @@ dependencies {
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.test.ext.junit)
androidTestImplementation(libs.espresso.core)

compileOnly(project(":hiddenapi"))
}
1 change: 0 additions & 1 deletion dex/app/src/main/java/com/xayah/dex/HiddenApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.lang.reflect.InvocationTargetException;
import java.util.Objects;

public class HiddenApi {
public static Context getContext() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Expand Down
46 changes: 44 additions & 2 deletions dex/app/src/main/java/com/xayah/dex/HiddenApiUtil.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.xayah.dex;

import android.annotation.SuppressLint;
import android.app.AppOpsManagerHidden;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
Expand All @@ -9,6 +11,8 @@
import androidx.core.content.pm.PermissionInfoCompat;

import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import java.util.stream.Collectors;

public class HiddenApiUtil {

Expand All @@ -23,6 +27,8 @@ private static void onHelp() {
System.out.println(" grantRuntimePermission USER_ID PACKAGE PERM_NAME PERM_NAME PERM_NAME ...");
System.out.println();
System.out.println(" revokeRuntimePermission USER_ID PACKAGE PERM_NAME PERM_NAME PERM_NAME ...");
System.out.println();
System.out.println(" setOpsMode USER_ID PACKAGE OP MODE");
}

private static void onCommand(String cmd, String[] args) {
Expand All @@ -35,6 +41,8 @@ private static void onCommand(String cmd, String[] args) {
grantRuntimePermission(args);
case "revokeRuntimePermission":
revokeRuntimePermission(args);
case "setOpsMode":
setOpsMode(args);
case "help":
onHelp();
default:
Expand Down Expand Up @@ -67,25 +75,40 @@ private static void getPackageUid(String[] args) {
}
}

@SuppressLint("ServiceCast")
private static void getRuntimePermissions(String[] args) {
try {
Context ctx = HiddenApi.getContext();
PackageManager packageManager = ctx.getPackageManager();
AppOpsManagerHidden appOpsManager = (AppOpsManagerHidden) ctx.getSystemService(Context.APP_OPS_SERVICE);
int userId = Integer.parseInt(args[1]);
String packageName = args[2];
PackageInfo packageInfo = HiddenApi.getPackageInfoAsUser(packageManager, packageName, PackageManager.GET_PERMISSIONS, userId);
String[] requestedPermissions = packageInfo.requestedPermissions;
int[] requestedPermissionsFlags = packageInfo.requestedPermissionsFlags;
AppOpsManagerHidden.PackageOps ops = appOpsManager.getOpsForPackage(packageInfo.applicationInfo.uid, packageName, null).get(0);
Map<Integer, Integer> opsMap = null;
if (ops != null) {
opsMap = ops.getOps().stream().collect(Collectors.toMap(AppOpsManagerHidden.OpEntry::getOp, AppOpsManagerHidden.OpEntry::getMode));
}
for (int i = 0; i < requestedPermissions.length; i++) {
try {
PermissionInfo permissionInfo = packageManager.getPermissionInfo(requestedPermissions[i], 0);
int protection = PermissionInfoCompat.getProtection(permissionInfo);
int protectionFlags = PermissionInfoCompat.getProtectionFlags(permissionInfo);
boolean isGranted = (requestedPermissionsFlags[i] & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0;
if (protection == PermissionInfo.PROTECTION_DANGEROUS || (protectionFlags & PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0) {
System.out.println(requestedPermissions[i] + " " + isGranted);
int op = AppOpsManagerHidden.permissionToOpCode(requestedPermissions[i]);
int mode = AppOpsManagerHidden.MODE_IGNORED;
if (opsMap != null) {
mode = opsMap.getOrDefault(op, AppOpsManagerHidden.MODE_IGNORED);
}
if ((op != AppOpsManagerHidden.OP_NONE)
|| (protection == PermissionInfo.PROTECTION_DANGEROUS || (protectionFlags & PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0)) {
System.out.println(requestedPermissions[i] + " " + isGranted + " " + op + " " + mode);
}
} catch (PackageManager.NameNotFoundException ignored) {
} catch (Exception e) {
e.printStackTrace(System.out);
}
}
System.exit(0);
Expand Down Expand Up @@ -140,4 +163,23 @@ private static void revokeRuntimePermission(String[] args) {
System.exit(1);
}
}

@SuppressLint("ServiceCast")
private static void setOpsMode(String[] args) {
try {
Context ctx = HiddenApi.getContext();
PackageManager packageManager = ctx.getPackageManager();
AppOpsManagerHidden appOpsManager = (AppOpsManagerHidden) ctx.getSystemService(Context.APP_OPS_SERVICE);
int userId = Integer.parseInt(args[1]);
String packageName = args[2];
int op = Integer.parseInt(args[3]);
int mode = Integer.parseInt(args[4]);
PackageInfo packageInfo = HiddenApi.getPackageInfoAsUser(packageManager, packageName, PackageManager.GET_PERMISSIONS, userId);
appOpsManager.setMode(op, packageInfo.applicationInfo.uid, packageName, mode);
System.exit(0);
} catch (Exception e) {
e.printStackTrace(System.out);
System.exit(1);
}
}
}
1 change: 1 addition & 0 deletions dex/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
@Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed
plugins {
alias(libs.plugins.androidApplication) apply false
alias(libs.plugins.androidLibrary) apply false
}
true // Needed to make the Suppress annotation work for the plugins block
6 changes: 5 additions & 1 deletion dex/gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@ junit = "4.13.2"
androidx-test-ext-junit = "1.1.5"
espresso-core = "3.5.1"
appcompat = "1.6.1"
refine = "4.4.0"

[libraries]
junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-test-ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-test-ext-junit" }
espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espresso-core" }
appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
refine-annotation = { module = "dev.rikka.tools.refine:annotation", version.ref = "refine" }
refine-annotation-processor = { module = "dev.rikka.tools.refine:annotation-processor", version.ref = "refine" }

[plugins]
androidApplication = { id = "com.android.application", version.ref = "agp" }

androidLibrary = { id = "com.android.library", version.ref = "agp" }
refine = { id = "dev.rikka.tools.refine", version.ref = "refine" }
1 change: 1 addition & 0 deletions dex/hiddenapi/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
23 changes: 23 additions & 0 deletions dex/hiddenapi/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
plugins {
alias(libs.plugins.androidLibrary)
}

android {
namespace = "com.xayah.hiddenapi"
compileSdk = 34

buildTypes {
release {
isMinifyEnabled = false
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
}

dependencies {
annotationProcessor(libs.refine.annotation.processor)
compileOnly(libs.refine.annotation)
}
4 changes: 4 additions & 0 deletions dex/hiddenapi/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

</manifest>
51 changes: 51 additions & 0 deletions dex/hiddenapi/src/main/java/android/app/AppOpsManagerHidden.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package android.app;

import java.util.List;

import dev.rikka.tools.refine.RefineAs;

/**
* @see <a href="https://cs.android.com/android/platform/superproject/+/android-7.0.0_r1:frameworks/base/core/java/android/app/AppOpsManager.java">AppOpsManager.java</a>
*/
@RefineAs(AppOpsManager.class)
public class AppOpsManagerHidden {
public static final int MODE_IGNORED = 1;
public static final int OP_NONE = -1;
public static final int _NUM_OP = 64;

public List<PackageOps> getOpsForPackage(int uid, String packageName, int[] ops) {
throw new RuntimeException("Stub!");
}

public static int permissionToOpCode(String permission) {
throw new RuntimeException("Stub!");
}

public void setMode(int code, int uid, String packageName, int mode) {
throw new RuntimeException("Stub!");
}

public static class PackageOps {
public String getPackageName() {
throw new RuntimeException("Stub!");
}

public int getUid() {
throw new RuntimeException("Stub!");
}

public List<OpEntry> getOps() {
throw new RuntimeException("Stub!");
}
}

public static class OpEntry {
public int getOp() {
throw new RuntimeException("Stub!");
}

public int getMode() {
throw new RuntimeException("Stub!");
}
}
}
1 change: 1 addition & 0 deletions dex/settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ dependencyResolutionManagement {

rootProject.name = "Script Dex"
include(":app")
include(":hiddenapi")
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ import com.xayah.core.util.ConfigsPackageRestoreName
import com.xayah.core.util.DateUtil
import com.xayah.core.util.IconRelativeDir
import com.xayah.core.util.PathUtil
import com.xayah.core.util.PermissionUtil
import com.xayah.core.util.command.BaseUtil
import com.xayah.core.util.command.PackageUtil
import com.xayah.core.util.command.Tar
Expand Down Expand Up @@ -329,7 +328,7 @@ class AppsRepo @Inject constructor(
updateEntity.extraInfo.firstUpdated = true
val uid = info.applicationInfo.uid
updateEntity.extraInfo.uid = uid
updateEntity.extraInfo.permissions = PermissionUtil.getPermission(packageManager = pm, packageInfo = info)
updateEntity.extraInfo.permissions = rootService.getPermissions(packageInfo = info)
updateEntity.extraInfo.hasKeystore = PackageUtil.hasKeystore(context.readCustomSUFile().first(), uid)
updateEntity.extraInfo.ssaid = rootService.getPackageSsaidAsUser(packageName = info.packageName, uid = uid, userId = userId)
updateEntity.extraInfo.enabled = info.applicationInfo.enabled
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ import com.xayah.core.util.DateUtil
import com.xayah.core.util.IconRelativeDir
import com.xayah.core.util.LogUtil
import com.xayah.core.util.PathUtil
import com.xayah.core.util.PermissionUtil
import com.xayah.core.util.command.BaseUtil
import com.xayah.core.util.command.PackageUtil
import com.xayah.core.util.command.Tar
Expand Down Expand Up @@ -232,7 +231,7 @@ class PackageRepository @Inject constructor(
userHandle: UserHandle?,
hasPassedOneDay: Boolean
): PackageEntity {
val permissions = PermissionUtil.getPermission(packageManager = pm, packageInfo = info)
val permissions = rootService.getPermissions(packageInfo = info)
val uid = info.applicationInfo.uid
val hasKeystore = if (checkKeystore) PackageUtil.hasKeystore(context.readCustomSUFile().first(), uid) else false
val ssaid = rootService.getPackageSsaidAsUser(packageName = info.packageName, uid = uid, userId = userId)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package android.app;

import java.util.List;

import dev.rikka.tools.refine.RefineAs;

/**
* @see <a href="https://cs.android.com/android/platform/superproject/+/android-7.0.0_r1:frameworks/base/core/java/android/app/AppOpsManager.java">AppOpsManager.java</a>
*/
@RefineAs(AppOpsManager.class)
public class AppOpsManagerHidden {
public static final int OP_NONE = -1;
public static final int _NUM_OP = 64;

public List<PackageOps> getOpsForPackage(int uid, String packageName, int[] ops) {
throw new RuntimeException("Stub!");
}

public static int permissionToOpCode(String permission) {
throw new RuntimeException("Stub!");
}

public void setMode(int code, int uid, String packageName, int mode) {
throw new RuntimeException("Stub!");
}

public static class PackageOps {
public String getPackageName() {
throw new RuntimeException("Stub!");
}

public int getUid() {
throw new RuntimeException("Stub!");
}

public List<OpEntry> getOps() {
throw new RuntimeException("Stub!");
}
}

public static class OpEntry {
public int getOp() {
throw new RuntimeException("Stub!");
}

public int getMode() {
throw new RuntimeException("Stub!");
}
}
}
5 changes: 5 additions & 0 deletions source/core/model/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,16 @@ plugins {

android {
namespace = "com.xayah.core.model"

buildFeatures {
aidl = true
}
}

dependencies {
// Core
implementation(project(":core:common"))
compileOnly(project(":core:hiddenapi"))

// Gson
implementation(libs.gson)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
package com.xayah.core.model.database;
parcelable PackagePermission;
Loading

0 comments on commit c963d51

Please sign in to comment.