概念

       在OpenHarmony的日志系统中,如果频繁出现诸如“permission defined”等报错信息,这往往指向了一个核心问题——权限配置不当。OpenHarmony的权限体系相当复杂且全面,涵盖了多个层面,包括应用调用时所需的权限、系统文件对不同用户的访问权限、SELinux策略所强制执行的权限控制,以及沙箱环境中路径的访问权限等。下面分析每一种权限的配置方式。

 

权限配置一:应用调用时所需的权限

      比如应用申请访问通讯录、位置信息、语音等权限时,需要配置如下

     Stage模型:需要在应用的module.json5中声明权限,示例:

{
  "module": {
    "requestPermissions": [{
      "name": "ohos.permission.INSTALL_BUNDLE",
      "reason": "install bundle",
      "usedScene": {
        "ability": [
          "KitFramework"
        ],
        "when": "always"
      }
    },
    {
      "name": "ohos.permission.LISTEN_BUNDLE_CHANGE",
      "reason": "install bundle",
      "usedScene": {
        "ability": [
          "KitFramework"
        ],
        "when": "always"
      }
    },
    {
      "name": "ohos.permission.GET_BUNDLE_INFO",
      "reason": "install bundle",
      "usedScene": {
        "ability": [
          "KitFramework"
        ],
        "when": "always"
      }
    }]
  }
}

 

        当包管理器开发应用安装功能接口时,会调用权限管理相关接口检查自身是否具有安装应用程序的权限,例如:以安装应用的权限名"ohos.permission.INSTALL_BUNDLE"作为入参,调用CheckPermission接口检查包管理器是否具有安装应用的权限,如果有权限,安装流程继续执行,否则返回安装失败;

constexpr static char PERMISSION_INSTALL_BUNDLE[] = "ohos.permission.INSTALL_BUNDLE";

bool Install(const char *hapPath, const InstallParam *installParam, InstallerCallback installerCallback)
{
    if ((hapPath == nullptr) || (installerCallback == nullptr) || (installParam == nullptr)) {
        HILOG_ERROR(HILOG_MODULE_APP, "BundleManager install failed due to nullptr parameters");
        return false;
    }
    // 检查ohos.permission.INSTALL_BUNDLE权限是否被授予
    if (CheckPermission(0, static_cast<const char *>(PERMISSION_INSTALL_BUNDLE)) != GRANTED) {
        HILOG_ERROR(HILOG_MODULE_APP, "BundleManager install failed due to permission denied");
        return false;  // 返回安装失败
    }
    // 安装流程
    ...
}

也可以用户手动授权,用户申请授权示例:

         动态向用户申请权限是指在应用程序运行时向用户请求授权的过程。可以通过调用requestPermissionsFromUser()方法来实现。该方法接收一个权限列表参数,例如位置、日历、相机、麦克风等。用户可以选择授予权限或者拒绝授权。

import { abilityAccessCtrl, common, Permissions, UIAbility } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';

const permissions: Array<Permissions> = ['ohos.permission.LOCATION','ohos.permission.APPROXIMATELY_LOCATION'];
function reqPermissionsFromUser(permissions: Array<Permissions>, context: common.UIAbilityContext): void {
  let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
  // requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗
  atManager.requestPermissionsFromUser(context, permissions).then((data) => {
    let grantStatus: Array<number> = data.authResults;
    let length: number = grantStatus.length;
    for (let i = 0; i < length; i++) {
      if (grantStatus[i] === 0) {
        // 用户授权,可以继续访问目标操作
      } else {
        // 用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限
        return;
      }
    }
    // 授权成功
  }).catch((err: BusinessError) => {
    console.error(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`);
  })
}
export default class EntryAbility extends UIAbility {
  onWindowStageCreate(windowStage: window.WindowStage): void {
    // ...
    windowStage.loadContent('pages/Index', (err, data) => {
      reqPermissionsFromUser(permissions, this.context);
    // ...
    });
  }

  // ...
}

上述方式授权后,调用如下接口去核实相关APP或进程是否有权限调用相关的API接口

接口名描述
int CheckPermission(int uid, const char *permissionName)检查指定UID的应用进程是否具有访问系统服务API的权限
int CheckSelfPermission(const char *permissionName)检查调用者是否具有访问系统服务API的权限
int QueryPermission(const char *identifier, PermissionSaved **permissions, int *permNum)查询应用申请的所有权限,并检查权限是否被授予
int GrantPermission(const char *identifier, const char *permName)将指定权限授予应用程序
int RevokePermission(const char *identifier, const char *permName)收回应用程序的指定权限
int GrantRuntimePermission(int uid, const char *permissionName)应用运行时动态授予指定权限
int RevokeRuntimePermission(int uid, const char *permissionName)应用运行时动态撤销指定权限

上述API对应的源码路径base/security/access_token/interfaces/kits/napi/accesstoken/src/napi_atmanager.cpp,有兴趣的盆友可以去看看源码。

 

权限配置二:系统文件对不同用户的访问权限

在源码路径base/startup/init/services/etc/init.cfg或者hdcshell路径/etc/init下的cfg中在jobs管理中使用chmod

 

权限配置三:SELinux策略

设置selinux各个子系统的访问策略在base/security/selinux_adapter/sepolicy/ohos_policy里面的te文件中进行配置,具体配置方式可以查看https://laval.csdn.net/64ee90df4165333c3076badb.html

 

权限配置四:沙盒文件访问权限

       沙盒机制是每个进程独立空间,如果你要将沙盒中的进程写到物理路径目录下,需要在/system/etc/sandbox或者在源码路径base/startup/appspawn/中修改appdata-sandbox.json或者appdata-sandbox64.json,将物理路径和沙盒路径映射起来,这样你的沙盒里的进程就可以访问物理路径的文件夹了。sandbox-path是沙盒路径,src-path是物理路径

例如

 

总结

当开发过程中碰到权限问题时,可以从上述几种权限配置中去排查,一般可以解决大多数权限相关的错误。

Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐