当前位置:   article > 正文

AppOps 对于Normal permission 的控制_ublic int noteopnothrow(

ublic int noteopnothrow(

相关资源:

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 如下:

  1. <permission android:name="android.permission.BLUETOOTH_ADMIN"
  2. android:description="@string/permdesc_bluetoothAdmin"
  3. android:label="@string/permlab_bluetoothAdmin"
  4. 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:

  1. public boolean enableBLE() {
  2. if (!isBleScanAlwaysAvailable()) return false;
  3. try {
  4. String packageName = ActivityThread.currentPackageName();
  5. mManagerService.updateBleAppCount(mToken, true, packageName);
  6. if (isLeEnabled()) {
  7. if (DBG) Log.d(TAG, "enableBLE(): Bluetooth already enabled");
  8. return true;
  9. }
  10. if (DBG) Log.d(TAG, "enableBLE(): Calling enable");
  11. return mManagerService.enable(packageName);
  12. } catch (RemoteException e) {
  13. Log.e(TAG, "", e);
  14. }
  15. return false;
  16. }

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

class BluetoothManagerService extends IBluetoothManager.Stub {}
  1. public boolean enable(String packageName) throws RemoteException {
  2. final int callingUid = Binder.getCallingUid();
  3. final boolean callerSystem = UserHandle.getAppId(callingUid) == Process.SYSTEM_UID;
  4. if (isBluetoothDisallowed()) {
  5. if (DBG) {
  6. Slog.d(TAG,"enable(): not enabling - bluetooth disallowed");
  7. }
  8. return false;
  9. }
  10. if (!callerSystem) {
  11. if (!checkIfCallerIsForegroundUser()) {
  12. Slog.w(TAG, "enable(): not allowed for non-active and non system user");
  13. return false;
  14. }
  15. mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
  16. "Need BLUETOOTH ADMIN permission");
  17. if (!isEnabled() && mPermissionReviewRequired
  18. && startConsentUiIfNeeded(packageName, callingUid,
  19. BluetoothAdapter.ACTION_REQUEST_ENABLE)) {
  20. return false;
  21. }
  22. }
  23. ...
  24. ...
  25. }

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

  1. AppOpsManager mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
  2. String packages = mContext.getPackageManager().getNameForUid(Binder.getCallingUid());
  3. if ((Binder.getCallingUid() >= Process.FIRST_APPLICATION_UID)
  4. && (packages.indexOf("android.uid.systemui") != 0)
  5. && (packages.indexOf("android.uid.system") != 0)) {
  6. int result = mAppOpsManager.noteOp(AppOpsManager.OP_BLUETOOTH_ADMIN,
  7. Binder.getCallingUid(), packages);
  8. if (result == AppOpsManager.MODE_IGNORED) {
  9. return false;
  10. }
  11. }

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

 

AppOpsManager.noteOp:

  1. public int noteOp(int op, int uid, String packageName) {
  2. try {
  3. int mode = mService.noteOperation(op, uid, packageName);
  4. if (mode == MODE_ERRORED) {
  5. throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName));
  6. }
  7. return mode;
  8. } catch (RemoteException e) {
  9. throw e.rethrowFromSystemServer();
  10. }
  11. }

当然还有一个接口:

  1. public int noteOpNoThrow(int op, int uid, String packageName) {
  2. try {
  3. return mService.noteOperation(op, uid, packageName);
  4. } catch (RemoteException e) {
  5. throw e.rethrowFromSystemServer();
  6. }
  7. }

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

  1. public int noteOperation(int code, int uid, String packageName) {
  2. verifyIncomingUid(uid);
  3. verifyIncomingOp(code);
  4. String resolvedPackageName = resolvePackageName(uid, packageName);
  5. if (resolvedPackageName == null) {
  6. return AppOpsManager.MODE_IGNORED;
  7. }
  8. return noteOperationUnchecked(code, uid, resolvedPackageName, 0, null);
  9. }

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

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

 

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

 

NFC enable 的管控:

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

  1. private boolean isNfcAllowed() {
  2. AppOpsManager mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
  3. String packages = mContext.getPackageManager().getNameForUid(Binder.getCallingUid());
  4. if ((Binder.getCallingUid() >= Process.FIRST_APPLICATION_UID)
  5. && (packages.indexOf("android.uid.systemui") != 0)
  6. && (packages.indexOf("android.uid.system") != 0)) {
  7. int result = mAppOpsManager.noteOp(AppOpsManager.OP_NFC,
  8. Binder.getCallingUid(), packages);
  9. if (result == AppOpsManager.MODE_IGNORED) {
  10. return false;
  11. }
  12. }
  13. return true;
  14. }

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

 

 

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/261402
推荐阅读
相关标签
  

闽ICP备14008679号