Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
<uses-permission
android:name="android.permission.REVOKE_RUNTIME_PERMISSIONS"
tools:ignore="ProtectedPermissions" />
Expand All @@ -152,6 +152,10 @@
<uses-permission
android:name="android.permission.WRITE_SECURE_SETTINGS"
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES"/>
<uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_APPS_CONTROL"/>
<uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_PACKAGE_STATE"/>
<uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS" />
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
<uses-permission android:name="com.termux.permission.RUN_COMMAND" />

Expand Down Expand Up @@ -1374,6 +1378,20 @@
android:name="android.appwidget.provider"
android:resource="@xml/recording_widget_info" />
</receiver>
<receiver
android:name=".dpc.DpcReceiver"
android:label="@string/app_name"
android:description="@string/dpc_service_description"
android:exported="false"
android:permission="android.permission.BIND_DEVICE_ADMIN">
<meta-data
android:name="android.app.device_admin"
android:resource="@xml/device_admin" />
<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
<action android:name="android.app.action.DEVICE_ADMIN_DISABLED" />
</intent-filter>
</receiver>
<receiver
android:name=".self.BootReceiver"
android:exported="false">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
import io.github.muntashirakon.AppManager.R;
import io.github.muntashirakon.AppManager.apk.ApkFile;
import io.github.muntashirakon.AppManager.apk.ApkUtils;
import io.github.muntashirakon.AppManager.compat.DevicePolicyManagerCompat;
import io.github.muntashirakon.AppManager.compat.ManifestCompat;
import io.github.muntashirakon.AppManager.compat.PackageManagerCompat;
import io.github.muntashirakon.AppManager.ipc.ProxyBinder;
Expand Down Expand Up @@ -953,7 +954,7 @@ public boolean installExisting(@NonNull String packageName, @UserIdInt int userI
}
mInstallWatcher = new CountDownLatch(0);
mInteractionWatcher = new CountDownLatch(0);
if (!SelfPermissions.canInstallExistingPackages()) {
if (!SelfPermissions.canInstallExistingPackages() || !DevicePolicyManagerCompat.canModifyPermissions()) {
installCompleted(mSessionId, STATUS_FAILURE_BLOCKED, "android", "STATUS_FAILURE_BLOCKED: Insufficient permission.");
Log.d(TAG, "InstallExisting: Requires INSTALL_PACKAGES permission.");
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import io.github.muntashirakon.AppManager.compat.AppOpsManagerCompat;
import io.github.muntashirakon.AppManager.compat.BackupCompat;
import io.github.muntashirakon.AppManager.compat.DeviceIdleManagerCompat;
import io.github.muntashirakon.AppManager.compat.DevicePolicyManagerCompat;
import io.github.muntashirakon.AppManager.compat.ManifestCompat;
import io.github.muntashirakon.AppManager.compat.NetworkPolicyManagerCompat;
import io.github.muntashirakon.AppManager.compat.PackageManagerCompat;
Expand Down Expand Up @@ -483,7 +484,7 @@ private void backupExtras() throws BackupException {
}
boolean isGranted = (permissionFlags[i] & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0;
int permFlags;
if (SelfPermissions.checkGetGrantRevokeRuntimePermissions()) {
if (SelfPermissions.checkGetGrantRevokeRuntimePermissions() || DevicePolicyManagerCompat.canModifyPermissions()) {
permFlags = PermissionCompat.getPermissionFlags(info.name, mPackageName, mUserId);
} else permFlags = PermissionCompat.FLAG_PERMISSION_NONE;
rules.setPermission(permissions[i], isGranted, permFlags);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import io.github.muntashirakon.AppManager.logs.Log;
import io.github.muntashirakon.AppManager.runner.Runner;
import io.github.muntashirakon.AppManager.self.SelfPermissions;
import io.github.muntashirakon.AppManager.settings.Ops;
import io.github.muntashirakon.AppManager.users.Users;
import io.github.muntashirakon.AppManager.utils.ExUtils;
import io.github.muntashirakon.AppManager.utils.ThreadUtils;
Expand All @@ -63,7 +64,7 @@ public static boolean startActivityViaAssist(@NonNull Context context, @NonNull
@Nullable ActivityLaunchUserInteractionRequiredCallback callback)
throws SecurityException {
// Need two permissions: WRITE_SECURE_SETTINGS and INJECT_EVENTS
SelfPermissions.requireSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS);
boolean canWriteSecure = SelfPermissions.checkSelfOrRemotePermission(Manifest.permission.WRITE_SECURE_SETTINGS);
boolean canInjectEvents = SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.INJECT_EVENTS);
ContentResolver resolver = context.getContentResolver();
// Backup assistant value
Expand All @@ -72,27 +73,44 @@ public static boolean startActivityViaAssist(@NonNull Context context, @NonNull
ThreadUtils.postOnBackgroundThread(() -> {
try {
// Set assistant value to the target activity component
Settings.Secure.putString(resolver, "assistant", activity.flattenToShortString());
if (canWriteSecure) {
Settings.Secure.putString(resolver, "assistant", activity.flattenToShortString());
} else if (Ops.isDpc()) {
DevicePolicyManagerCompat.setSecureSetting("assistant", activity.flattenToShortString());
}
// Run it as an assistant by injecting KEYCODE_ASSIST (219)
InputManagerCompat.sendKeyEvent(KeyEvent.KEYCODE_ASSIST, false);
// Wait until system opens the new assistant (i.e., activity), this is an empirical value
SystemClock.sleep(500);
} finally {
// Restore assistant value
Settings.Secure.putString(resolver, "assistant", assistantComponent);
if (canWriteSecure) {
Settings.Secure.putString(resolver, "assistant", assistantComponent);
} else if (Ops.isDpc()) {
DevicePolicyManagerCompat.setSecureSetting("assistant", assistantComponent);
}

}
});
} else if (callback != null) {
// Cannot launch event by default, use callback
ThreadUtils.postOnBackgroundThread(() -> {
try {
// Set assistant value to the target activity component
Settings.Secure.putString(resolver, "assistant", activity.flattenToShortString());
if (canWriteSecure) {
Settings.Secure.putString(resolver, "assistant", activity.flattenToShortString());
} else if (Ops.isDpc()) {
DevicePolicyManagerCompat.setSecureSetting("assistant", activity.flattenToShortString());
}
// Trigger callback
callback.onInteraction();
} finally {
// Restore assistant value
Settings.Secure.putString(resolver, "assistant", assistantComponent);
if (canWriteSecure) {
Settings.Secure.putString(resolver, "assistant", assistantComponent);
} else if (Ops.isDpc()) {
DevicePolicyManagerCompat.setSecureSetting("assistant", assistantComponent);
}
}
});
} // else do nothing
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package io.github.muntashirakon.AppManager.compat;

import android.annotation.SuppressLint;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManager.OnClearApplicationUserDataListener;
import android.content.ComponentName;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;

import io.github.muntashirakon.AppManager.BuildConfig;
import io.github.muntashirakon.AppManager.R;
import io.github.muntashirakon.AppManager.dpc.DpcReceiver;
import io.github.muntashirakon.AppManager.settings.Ops;
import io.github.muntashirakon.AppManager.utils.ContextUtils;
import io.github.muntashirakon.AppManager.utils.ThreadUtils;
import io.github.muntashirakon.AppManager.utils.UIUtils;

public class DevicePolicyManagerCompat {
public static final String LOG_TAG = "DPC";
public static final ComponentName DPC_ADMIN = new ComponentName(BuildConfig.APPLICATION_ID, DpcReceiver.class.getCanonicalName());
public static final String DPC_COMMAND = String.format("dpm set-device-owner %s", DevicePolicyManagerCompat.DPC_ADMIN.flattenToString());
private static DevicePolicyManager dpm;
@SuppressLint("WrongConstant")
public static DevicePolicyManager getDevicePolicyManager() {
if (dpm==null) {dpm=(DevicePolicyManager) ContextUtils.getContext().getSystemService(Context.DEVICE_POLICY_SERVICE);}
return dpm;
}

public static boolean isOwnerApp() {
return getDevicePolicyManager().isDeviceOwnerApp(BuildConfig.APPLICATION_ID);
}

public static void setSecureSetting(String setting, String value) {
getDevicePolicyManager().setSecureSetting(DPC_ADMIN, setting, value);
}
public static void setGlobalSetting(String setting, String value) {
getDevicePolicyManager().setGlobalSetting(DPC_ADMIN, setting, value);
}
@RequiresApi(api = Build.VERSION_CODES.P)
public static void setSystemSetting(String setting, String value) {
getDevicePolicyManager().setSystemSetting(DPC_ADMIN, setting, value);
}

public static void clearDeviceOwnerApp() {
getDevicePolicyManager().clearDeviceOwnerApp(BuildConfig.APPLICATION_ID);
}

public static boolean canModifyPermissions() {
return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Ops.isDpc());
}

@RequiresApi(api = Build.VERSION_CODES.M)
public static void revokePermission(String packageName, String permission) {
getDevicePolicyManager().setPermissionGrantState(DPC_ADMIN, packageName, permission, DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED);
}

@RequiresApi(api = Build.VERSION_CODES.M)
public static void grantPermission(String packageName, String permission) {
getDevicePolicyManager().setPermissionGrantState(DPC_ADMIN, packageName, permission, DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED);
}

@RequiresApi(api = Build.VERSION_CODES.N)
public static void setOrganizationName(String name) {
getDevicePolicyManager().setOrganizationName(DPC_ADMIN, name);
}

@RequiresApi(api = Build.VERSION_CODES.N)
public static void setOrganizationColor(int color) {
getDevicePolicyManager().setOrganizationColor(DPC_ADMIN, color);
}

@NonNull
@RequiresApi(api = Build.VERSION_CODES.N)
public static Bundle getUserRestrictions() {
return getDevicePolicyManager().getUserRestrictions(DPC_ADMIN);
}

public static boolean setApplicationHidden(String packageName, boolean hidden) {
return getDevicePolicyManager().setApplicationHidden(DPC_ADMIN, packageName, hidden);
}

@RequiresApi(api = Build.VERSION_CODES.N)
public static boolean setPackageSuspended(String packageName, boolean suspended) {
return !Arrays.stream(getDevicePolicyManager().setPackagesSuspended(DPC_ADMIN, new String[]{packageName}, suspended)).anyMatch((s)-> Objects.equals(s, packageName));
}

@RequiresApi(api = Build.VERSION_CODES.P)
public static void clearApplicationUserData(String packageName, DevicePolicyManager.OnClearApplicationUserDataListener listener) {
getDevicePolicyManager().clearApplicationUserData(DPC_ADMIN, packageName, ThreadUtils.getBackgroundThreadExecutor(), listener);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@

import dev.rikka.tools.refine.Refine;
import io.github.muntashirakon.AppManager.ipc.ProxyBinder;
import io.github.muntashirakon.AppManager.self.SelfPermissions;
import io.github.muntashirakon.AppManager.settings.Ops;
import io.github.muntashirakon.AppManager.utils.ContextUtils;
import io.github.muntashirakon.AppManager.utils.ExUtils;

Expand Down Expand Up @@ -278,6 +280,9 @@ public final class PermissionCompat {
public static int getPermissionFlags(@NonNull String permissionName,
@NonNull String packageName,
@UserIdInt int userId) throws SecurityException {
if (Ops.isDpc()) {
return FLAG_PERMISSION_NONE;
}
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
IPermissionManager permissionManager = getPermissionManager();
Expand Down Expand Up @@ -363,6 +368,10 @@ public static void grantPermission(@NonNull String packageName,
@NonNull String permissionName,
@UserIdInt int userId)
throws RemoteException {
if (!SelfPermissions.canModifyPermissions() && DevicePolicyManagerCompat.canModifyPermissions()) {
DevicePolicyManagerCompat.grantPermission(packageName, permissionName);
return;
}
IPackageManager pm = PackageManagerCompat.getPackageManager();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
IPermissionManager permissionManager = getPermissionManager();
Expand Down Expand Up @@ -406,6 +415,10 @@ public static void revokePermission(@NonNull String packageName,
@UserIdInt int userId,
@Nullable String reason) throws RemoteException {
IPackageManager pm = PackageManagerCompat.getPackageManager();
if (!SelfPermissions.canModifyPermissions() && DevicePolicyManagerCompat.canModifyPermissions()) {
DevicePolicyManagerCompat.revokePermission(packageName, permissionName);
return;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
IPermissionManager permissionManager = getPermissionManager();
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@

import io.github.muntashirakon.AppManager.R;
import io.github.muntashirakon.AppManager.compat.AppOpsManagerCompat;
import io.github.muntashirakon.AppManager.compat.DevicePolicyManagerCompat;
import io.github.muntashirakon.AppManager.compat.ManifestCompat;
import io.github.muntashirakon.AppManager.compat.PermissionCompat;
import io.github.muntashirakon.AppManager.details.struct.AppDetailsAppOpItem;
Expand Down Expand Up @@ -350,7 +351,7 @@ private int getHelpString(@PermissionProperty int index) {
if (!TipsPrefs.getInstance().displayInUsesPermissionsTab()) {
return 0;
}
if (SelfPermissions.canModifyPermissions()) {
if (SelfPermissions.canModifyPermissions() || DevicePolicyManagerCompat.canModifyPermissions()) {
return R.string.help_uses_permissions_tab;
} else return 0;
case PERMISSIONS:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
import io.github.muntashirakon.AppManager.compat.ActivityManagerCompat;
import io.github.muntashirakon.AppManager.compat.AppOpsManagerCompat;
import io.github.muntashirakon.AppManager.compat.ApplicationInfoCompat;
import io.github.muntashirakon.AppManager.compat.DevicePolicyManagerCompat;
import io.github.muntashirakon.AppManager.compat.ManifestCompat;
import io.github.muntashirakon.AppManager.compat.OverlayManagerCompact;
import io.github.muntashirakon.AppManager.compat.PackageManagerCompat;
Expand Down Expand Up @@ -1223,7 +1224,8 @@ private void loadActivities() {
CharSequence appLabel = packageInfo.applicationInfo.loadLabel(mPackageManager);
boolean canStartAnyActivity = SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.START_ANY_ACTIVITY);
boolean canStartViaAssist = UserHandleHidden.myUserId() == mUserId &&
SelfPermissions.checkSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS);
(SelfPermissions.checkSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
|| Ops.isDpc());
for (ActivityInfo activityInfo : packageInfo.activities) {
AppDetailsActivityItem componentItem = new AppDetailsActivityItem(activityInfo);
componentItem.label = getComponentLabel(activityInfo, appLabel);
Expand Down Expand Up @@ -1453,7 +1455,7 @@ private void loadAppOps() {
mAppOps.postValue(Collections.emptyList());
return;
}
boolean canGetGrantRevokeRuntimePermissions = SelfPermissions.checkGetGrantRevokeRuntimePermissions();
boolean canGetGrantRevokeRuntimePermissions = SelfPermissions.checkGetGrantRevokeRuntimePermissions() || DevicePolicyManagerCompat.canModifyPermissions();
synchronized (mAppOpItems) {
mAppOpItems.clear();
try {
Expand Down Expand Up @@ -1612,7 +1614,7 @@ private AppDetailsPermissionItem getPermissionItem(@NonNull String permissionNam
int appOp = AppOpsManagerCompat.permissionToOpCode(permissionName);
int permissionFlags;
boolean appOpAllowed = false;
if (!mExternalApk && SelfPermissions.checkGetGrantRevokeRuntimePermissions()) {
if (!mExternalApk && (SelfPermissions.checkGetGrantRevokeRuntimePermissions() || DevicePolicyManagerCompat.canModifyPermissions())) {
permissionFlags = PermissionCompat.getPermissionFlags(
permissionName, packageInfo.packageName, mUserId);
} else permissionFlags = PermissionCompat.FLAG_PERMISSION_NONE;
Expand Down
Loading
Loading