华为打开后台弹窗权限

系统分析

Posted by JovenHe on May 6, 2023

为保护用户使用华为手机过程中,不受三方应用随意后台弹窗打扰。我们增加了“后台弹窗”权限,该权限关闭时应用在后台弹出界面的能力会受到限制,除非用户手动授予该权限给应用。后台弹窗权限开关默认为拒绝,拒绝时应用无法在后台时弹出界面。 如果您当前的业务有后台弹窗的场景,我们提供了两种适配方案,推荐您使用方案1: 1、推荐您将后台启动activity改为显示通知,参考适配方案: https://developer.android.com/guide/components/activities/background-starts?hl=zh-cn 实现横幅通知的适配方式: https://developer.android.com/training/notify-user/time-sensitive?hl=zh-cn 2、对于业务上必须具有在后台时弹出界面的应用,例如闹钟类、运动类、电话类等类型,您可以提醒用户去权限设置里手动开启后台弹窗权限开关

以上是后台弹窗权限的说明,现在想要分析如何判断后台弹窗权限是否开启

直接导出HwSystemManager.apk,jadx打开

直接搜类,permissionApp

搜类permissionApp1.jpg

逐个分析,先排除runtime、group相关,后台弹窗权限不是运行时权限,也不是组权限

permissionApp和permissionApps是抽象父类

所以只剩下SingleHwPermissionApps和HwPermissionApp

HwPermissionApp继承自PermissionApp

public abstract class PermissionApp {
    public boolean HGa = false;
    public final Context mContext;
    public Drawable mIcon = null;
    public final String mPackageName;
    public final String mPermissionName;
    public final long mPermissionType;
    public List<String> nMa;

代表某个权限类型的单一应用

SingleHwPermissionApps继承自PermissionApps

public abstract class PermissionApps {
    public final Context mContext;
    public final String mName;
    public final long mPermissionType;
    public final ArrayList<PermissionApp> rMa = new ArrayList<>(10);
    public final HashMap<String, PermissionApp> sMa = new HashMap<>(16);

代表某个权限类型的所有应用,所以SingleHwPermissionApps就是要找的

rMa代表拥有该权限的所有应用,直接在SingleHwPermissionApps中查找rMa的数据添加方法

权限应用查找1.jpg

生成HwPermissionApp1.jpg

可以看到两个很重要的boolean值传入到PermissionInfoWrapper中,并生成HwMonitoredPermission

HwMonitoredPermission.jpg

在HwMonitoredPermission中看到granted的值就是xGa,也就是z2

 boolean z2 = j != UpdateConfig.UPDATE_FLAG_KingUserPermision ? PermissionUtils.m20646b(j, aVar.mPermissionCode, aVar.mPermissionCfg) == 1 : PermissionUtils.m20636W(aVar.mPkgName, aVar.f12071Be) == 0;

z2的值是m20646b或者m20636W方法得到的值比对得到的

    public static int m20636W(String str, int i) {
        if (TextUtils.isEmpty(str)) {
            C5994c.warn("PermissionUtils", "getPopupBackgroundWindowMode get invalid package name");
            return 3;
        }
        AppOpsManager appOpsManager = (AppOpsManager) ImageShowMemoryUtil.sContext.getSystemService(AppOpsManager.class);
        if (appOpsManager == null) {
            C5994c.warn("PermissionUtils", "checkHwOp get null AppOpsManager");
            return 3;
        }
        try {
            Class<?> cls = Class.forName("com.huawei.android.app.AppOpsManagerEx");
            return ((Integer) cls.getDeclaredMethod("checkHwOpNoThrow", AppOpsManager.class, Integer.TYPE, Integer.TYPE, String.class).invoke(cls, appOpsManager, Integer.valueOf((int) HwAlphaIndexResourceManager.f7172c), Integer.valueOf(i), str)).intValue();
        } catch (ClassNotFoundException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
            outline.m11090a(e, outline.m11053Va("getPopupBackgroundOpMode failed"), "PermissionUtils");
            return 3;
        }
    }

可以看到这个方法名就是getPopupBackgroundWindowMode,获取的就是后台弹窗权限的状态,修改代码后就能得到

    public static boolean getHadPopWindowPermission(Context context){
        try {
            AppOpsManager appOpsManager = null;
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
                appOpsManager = context.getSystemService(AppOpsManager.class);
            }
            if (appOpsManager == null) {
                return true;
            }
            PackageManager packageManager = context.getPackageManager();
            PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), PackageManager.GET_META_DATA);
            int uid = packageInfo.applicationInfo.uid;
            Class<?> cls = Class.forName("com.huawei.android.app.AppOpsManagerEx");
            Method checkHwOpNoThrow = cls.getDeclaredMethod("checkHwOpNoThrow", AppOpsManager.class, Integer.TYPE, Integer.TYPE, String.class);
            int checkHwOpResult = (Integer) checkHwOpNoThrow.invoke(cls, appOpsManager,
                    100000, uid, context.getPackageName());
            return checkHwOpResult == 0;
        } catch (PackageManager.NameNotFoundException | ClassNotFoundException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
            Log.d(TAG, "");
        }
        return true;
    }