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}