查看: 220|回复: 0

鸿蒙沙箱目录共享捐献机制与fileAccess深度搜索实战

[复制链接]
发表于 1 小时前 | 显示全部楼层 |阅读模式
在企业级应用开发中,跨应用批量文件协同一直是个棘手问题。用户在用生产力工具编辑大量工程文件后,这些文件被安全地锁在应用自己的沙箱目录里。若想让另一个渲染引擎或同厂矩阵应用直接处理这些文件,传统做法要么依赖 FilePicker 让用户逐个手选,要么复制到公共目录,既浪费存储,又增加非授权访问风险。

HarmonyOS 7.0(API 26)的 Core File Kit 针对这个场景给出了两个关键解法:一是应用沙箱目录共享捐献机制(sandboxShare),二是文件搜索功能的大幅增强。前者允许应用在严格的 MAC/DAC 鉴权管控下,把沙箱内某个目录主动“捐献”给指定应用访问;后者则重构了文件搜索底层逻辑,通过开放 inode 遍历的递归深度控制算法,解决深层目录树下的搜索性能与稳定性问题。

一、沙箱目录共享捐献机制

过去的沙箱像一座密不透风的堡垒,除 FilePicker 能通过 URI 临时授权外,应用之间无法直接读取对方目录。sandboxShare 则是一种主动授权行为,不是简单修改 Linux 目录的 rwx 权限,而是结合了 MAC(强制访问控制)与 DAC(自主访问控制)的双重安全体系。

DAC 层面仍按文件系统原有的 UID/GID 归属判断;MAC 层面引入更细粒度的“上下文流转”机制。当应用 A 把目录捐献给应用 B 时,系统并不改变文件的真实物理路径和所有权,而是在 VFS(虚拟文件系统)层为应用 B 建立一条携带特定 Token 的映射通道。一旦 A 撤销捐献或 Token 过期,通道会在纳秒级被切断,避免“悬空权限”导致非授权访问。

核心 API 位于 @kit.CoreFileKit 的 sandboxShare 模块。以下代码展示了捐献目录与撤销授权的完整流程:
  1. import { sandboxShare } from '@kit.CoreFileKit';
  2. import { BusinessError } from '@kit.BasicServicesKit';
  3. import { fileIo } from '@kit.CoreFileKit';
  4. export class ShareDonationManager {
  5.     public async donateDirectory(sourceDirPath: string, targetBundleName: string): Promise<string> {
  6.         try {
  7.             // 检查目标目录是否存在且必须是目录
  8.             let stat = fileIo.statSync(sourceDirPath);
  9.             if (!stat.isDirectory()) {
  10.                 throw new Error('捐献失败:目标路径不是一个合法的目录');
  11.             }
  12.             // 构造捐献策略参数
  13.             let policy: sandboxShare.SharePolicy = {
  14.                 targetBundleName: targetBundleName,
  15.                 mode: sandboxShare.ShareMode.READ_WRITE, // 建议在不需要修改时用 READ_ONLY
  16.                 expiration: 24 * 60 * 60 // 可选有效期,单位为秒
  17.             };
  18.             // 执行捐献,底层触发 MAC/DAC 鉴权流并建立 VFS 映射
  19.             let sharedUri: string = await sandboxShare.shareDirectory(sourceDirPath, policy);
  20.             console.info(`[ShareDonation] 目录捐献成功!生成跨应用 URI: ${sharedUri}`);
  21.             return sharedUri;
  22.         } catch (error) {
  23.             let err = error as BusinessError;
  24.             console.error(`[ShareDonation] 捐献过程发生异常: 错误码 ${err.code}, 错误信息 ${err.message}`);
  25.             throw error;
  26.         }
  27.     }
  28.     public async revokeDonation(sharedUri: string): Promise<void> {
  29.         try {
  30.             await sandboxShare.cancelShare(sharedUri);
  31.             console.info(`[ShareDonation] URI 授权已彻底撤销: ${sharedUri}`);
  32.         } catch (error) {
  33.             console.error(`[ShareDonation] 撤销异常,请检查 URI 状态`);
  34.         }
  35.     }
  36. }
复制代码

这里有两个易踩的坑。第一,如果业务是跨应用的长效离线处理,必须显式设置 expiration,否则 Token 可能在应用进程死亡后默认回收。第二,即便目标应用拿到 READ_WRITE 权限,如果目录下包含系统保留只读文件,底层 IO 拦截器仍会抛出权限不足。捐献只是平移当前最高权限,不是提权。

二、fileAccess.search 深度搜索

过去要在一个包含数万个素材、深达十几层的目录中寻找指定后缀文件,只能手写递归调用 fs.listFile,导致堆栈内存暴涨,频繁的 JS 到 C++ 跨语言调用也会消耗大量 CPU,界面容易卡顿。HarmonyOS 7.0 的 fileAccess.search 把搜索过程下沉到系统内核的系统调用层。

底层不是简单封装 find 命令,而是一种带启发式剪枝的 inode 广度优先/深度优先混合遍历算法。当递归深度达到阈值时,系统会直接在节点上剪枝,连子节点的系统调用都不发起。因此,maxDepth 参数不仅是业务限制,更是防止符号链接成环引发死循环和内存爆炸的核心手段。

实际使用时,通过 fileAccess.createFileAccessHelper 创建实例,再调用 search 方法,传入目标目录数组和搜索选项。API 返回的不是一次性数组,而是迭代器,可以按需惰性拉取结果,避免海量命中导致 OOM。
  1. import { fileAccess } from '@kit.CoreFileKit';
  2. import { common } from '@kit.AbilityKit';
  3. export class DeepSearchManager {
  4.     private fileAccessHelper: fileAccess.FileAccessHelper;
  5.     constructor(context: common.UIAbilityContext) {
  6.         this.fileAccessHelper = fileAccess.createFileAccessHelper(context);
  7.     }
  8.     public async searchMediaFiles(targetDirs: string[], keyword: string, limitDepth: number): Promise<Array<string>> {
  9.         let resultPaths: Array<string> = [];
  10.         try {
  11.             let searchOptions: fileAccess.FileSearchOptions = {
  12.                 pattern: keyword, // 支持 glob 模式,如 *.mp4
  13.                 maxDepth: limitDepth,
  14.                 fileFilter: {
  15.                     types: [fileAccess.FileType.FILE]
  16.                 }
  17.             };
  18.             console.info(`[DeepSearch] 正在发起多目录深度搜索,目标深度: ${limitDepth}`);
  19.             let startTime = new Date().getTime();
  20.             // 底层并行执行,多个目录会自动进入协程池
  21.             let searchResult = await this.fileAccessHelper.search(targetDirs, searchOptions);
  22.             let nextResult = await searchResult.next();
  23.             while (!nextResult.done) {
  24.                 let fileInfo = nextResult.value;
  25.                 resultPaths.push(fileInfo.uri);
  26.                 nextResult = await searchResult.next();
  27.             }
  28.             let costTime = new Date().getTime() - startTime;
  29.             console.info(`[DeepSearch] 搜索完成!共找到 ${resultPaths.length} 个文件,耗时 ${costTime}ms`);
  30.         } catch (err) {
  31.             console.error(`[DeepSearch] 搜索过程异常,请排查路径有效性或权限。错误: ${err}`);
  32.         }
  33.         return resultPaths;
  34.     }
  35. }
复制代码

值得注意,FileSearchOptions 的 pattern 是专为文件系统优化的 glob 匹配机制,写 *.mp4 比正则 .*\.mp4$ 效率高得多。另外,如果提前 break 迭代器,底层搜索上下文可能不会立即释放。在极端密集调用下,容易耗尽底层句柄,务必确保流程完整闭环。

三、方案对比与适用边界

跨应用文件流转方面,FilePicker 适合少量手动选择,但操作笨重;复制到公共目录会浪费空间且增加泄露风险;sandboxShare 则适合批量、受控、可撤销的目录级共享。文件搜索方面,手写递归虽然灵活,但性能和稳定性差;fileAccess.search 适合海量文件、深层目录树的快速检索,尤其配合多目录并行搜索能显著提升效率。

四、避坑指南

1. 包名大小写和特殊符号必须确认一致。包名写错不一定会立刻报错,但目标应用访问时会触发 MAC 策略阻断,抛出模糊的 Permission denied。
2. 捐献目录后,两个应用操作同一物理文件块,必须约定并发控制机制。例如目标应用在写 SQLite 事务时,源应用强行重置文件,可能导致文件损坏。
3. maxDepth 不宜设置过大,比如 999。根据实测,企业级业务限制在 3 到 5 层即可覆盖绝大多数场景,过深会拖慢存储系统全局响应。
4. 迭代器中断后,尽量让资源生命周期完整闭环,避免底层句柄耗尽。

五、总结

HarmonyOS 7.0 的 Core File Kit 把容易出错、效率低下的文件共享与搜索逻辑,下沉到了系统安全的底层实现。sandboxShare 用 MAC/DAC 双重鉴权和 VFS 映射,平衡了沙箱隔离与跨应用协作;fileAccess.search 则用内核级剪枝算法解决了深层目录性能瓶颈。在架构选型时理解这些底层机制,能让我们在企(业级)应用中做出更合理的技术决策,少踩一些没有文档的暗坑。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-8-31 11:05 , Processed in 0.019311 second(s), 18 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部