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