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