AppOps 对于Normal permission 的控制

相关资源:

Android Runtime Permission 详解

android GrantPermissionsActivity 详解

android grantRuntimePermission 详解

Android native 权限控制流程

AppOps 中setUidMode 和setMode区别

android M 之前应用权限和M 之后的应用权限控制

Provider 权限详解

 

前言:

之前几篇博文(Android Runtime Permission 详解android grantRuntimePermission 详解

android GrantPermissionsActivity 详解)主要是分析了Runtime permission的控制流程。

对于Runtime permission,在应用需要对应的权限的时候,会给用户一个提示。
CTA 要求对于BT、WLAN、NFC 等也需要给出相应的提示,所以这些permission也需要单独的控制。

这一篇来分析一下Normal permission或者intall time permission 在android M之后单独控制流程。

 

举例说明:

这里我们用蓝牙来举例说明,蓝牙的permission 如下:

    <permission android:name="android.permission.BLUETOOTH_ADMIN"                                       
        android:description="@string/permdesc_bluetoothAdmin"                                           
        android:label="@string/permlab_bluetoothAdmin"                                                  
        android:protectionLevel="normal" /> 

如果需要打开/关闭蓝牙的控制,必须申请这个权限,但是这个权限level 是normal的,并不是runtime permission,不能通过PMS 中的grantRuntimePermission 或者是invokeRuntimePermission 来管理。对于这种normal permission,我们可以利用AppOps 来管理。

 

BT enable:

先来看下BT enable/disable是如何实现的?

framework/base/core/java/android/bluetooth/BluetoothAdapter.java:

    public boolean enableBLE() {
        if (!isBleScanAlwaysAvailable()) return false;

        try {
            String packageName = ActivityThread.currentPackageName();
            mManagerService.updateBleAppCount(mToken, true, packageName);
            if (isLeEnabled()) {
                if (DBG) Log.d(TAG, "enableBLE(): Bluetooth already enabled");
                return true;
            }
            if (DBG) Log.d(TAG, "enableBLE(): Calling enable");
            return mManagerService.enable(packageName);
        } catch (RemoteException e) {
            Log.e(TAG, "", e);
        }

        return false;
    }

这里是提供用户enable的开关入口,最终会调用到IBluetoothManager.enable:

class BluetoothManagerService extends IBluetoothManager.Stub {}
    public boolean enable(String packageName) throws RemoteException {
        final int callingUid = Binder.getCallingUid();
        final boolean callerSystem = UserHandle.getAppId(callingUid) == Process.SYSTEM_UID;

        if (isBluetoothDisallowed()) {
            if (DBG) {
                Slog.d(TAG,"enable(): not enabling - bluetooth disallowed");
            }
            return false;
        }

        if (!callerSystem) {
            if (!checkIfCallerIsForegroundUser()) {
                Slog.w(TAG, "enable(): not allowed for non-active and non system user");
                return false;
            }

            mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                    "Need BLUETOOTH ADMIN permission");

            if (!isEnabled() && mPermissionReviewRequired
                    && startConsentUiIfNeeded(packageName, callingUid,
                            BluetoothAdapter.ACTION_REQUEST_ENABLE)) {
                return false;
            }
        }
        ...
        ...
    }

我们通过AppOps 控制,只需要在这里,enable 真正实施之前加一个dialog 确认即可。

AppOpsManager mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
String packages = mContext.getPackageManager().getNameForUid(Binder.getCallingUid());
if ((Binder.getCallingUid() >= Process.FIRST_APPLICATION_UID)
         && (packages.indexOf("android.uid.systemui") != 0)
         && (packages.indexOf("android.uid.system") != 0)) {
    int result = mAppOpsManager.noteOp(AppOpsManager.OP_BLUETOOTH_ADMIN,
          Binder.getCallingUid(), packages);
    if (result == AppOpsManager.MODE_IGNORED) {
        return false;
    }
}

通过AppOps 的noteOp 接口确认当前permission 是否是允许或者禁止状态,返回值分别是AppOpsManager.MODE_ALLOWED 和AppOpsManager.MODE_IGNORED。

 

AppOpsManager.noteOp:

    public int noteOp(int op, int uid, String packageName) {
        try {
            int mode = mService.noteOperation(op, uid, packageName);
            if (mode == MODE_ERRORED) {
                throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName));
            }
            return mode;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

当然还有一个接口:

    public int noteOpNoThrow(int op, int uid, String packageName) {
        try {
            return mService.noteOperation(op, uid, packageName);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

显而易见,对于返回值MODE_ERRORED 是否进行exception 提醒进行了区分。但是最终调用的都是AppOpsService 中的noteOperation 接口:

    public int noteOperation(int code, int uid, String packageName) {
        verifyIncomingUid(uid);
        verifyIncomingOp(code);
        String resolvedPackageName = resolvePackageName(uid, packageName);
        if (resolvedPackageName == null) {
            return AppOpsManager.MODE_IGNORED;
        }
        return noteOperationUnchecked(code, uid, resolvedPackageName, 0, null);
    }

noteOperationUnchecked 的source code 这里就不给出了,我们可以看到最终会调用到这里,确认此权限在app 中是否会被允许或禁止。

那按照CTA 的要求,我们可以在这里给出用户dialog 提示,并且让用户选择是否打开。

 

具体dialog 的source code 涉及公司保密协议,暂不给出,不过欢迎一起交流。

 

NFC enable 的管控:

根据BT 的经验,对于NFC 可以同样的进行控制:

    private boolean isNfcAllowed() {
        AppOpsManager mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
        String packages = mContext.getPackageManager().getNameForUid(Binder.getCallingUid());
        if ((Binder.getCallingUid() >= Process.FIRST_APPLICATION_UID)
                && (packages.indexOf("android.uid.systemui") != 0)
                && (packages.indexOf("android.uid.system") != 0)) {
            int result = mAppOpsManager.noteOp(AppOpsManager.OP_NFC,
                                                Binder.getCallingUid(), packages);
            if (result == AppOpsManager.MODE_IGNORED) {
                return false;
            }
        }
        return true;
    }

最主要是其中OP_BLUETOOTH_ADMIN 和 OP_NFC 的逻辑控制需要在AppOpsManager 中控制好。

 

 

 

 

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

私房菜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值