• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import DecryptContent from '../data/DecryptContent';
17import { common, wantConstant } from '@kit.AbilityKit';
18import Constants from '../../common/constant';
19import { ResultMsg } from '../../common/ResultMsg';
20import Result from '../../common/Result';
21import OpeningDialogManager from '../manager/OpeningDialogManager';
22import { HiLog } from '../../common/HiLog';
23import { OpenDlpFileManager } from '../manager/OpenDlpFileManager';
24import { FileParseType } from '../../bean/data/FileParseType';
25import { hiTraceMeter } from '@kit.PerformanceAnalysisKit';
26import { dlpPermission } from '@kit.DataProtectionKit';
27import { ObjectUtil } from '../../common/ObjectUtil';
28import { DlpFileOpenReport } from '../common/DlpFileOpenReport';
29import ViewAbilityService from '../../rpc/ViewAbility/service/ViewAbilityService';
30
31const TAG = 'StartSandboxHandler';
32
33export default class StartSandboxHandler {
34  private static instance: StartSandboxHandler;
35  private _decryptContent?: DecryptContent;
36
37  private constructor() {
38  }
39
40  static getInstance(): StartSandboxHandler {
41    if (!StartSandboxHandler.instance) {
42      StartSandboxHandler.instance = new StartSandboxHandler();
43    }
44    return StartSandboxHandler.instance;
45  }
46
47  private async prepareStartSandbox(decryptContent: DecryptContent,
48    context: common.ServiceExtensionContext): Promise<Result<DecryptContent>> {
49    const startSandboxRet = await this.startSandboxInner(decryptContent, context);
50    if (startSandboxRet.errcode !== Constants.ERR_CODE_SUCCESS) {
51      HiLog.error(TAG, 'startSandboxInner error');
52      await OpenDlpFileManager.getInstance().deleteStatus(decryptContent.openDlpFileData.uri);
53    }
54    this._decryptContent = undefined;
55    return startSandboxRet;
56  }
57
58  // 拉起沙箱:弹框超过250ms,拉起沙箱;弹框小于250ms,等待弹框250ms之后,拉起沙箱
59  public async startSandbox(decryptContent?: DecryptContent, context?: common.ServiceExtensionContext):
60    Promise<Result<DecryptContent>> {
61    HiLog.info(TAG, 'start startSandbox');
62    if (decryptContent) {
63      this._decryptContent = decryptContent;
64    }
65    const viewContext = AppStorage.get('viewContext') as common.ServiceExtensionContext;
66    if (!this._decryptContent) {
67      HiLog.error(TAG, 'decryptContent null');
68      return ResultMsg.getErrMsg(Constants.ERR_CODE_PARAMS_CHECK_ERROR);
69    }
70    if (!viewContext) {
71      HiLog.error(TAG, 'viewContext null');
72      return ResultMsg.getErrMsg(Constants.ERR_CODE_PARAMS_CHECK_ERROR);
73    }
74
75    const canStartAbility =
76      OpeningDialogManager.getInstance().getCanStartAbility(this._decryptContent.openDlpFileData.requestId);
77    const needStartAbility =
78      OpeningDialogManager.getInstance().getNeedStartAbility(this._decryptContent.openDlpFileData.requestId);
79    const needShowDialog = this._decryptContent.openDlpFileData.needShowToast;
80    const isZip = this._decryptContent.openDlpFileData.fileParse === FileParseType.ZIP;
81    const hasDecrypt = this._decryptContent.hasDecrypted;
82    HiLog.info(TAG, `startSandbox canStartAbility ${canStartAbility}, needStartAbility ${needStartAbility},
83    needShowDialog ${needShowDialog}, isZip ${isZip}, hasDecrypt ${hasDecrypt}`);
84
85    if ((hasDecrypt && !isZip) || !needShowDialog) {
86      return this.prepareStartSandbox(this._decryptContent, viewContext);
87    }
88    if (needShowDialog && !canStartAbility) {
89      HiLog.error(TAG, 'CanStartAbility error');
90      return ResultMsg.getErrMsg(Constants.ERR_CODE_USER_STOP_DIALOG);
91    }
92    if (needShowDialog && !needStartAbility) {
93      HiLog.info(TAG, 'no need to start ability, wait timeout callback');
94      return ResultMsg.buildSuccess(decryptContent);
95    }
96    return this.prepareStartSandbox(this._decryptContent, viewContext);
97  }
98
99  private async startSandboxInner(decryptContent: DecryptContent, context: common.ServiceExtensionContext):
100    Promise<Result<DecryptContent>> {
101    HiLog.info(TAG, 'startSandboxInner');
102    OpeningDialogManager.getInstance().deleteRequestId(decryptContent.openDlpFileData.requestId);
103    const startSandboxRet = await this.startSandboxAbility(decryptContent, context);
104    if (startSandboxRet.errcode !== Constants.ERR_CODE_SUCCESS) {
105      HiLog.error(TAG, 'startSandbox error');
106      return ResultMsg.buildMsg(startSandboxRet.errcode, startSandboxRet.errmsg);
107    }
108    return ResultMsg.buildSuccess(decryptContent);
109  }
110
111  private async startSandboxAbility(decryptContent: DecryptContent, context: common.ServiceExtensionContext):
112    Promise<Result<void>> {
113    // 1. startSandboxApp
114    hiTraceMeter.startTrace('DlpStartSandboxJs', decryptContent.openDlpFileData.startId);
115    const startSandboxAppRet = await this.startSandboxApp(decryptContent, context);
116    hiTraceMeter.finishTrace('DlpStartSandboxJs', decryptContent.openDlpFileData.startId);
117    if (startSandboxAppRet.errcode !== Constants.ERR_CODE_SUCCESS) {
118      HiLog.error(TAG, 'startSandboxApp failed');
119      return ResultMsg.buildMsg(startSandboxAppRet.errcode, startSandboxAppRet.errmsg);
120    }
121
122    // 2. startDataAbility
123    await this.startDataAbility(context);
124    return ResultMsg.buildSuccess();
125  }
126
127  private prepareWantParams(decryptContent: DecryptContent): void {
128    let want = decryptContent.openDlpFileData.want;
129    want.bundleName = decryptContent.openDlpFileData.sandboxBundleName;
130    want.abilityName = decryptContent.openDlpFileData.sandboxAbilityName;
131    want.moduleName = decryptContent.openDlpFileData.sandboxModuleName;
132    want.uri = decryptContent.linkUri;
133    want.flags = decryptContent.linkFileWriteable ?
134    wantConstant.Flags.FLAG_AUTH_WRITE_URI_PERMISSION : wantConstant.Flags.FLAG_AUTH_READ_URI_PERMISSION;
135    let dlpWant: Want = {
136      parameters: {
137        'linkFileName': {
138          'name': decryptContent.linkFileName
139        },
140        'fileAsset': {
141          'displayName': decryptContent.uriInfo.name,
142          'relativePath': decryptContent.uriInfo.path,
143          'dateModified': decryptContent.linkUriStat?.ctime
144        },
145        'uri': decryptContent.linkUri,
146        'dlpUri': {
147          'name': decryptContent.openDlpFileData.uri
148        },
149        'linkFileWriteable': {
150          'name': decryptContent.linkFileWriteable
151        },
152        'fileName': {
153          'name': decodeURIComponent(decryptContent.fileName)
154        },
155        'ohos.dlp.params.index': decryptContent.appInfo.appIndex,
156        'ohos.dlp.params.moduleName': decryptContent.openDlpFileData.sandboxModuleName,
157        'ohos.dlp.params.securityFlag': decryptContent.authPerm ===
158        dlpPermission.DLPFileAccess.READ_ONLY ? true : false
159      }
160    };
161    ObjectUtil.Assign(want.parameters, dlpWant.parameters);
162  }
163
164  private async startSandboxApp(decryptContent: DecryptContent, context: common.ServiceExtensionContext):
165    Promise<Result<void>> {
166    HiLog.info(TAG, 'start sandbox begin');
167    this.prepareWantParams(decryptContent);
168    try {
169      await context.startAbility(decryptContent.openDlpFileData.want);
170      HiLog.info(TAG, `startAbility success startId: ${decryptContent.openDlpFileData.startId}`);
171      await ViewAbilityService.getInstance().sendDisconnectMsgWithTimeout();
172      await this.addDecryptData(decryptContent);
173      DlpFileOpenReport.reportDlpFileOpenSuccess(Constants.DLP_START_SANDBOX_SUCCESS, decryptContent);
174      return ResultMsg.buildSuccess();
175    } catch (error) {
176      HiLog.wrapError(TAG, error, 'startAbility failed');
177      await OpenDlpFileManager.getInstance().deleteStatus(decryptContent.openDlpFileData.uri);
178      return ResultMsg.getErrMsg(error.code, error.message);
179    }
180  }
181
182  private async startDataAbility(context: common.ServiceExtensionContext):
183    Promise<void> {
184    let want: Want = {
185      bundleName: Constants.DLP_MANAGER_BUNDLE_NAME,
186      abilityName: 'DataAbility'
187    };
188    try {
189      await context.startAbility(want);
190      HiLog.debug(TAG, 'startDataAbility success');
191    } catch (error) {
192      HiLog.wrapError(TAG, error, 'startDataAbility failed')
193    }
194  }
195
196  private async addDecryptData(decryptContent: DecryptContent): Promise<void> {
197    const manager = OpenDlpFileManager.getInstance();
198    const setRet = await manager.addDecryptContent(decryptContent.openDlpFileData.uri, decryptContent);
199    if (setRet.errcode !== Constants.ERR_CODE_SUCCESS) {
200      HiLog.error(TAG, 'addDecryptData failed');
201    }
202  }
203}