• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2023 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 ServiceExtensionAbility from '@ohos.app.ability.ServiceExtensionAbility';
17import dlpPermission from '@ohos.dlpPermission';
18import fileio from '@ohos.fileio';
19import Want from '@ohos.app.ability.Want';
20import hiTraceMeter from '@ohos.hiTraceMeter';
21import hiSysEvent from '@ohos.hiSysEvent';
22import wantConstant from '@ohos.app.ability.wantConstant';
23import fs from '@ohos.file.fs';
24import fileUri from '@ohos.file.fileuri';
25import { BusinessError } from '@ohos.base';
26import osAccount from '@ohos.account.osAccount';
27import uriPermissionManager from '@ohos.application.uriPermissionManager';
28import {
29  getOsAccountInfo,
30  getUserId,
31  checkDomainAccountInfo,
32  getAuthPerm,
33  getFileFd,
34  getFileUriByPath,
35  getAppId,
36  DLPInfo,
37  getDLPInfo,
38  sendDlpFileOpenProperties,
39  isValidPath,
40  defaultDlpFile,
41  getAccountType,
42  getConnectionStatus
43} from '../common/utils';
44import {
45  DlpFileInfo,
46  deleteSandbox2linkFileData,
47  deleteFileOpenHistoryData,
48  deleteLinkSetData,
49  deleteToken2FileData,
50  getDlpFileInfoFromSandbox2linkFileData,
51} from '../common/DataUtils';
52import Constants from '../common/constant';
53import GlobalContext from '../common/GlobalContext';
54import rpc from '@ohos.rpc';
55import { GetAlertMessage } from '../common/GetAlertMessage';
56import { HiLog } from '../common/HiLog';
57import { ObjectUtil } from '../common/ObjectUtil';
58
59const TAG = 'View';
60const SUFFIX_INDEX = 2;
61
62let opening: boolean = false;
63export default class ViewAbility extends ServiceExtensionAbility {
64  private dlpFd: number = -1;
65  private linkFileName: string = '';
66  private linkFilePath: string = '';
67  private appIndex: number = -1;
68  private tokenId: number = -1;
69  private dlpFile: dlpPermission.DLPFile = defaultDlpFile;
70  private authPerm: dlpPermission.DLPFileAccess = dlpPermission.DLPFileAccess.READ_ONLY;
71  private sandboxBundleName: string = '';
72  private sandboxAbilityName: string = '';
73  private sandboxModuleName: string = '';
74  private fileName: string = '';
75  private uri: string = '';
76  private stat?: fs.Stat;
77  private accountInfo?: osAccount.OsAccountInfo;
78  private uriInfo: fileUri.FileUri = new fileUri.FileUri('');
79  private linkUri: string = '';
80  private alreadyOpened: boolean = false;
81  private userId: number = -1;
82  private linkFileWriteable: boolean = false;
83  private callerBundleName: string = '';
84  private accountType: number = dlpPermission.AccountType.DOMAIN_ACCOUNT;
85  private distributedInfoId: string = '';
86
87  async onCreate(want: Want): Promise<void> {
88    if (!GlobalContext.load('sandbox2linkFile')) {
89      GlobalContext.store('sandbox2linkFile', new Map<string, (number | string | dlpPermission.DLPFile)[][]>());
90    }
91    if (!GlobalContext.load('fileOpenHistory')) {
92      GlobalContext.store('fileOpenHistory', new Map<string, (number | string)[]>());
93    }
94    if (!GlobalContext.load('token2File')) {
95      GlobalContext.store('token2File', new Map<number, (number | string | dlpPermission.DLPFile)[]>());
96    }
97    if (!GlobalContext.load('linkSet')) {
98      GlobalContext.store('linkSet', new Set<string>());
99    }
100    let dlpInfo: DLPInfo = await getDLPInfo();
101    AppStorage.setOrCreate('hiPNameId', dlpInfo.name);
102    AppStorage.setOrCreate('hiPVersionId', dlpInfo.versionCode);
103    AppStorage.setOrCreate('viewContext', this.context);
104  }
105
106  async terminateCall(): Promise<void> {
107    return new Promise((resolve, reject) => {
108     let sandbox2linkFile: Map<string, (number | string | dlpPermission.DLPFile)[][]> =
109      GlobalContext.load('sandbox2linkFile') as Map<string, (number | string | dlpPermission.DLPFile)[][]>;
110      HiLog.debug(TAG, `sandbox2linkFile size: ${sandbox2linkFile.size}`);
111      if (sandbox2linkFile.size === 0) {
112        this.context.terminateSelf();
113      }
114      reject();
115      return;
116    });
117  }
118
119  async startDataAbility(): Promise<void> {
120    let want: Want = {
121      bundleName: Constants.DLP_MANAGER_BUNDLE_NAME,
122      abilityName: 'DataAbility'
123    };
124    try {
125      await this.context.startAbility(want);
126    } catch {
127      HiLog.info(TAG, `startDataAbility failed`);
128    }
129  }
130
131  startAbility(want: Want, startId: number): void {
132    HiLog.info(TAG, `start sandbox begin`);
133    this.context.startAbility(want, async (err) => {
134      hiTraceMeter.finishTrace('DlpStartSandboxJs', startId);
135      if (err && err.code !== 0) {
136        HiLog.error(TAG, `startSandboxApp failed: ${JSON.stringify(err)}`);
137        try {
138          await this.dlpFile.deleteDLPLinkFile(this.linkFileName);
139        } catch (err) {
140          HiLog.error(TAG, `dlpFile deleteDLPLinkFile failed: ${JSON.stringify(err)}`);
141        }
142        try {
143          await this.dlpFile.closeDLPFile();
144        } catch (err) {
145          HiLog.error(TAG, `dlpFile closeDLPFile failed: ${JSON.stringify(err)}`);
146        }
147        opening = false;
148        //when errCode is ERR_JS_APP_NOT_EXIST, delete info.
149        if (err.code === Constants.ERR_JS_APP_NOT_EXIST) {
150          await this.deleteData(true, false);
151        }
152        await GetAlertMessage.startAlertAbility(this.context,
153          {code: Constants.ERR_JS_APP_INSIDE_ERROR } as BusinessError);
154        await this.sendDlpFileOpenFault(Constants.DLP_START_SANDBOX_ERROR, this.sandboxBundleName, this.appIndex,
155          undefined); // 105: DLP_START_SANDBOX_ERROR
156      } else {
157        // 203: DLP_START_SANDBOX_SUCCESS
158        await this.sendDlpFileOpenEvent(Constants.DLP_START_SANDBOX_SUCCESS, this.sandboxBundleName, this.appIndex);
159        let sandbox2linkFile: Map<string, (number | string | dlpPermission.DLPFile)[][]> =
160          GlobalContext.load('sandbox2linkFile') as Map<string, (number | string | dlpPermission.DLPFile)[][]>;
161        if (!sandbox2linkFile.has(this.sandboxBundleName + this.appIndex)) {
162          sandbox2linkFile.set(this.sandboxBundleName + this.appIndex, []);
163        }
164        if (!this.alreadyOpened) {
165          sandbox2linkFile.get(this.sandboxBundleName + this.appIndex)?.push(
166            [this.dlpFile, this.linkFileName, this.dlpFd, this.tokenId, this.uri]);
167          (GlobalContext.load('fileOpenHistory') as Map<string, (number | string)[]>).set(
168            this.uri, [this.sandboxBundleName, this.appIndex, this.linkFileName, this.linkUri, this.distributedInfoId]
169          );
170          (GlobalContext.load('token2File') as Map<number, (number | string | dlpPermission.DLPFile |
171            dlpPermission.DLPFileAccess | null)[]>).set(this.tokenId,
172            [this.dlpFile, this.sandboxBundleName, this.appIndex, this.authPerm, this.uri, null, -1]);
173          (GlobalContext.load('linkSet') as Set<string>).add(this.linkUri);
174        }
175        await this.startDataAbility();
176        opening = false;
177        HiLog.debug(TAG, `startDataAbility success`);
178      }
179    });
180  }
181
182  async deleteData(isNeedCloseFd: boolean, isNeedDeleteLink: boolean): Promise<void> {
183    HiLog.info(TAG, `deleteData start`);
184    if (isNeedCloseFd) {
185      try {
186        fileio.closeSync(this.dlpFd);
187      } catch (err) {
188        HiLog.error(TAG, `closeSync failed: ${JSON.stringify(err)}`);
189      }
190    }
191    try {
192      await deleteSandbox2linkFileData(this.sandboxBundleName + this.appIndex, isNeedDeleteLink);
193      await deleteToken2FileData(this.tokenId);
194      await deleteLinkSetData(this.linkUri);
195      await deleteFileOpenHistoryData(this.uri);
196    } catch (err) {
197      HiLog.error(TAG, `deleteData failed`);
198    }
199  }
200
201  startSandboxApp(startId: number, want: Want): void {
202    startId = Number(startId);
203    hiTraceMeter.startTrace('DlpStartSandboxJs', startId);
204    want.bundleName = this.sandboxBundleName;
205    want.abilityName = this.sandboxAbilityName;
206    want.moduleName = this.sandboxModuleName;
207    want.uri = this.linkUri;
208    want.flags = this.linkFileWriteable ?
209        wantConstant.Flags.FLAG_AUTH_WRITE_URI_PERMISSION : wantConstant.Flags.FLAG_AUTH_READ_URI_PERMISSION;
210    let dlpWant: Want = {
211      parameters: {
212        'linkFileName': {
213          'name': this.linkFileName
214        },
215        'fileAsset': {
216          'displayName': this.uriInfo.name,
217          'relativePath': this.uriInfo.path,
218          'dateModified': this.stat?.ctime
219        },
220        'uri': this.linkUri,
221        'dlpUri': {
222          'name': this.uri
223        },
224        'linkFileWriteable': {
225          'name': this.linkFileWriteable
226        },
227        'ohos.dlp.params.index': this.appIndex,
228        'ohos.dlp.params.moduleName': this.sandboxModuleName,
229        'ohos.dlp.params.securityFlag': this.authPerm ===
230          dlpPermission.DLPFileAccess.READ_ONLY ? true : false
231      }
232    };
233    ObjectUtil.Assign(want.parameters, dlpWant.parameters);
234    this.startAbility(want, startId);
235  }
236
237  async sendDlpFileOpenFault(code: number, sandboxName: string, appIndex: number, reason?: string): Promise<void> {
238    let event: hiSysEvent.SysEventInfo = {
239      domain: 'DLP',
240      name: 'DLP_FILE_OPEN',
241      eventType: hiSysEvent?.EventType?.FAULT,
242      params: {
243        'CODE': code,
244        'USER_ID': this.userId,
245        'SANDBOX_PKGNAME': sandboxName,
246      } as Record<string, number | string>
247    };
248    if (appIndex !== -1 && event.params) {
249      event.params['SANDBOX_INDEX'] = appIndex;
250    }
251    if (reason !== undefined && event.params) {
252      event.params['REASON'] = reason;
253    }
254    try {
255      await hiSysEvent.write(event);
256    } catch (err) {
257      HiLog.error(TAG, `sendDlpFileOpenFault failed`);
258    }
259  }
260
261  async sendDlpFileOpenEvent(code: number, sandboxName: string, appIndex: number): Promise<void> {
262    let event: hiSysEvent.SysEventInfo = {
263      domain: 'DLP',
264      name: 'DLP_FILE_OPEN_EVENT',
265      eventType: hiSysEvent?.EventType?.BEHAVIOR,
266      params: {
267        'CODE': code,
268        'USER_ID': this.userId,
269        'SANDBOX_PKGNAME': sandboxName,
270      } as Record<string, number | string>
271    };
272    if (appIndex !== -1 && event.params) {
273      event.params['SANDBOX_INDEX'] = appIndex;
274    }
275    try {
276      await hiSysEvent.write(event);
277    } catch (err) {
278      HiLog.error(TAG, `sendDlpFileOpenEvent failed`);
279    }
280  }
281
282
283  async closeFile(): Promise<void> {
284    try {
285      await this.dlpFile.closeDLPFile();
286      fileio.closeSync(this.dlpFd);
287    } catch (err) {
288      HiLog.error(TAG, `closeFile failed: ${JSON.stringify(err)}`);
289    }
290  }
291
292  async startLoginAbility(): Promise<void> {
293    let accountWant: Want = {
294      bundleName: 'com.huawei.hmos.dlpcredmgr',
295      abilityName: 'DlpCredLoginAbility'
296    };
297    if (await getConnectionStatus() === false) {
298      GetAlertMessage.startAlertAbility(this.context, {
299        code: Constants.ERR_JS_APP_NETWORK_INVALID } as BusinessError);
300      return;
301    }
302    try {
303      await this.context.startAbility(accountWant);
304    } catch (err) {
305      HiLog.info(TAG, `Failed to invoke startAbility, ${JSON.stringify(err)}`)
306      return;
307    }
308    await this.terminateCall();
309  }
310
311  async getAccountAndOpenDLPFile(startId: number): Promise<void> {
312    hiTraceMeter.startTrace('DlpGetOsAccountJs', startId);
313    return new Promise(async (resolve, reject) => {
314      try {
315        this.accountInfo = await getOsAccountInfo();
316        this.distributedInfoId = this.accountInfo.distributedInfo.id;
317        AppStorage.setOrCreate('accountDomain', this.accountInfo.domainInfo.domain);
318        this.userId = await getUserId();
319      } catch (err) {
320        HiLog.error(TAG, `getOsAccountInfo failed: ${JSON.stringify(err)}`);
321        hiTraceMeter.finishTrace('DlpGetOsAccountJs', startId);
322        hiTraceMeter.finishTrace('DlpOpenFileJs', startId);
323        opening = false;
324        await GetAlertMessage.startAlertAbility(this.context, {
325          code: Constants.ERR_JS_GET_ACCOUNT_ERROR } as BusinessError);
326        fileio.closeSync(this.dlpFd);
327        reject(err);
328        return;
329      }
330      hiTraceMeter.finishTrace('DlpGetOsAccountJs', startId);
331      if (this.accountType === dlpPermission.AccountType.CLOUD_ACCOUNT) {
332        if (this.accountInfo.distributedInfo.name === 'ohosAnonymousName' &&
333          this.accountInfo.distributedInfo.id === 'ohosAnonymousUid') {
334          HiLog.info(TAG, 'account not login');
335          opening = false;
336          await this.startLoginAbility();
337          reject();
338          return;
339        }
340        resolve();
341        return;
342      }
343      let codeMessage = checkDomainAccountInfo(this.accountInfo);
344      if (codeMessage) {
345        hiTraceMeter.finishTrace('DlpOpenFileJs', startId);
346        opening = false;
347        await GetAlertMessage.startAlertAbility(this.context, {
348          code: codeMessage } as BusinessError);
349        fileio.closeSync(this.dlpFd);
350        reject();
351        return;
352      }
353      resolve();
354    });
355  }
356
357  async callAlertAbility(errCode: BusinessError): Promise<void> {
358      await GetAlertMessage.startAlertAbility(this.context, errCode);
359      return;
360  }
361
362  async getOpenedDLPFile(startId: number): Promise<void> {
363    return new Promise(async (resolve, reject) => {
364      hiTraceMeter.startTrace('DlpOpenDlpFileJs', startId);
365      try {
366        HiLog.info(TAG, `openDLPFile: ${this.fileName}, dlpFd: ${this.dlpFd}`);
367        let callerAppId: string;
368        try {
369          callerAppId = await getAppId(this.callerBundleName);
370          HiLog.info(TAG, `get AppId success`);
371        } catch {
372          HiLog.error(TAG, `get AppId failed`);
373          await this.callAlertAbility({code: Constants.ERR_JS_NOT_AUTHORIZED_APPLICATION } as BusinessError);
374          return;
375        }
376        this.dlpFile = await dlpPermission.openDLPFile(this.dlpFd, callerAppId);
377        this.accountType = this.dlpFile.dlpProperty.ownerAccountType;
378      } catch (err) {
379        HiLog.error(TAG, `openDLPFile: ${this.fileName}, failed: ${JSON.stringify(err)}`);
380        hiTraceMeter.finishTrace('DlpOpenDlpFileJs', startId);
381        hiTraceMeter.finishTrace('DlpOpenFileJs', startId);
382        opening = false;
383        await this.sendDlpFileOpenFault(
384          Constants.DLP_FILE_PARSE_ERROR, this.sandboxBundleName, -1, (err as BusinessError<string>).data
385        ); // 103:DLP_FILE_PARSE_ERROR
386
387        if (err.code === Constants.ERR_JS_NOT_AUTHORIZED_APPLICATION ) {
388          await this.callAlertAbility({code: Constants.ERR_JS_NOT_AUTHORIZED_APPLICATION} as BusinessError);
389          return;
390        }
391        let accountFlag: boolean = true;
392        if (this.accountType === dlpPermission.AccountType.DOMAIN_ACCOUNT &&
393          err.code === Constants.ERR_JS_USER_NO_PERMISSION) {
394          let accountName: string = err.message.split(', contact:')?.[1];
395          accountFlag = await GetAlertMessage.checkAccountInfo(accountName);
396        }
397        if (!accountFlag) {
398          await this.callAlertAbility({code: Constants.ERR_JS_APP_INSIDE_ERROR } as BusinessError);
399          return;
400        }
401        await this.callAlertAbility(err.code === Constants.ERR_JS_APP_PERMISSION_DENY ?
402          {code: Constants.ERR_JS_RELEASE_FILE_OPEN } as BusinessError : err);
403        fileio.closeSync(this.dlpFd);
404        reject();
405        return;
406      }
407      hiTraceMeter.finishTrace('DlpOpenDlpFileJs', startId);
408      try {
409        await this.dlpGetAuthPerm();
410      } catch (err) {
411        reject();
412        return;
413      }
414      resolve();
415    })
416  }
417
418  async dlpGetAuthPerm(): Promise<void> {
419    return new Promise(async (resolve, reject) => {
420      if (this.accountType === dlpPermission.AccountType.DOMAIN_ACCOUNT) {
421        this.authPerm = getAuthPerm(this.accountInfo?.domainInfo.accountName ?? '', this.dlpFile.dlpProperty);
422      } else {
423        this.authPerm = dlpPermission.DLPFileAccess.READ_ONLY;
424      }
425      if (this.authPerm < dlpPermission.DLPFileAccess.READ_ONLY ||
426        this.authPerm > dlpPermission.DLPFileAccess.FULL_CONTROL) {
427        opening = false;
428        await GetAlertMessage.startAlertAbility(this.context, {
429          code: Constants.ERR_JS_APP_INSIDE_ERROR } as BusinessError);
430        await this.closeFile();
431        reject();
432        return;
433      }
434      resolve();
435    });
436  }
437
438  async getPolicyAndInstallSandbox(startId: number): Promise<void> {
439    return new Promise(async (resolve, reject) => {
440      this.alreadyOpened = false;
441      try {
442        await this.sandboxSetData(startId);
443      } catch {
444        reject();
445        return;
446      }
447      AppStorage.setOrCreate('hiSandboxIndex', this.appIndex);
448      hiTraceMeter.finishTrace('DlpInstallSandboxJs', startId);
449      // 202: DLP_INSTALL_SANDBOX_SUCCESS
450      await this.sendDlpFileOpenEvent(Constants.DLP_INSTALL_SANDBOX_SUCCESS, this.sandboxBundleName, this.appIndex);
451      if (!this.alreadyOpened) {
452        try {
453          await this.getAlreadyOpen(startId);
454        } catch {
455          reject();
456          return;
457        }
458      }
459      resolve();
460    });
461  }
462
463  async sandboxSetData(startId: number): Promise<void> {
464    return new Promise(async (resolve, reject) => {
465      try {
466        let fileOpenHistory: Map<string, (number | string)[]> =
467          GlobalContext.load('fileOpenHistory') as Map<string, (number | string)[]>;
468        if (fileOpenHistory.has(this.uri) && this.historyOpenSame(fileOpenHistory)) {
469          HiLog.info(TAG, `file: ${this.fileName} already open`);
470          let value: (number | string)[] = fileOpenHistory.get(this.uri) as (number | string)[];
471          this.appIndex = value[Constants.FILE_OPEN_HISTORY_ONE] as number;
472          this.linkFileName = value[Constants.FILE_OPEN_HISTORY_TWO] as string;
473          this.linkUri = value[Constants.FILE_OPEN_HISTORY_THREE] as string;
474          fs.closeSync(this.dlpFd);
475          let dlpFileInfo =
476            await getDlpFileInfoFromSandbox2linkFileData(this.sandboxBundleName + this.appIndex, this.uri);
477          this.dlpFile = dlpFileInfo.dlpFile;
478          this.tokenId = dlpFileInfo.tokenId;
479          this.accountType = this.dlpFile.dlpProperty.ownerAccountType;
480          await this.dlpGetAuthPerm();
481          this.alreadyOpened = true;
482        } else {
483          await this.getOpenedDLPFile(startId);
484        }
485        hiTraceMeter.startTrace('DlpInstallSandboxJs', startId);
486        let appInfo: dlpPermission.DLPSandboxInfo = await dlpPermission.installDLPSandbox(
487          this.sandboxBundleName, this.authPerm, this.userId, this.uri
488        );
489        if (this.alreadyOpened && (this.appIndex != appInfo.appIndex || this.tokenId != appInfo.tokenID)) {
490          HiLog.info(TAG, `return:${this.appIndex} ${appInfo.appIndex} ${this.tokenId} ${appInfo.tokenID} `);
491          await this.deleteData(false, true);
492          this.dlpFd = getFileFd(this.uri, fs.OpenMode.READ_WRITE);
493          await this.getOpenedDLPFile(startId);
494          this.alreadyOpened = false;
495        }
496        this.appIndex = appInfo.appIndex;
497        this.tokenId = appInfo.tokenID;
498        resolve();
499      } catch (err) {
500        HiLog.error(TAG, `installDLPSandbox failed: ${JSON.stringify(err)}`);
501        hiTraceMeter.finishTrace('DlpInstallSandboxJs', startId);
502        hiTraceMeter.finishTrace('DlpOpenFileJs', startId);
503        opening = false;
504        await this.sendDlpFileOpenFault(
505          Constants.DLP_INSTALL_SANDBOX_ERROR, this.sandboxBundleName, -1, (err as BusinessError<string>).data
506        ); // 104:DLP_INSTALL_SANDBOX_ERROR
507        await GetAlertMessage.startAlertAbility(this.context, {
508          code: Constants.ERR_JS_APP_INSIDE_ERROR } as BusinessError);
509        await this.closeFile();
510        reject();
511      }
512    })
513  }
514
515  historyOpenSame(fileOpenHistory: Map<string, (number | string)[]>): boolean {
516    let historyDistributedInfoId = fileOpenHistory.get(this.uri);
517    let distributeId = historyDistributedInfoId ? historyDistributedInfoId[4] : '';
518    if (distributeId === this.distributedInfoId) {
519      return true;
520    };
521    return false;
522  }
523
524  async generateLinkFileName(startId: number): Promise<string> {
525    return new Promise<string>(async (resolve, reject) => {
526      let timestamp = new Date().getTime();
527      let splitNames = this.fileName.split('.');
528      HiLog.debug(TAG, `splitNames: ${splitNames}`);
529      if (splitNames.length <= SUFFIX_INDEX) {
530        hiTraceMeter.finishTrace('DlpOpenFileJs', startId);
531        opening = false;
532        await GetAlertMessage.startAlertAbility(this.context, {
533          code: Constants.ERR_JS_APP_INSIDE_ERROR } as BusinessError);
534        await this.closeFile();
535        reject('');
536        return;
537      }
538      let secondarySuffix = splitNames[splitNames.length - SUFFIX_INDEX];
539      this.linkFileName = String(this.sandboxBundleName).substring(0, Constants.BUNDLE_LEN) + '_' + this.appIndex +
540        '_' + timestamp + String(Math.random()).substring(Constants.RAND_START, Constants.RAND_END) + '.dlp.link.' +
541        secondarySuffix;
542        resolve(secondarySuffix);
543    });
544  }
545
546  async getAlreadyOpen(startId: number): Promise<void> {
547    return new Promise(async (resolve, reject) => {
548      try {
549        await this.generateLinkFileName(startId);
550      } catch {
551        reject();
552        return;
553      }
554      hiTraceMeter.startTrace('DlpAddLinkFileJs', startId);
555      try {
556        await this.getAddDLPLinkFile(startId);
557      } catch {
558        reject();
559        return;
560      }
561      hiTraceMeter.finishTrace('DlpAddLinkFileJs', startId);
562      try {
563        this.linkFilePath = Constants.FUSE_PATH + this.linkFileName;
564        let stat = fs.statSync(this.linkFilePath);
565        const WRITE_ACCESS: number = 0o0200;
566        if (stat.mode & WRITE_ACCESS) {
567          this.linkFileWriteable = true;
568        } else {
569          this.linkFileWriteable = false;
570        }
571      } catch (err) {
572        HiLog.error(TAG, `file error: ${JSON.stringify(err)}`);
573        opening = false;
574        try {
575          await this.terminateCall();
576        } catch (err) {
577          reject();
578          return;
579        }
580      }
581      this.linkUri = getFileUriByPath(this.linkFilePath);
582      if (this.linkUri === '') {
583        HiLog.error(TAG, `get linkUri ByPath fail`);
584        opening = false;
585        try {
586          await this.terminateCall();
587        } catch (err) {
588          reject();
589          return;
590        }
591      }
592      resolve();
593    });
594  }
595
596  async getAddDLPLinkFile(startId: number): Promise<void> {
597    return new Promise(async (resolve, reject) => {
598      try {
599        await this.dlpFile.addDLPLinkFile(this.linkFileName);
600      } catch (error) {
601        HiLog.error(TAG, `addDLPLinkFile failed: ${JSON.stringify(error)}`);
602        try {
603          await this.dlpFile.closeDLPFile();
604        } catch (err) {
605          HiLog.error(TAG, `closeDLPFile failed: ${JSON.stringify(err)}`);
606        }
607        opening = false;
608        await GetAlertMessage.startAlertAbility(this.context, error);
609        hiTraceMeter.finishTrace('DlpAddLinkFileJs', startId);
610        hiTraceMeter.finishTrace('DlpOpenFileJs', startId);
611        await this.closeFile();
612        reject();
613        return;
614      }
615      resolve();
616    });
617  }
618
619  async getUriInfo(startId: number): Promise<void> {
620    return new Promise(async (resolve, reject) => {
621      try {
622        this.uriInfo = new fileUri.FileUri(this.uri);
623      } catch (error) {
624        hiTraceMeter.finishTrace('DlpOpenFileJs', startId);
625        opening = false;
626        await GetAlertMessage.startAlertAbility(this.context, {
627          code: Constants.ERR_JS_APP_GET_FILE_ASSET_ERROR } as BusinessError);
628        await this.closeFile();
629        HiLog.error(TAG, `open: ${this.uri}, failed: ${JSON.stringify(error)}`);
630        reject();
631        return;
632      }
633      try {
634        this.stat = await fs.stat(this.uriInfo.path);
635        AppStorage.setOrCreate('hiFileSize', this.stat.size);
636        AppStorage.setOrCreate('hiPolicySizeEnc', this.stat.size);
637      } catch (err) {
638        HiLog.info(TAG, `stat fail: ${JSON.stringify(err)}`);
639      }
640      resolve();
641    });
642  }
643
644  onConnect(want: Want): rpc.RemoteObject {
645    return new rpc.RemoteObject(TAG);
646  }
647
648  onDisconnect(want: Want): void {
649    HiLog.info(TAG, `onDisconnect`);
650  }
651
652  dlpFileMapHistory(want: Want): Promise<void> {
653    return new Promise(async (resolve, reject) => {
654      this.callerBundleName = want.parameters?.['ohos.dlp.params.bundleName'] as string;
655      AppStorage.setOrCreate('hiSandboxPkgName', this.callerBundleName);
656      if ((AppStorage.get('dlpFileMap') as Map<string, (string | number)[]>)?.has(want.uri ?? '')) {
657        await GetAlertMessage.startAlertAbility(this.context, {
658          code: Constants.ERR_JS_APP_ENCRYPTION_REJECTED } as BusinessError);
659        reject();
660        return;
661      }
662      if (opening) {
663        HiLog.info(TAG, `file is opening: ${this.uri}`);
664        reject();
665        return;
666      } else {
667        opening = true;
668        HiLog.info(TAG, `file is opened: ${this.uri}`);
669      }
670      this.uri = want.uri as string;
671      if (!isValidPath(this.uri)) {
672        opening = false;
673        HiLog.error(TAG, `invalid uri in want.uri`);
674        try {
675          await this.terminateCall();
676        } catch (err) {
677          reject();
678          return;
679        }
680      }
681      let strArray: string[] = this.uri.split('/');
682      let len: number = strArray.length;
683      this.fileName = strArray[len - 1];
684      this.dlpFd = getFileFd(this.uri, fs.OpenMode.READ_WRITE);
685      HiLog.debug(TAG, `dlpFd: ${this.dlpFd}`);
686      if (this.dlpFd === -1) {
687        opening = false;
688        try {
689          await this.terminateCall();
690        } catch (err) {
691          reject();
692          return;
693        }
694      }
695      resolve();
696    })
697  }
698
699  grandUriPermission() {
700    let flag = wantConstant.Flags.FLAG_AUTH_WRITE_URI_PERMISSION |
701      wantConstant.Flags.FLAG_AUTH_PERSISTABLE_URI_PERMISSION;
702    let targetBundleName = this.sandboxBundleName;
703    uriPermissionManager.grantUriPermission(this.uri, flag, targetBundleName, (result) => {
704      HiLog.info(TAG, `grandUriPermission result: ${JSON.stringify(result)}`);
705    });
706  }
707
708  async onRequest(want: Want, startId: number): Promise<void> {
709    HiLog.debug(TAG, `enter onRequest`);
710    try {
711      await this.dlpFileMapHistory(want);
712      this.accountType = await getAccountType(this.context, this.dlpFd);
713    } catch {
714      return;
715    }
716    startId = Number(startId);
717    hiTraceMeter.startTrace('DlpOpenFileJs', startId);
718    this.sandboxBundleName = want.parameters?.['ohos.dlp.params.bundleName'] as string;
719    this.sandboxAbilityName = want.parameters?.['ohos.dlp.params.abilityName'] as string;
720    this.sandboxModuleName = want.parameters?.['ohos.dlp.params.moduleName'] as string;
721    if (this.fileName === undefined || this.dlpFd === undefined || this.uri === undefined ||
722      this.sandboxBundleName === undefined || this.sandboxAbilityName === undefined ||
723      this.sandboxModuleName === undefined || !this.uri.endsWith('.dlp')) {
724      opening = false;
725      HiLog.error(TAG, `get parameters failed`);
726      try {
727        await this.terminateCall();
728      } catch (err) {
729        return;
730      }
731    }
732    let fileOpenHistory: Map<string, (number | string)[]> =
733        GlobalContext.load('fileOpenHistory') as Map<string, (number | string)[]>;
734    if (fileOpenHistory.has(this.uri)) {
735      let value: (number | string)[] = fileOpenHistory.get(this.uri) as (number | string)[];
736      if (this.sandboxBundleName !== value[Constants.FILE_OPEN_HISTORY_ZERO] as string) {
737        HiLog.error(TAG, `other app is opening this file`);
738        opening = false;
739        await GetAlertMessage.startAlertAbility(this.context, {
740          code: Constants.ERR_JS_OTHER_APP_OPEN_FILE } as BusinessError);
741        return;
742      }
743    }
744    try {
745      await this.getAccountAndOpenDLPFile(startId);
746      await this.getPolicyAndInstallSandbox(startId);
747      await this.getUriInfo(startId);
748    } catch {
749      return;
750    }
751    this.grandUriPermission();
752    this.startSandboxApp(startId, want);
753    AppStorage.setOrCreate('hiCode', Constants.DLP_START_SANDBOX_SUCCESS);
754    sendDlpFileOpenProperties();
755    hiTraceMeter.finishTrace('DlpOpenFileJs', startId);
756  }
757}
758