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 path from 'path'; 17import fs from 'fs'; 18import { 19 ArkObfuscator, 20 initObfuscationConfig, 21 readProjectPropertiesByCollectedPaths, 22 performancePrinter, 23 EventList, 24 blockPrinter, 25 endFilesEvent, 26 startFilesEvent 27} from 'arkguard'; 28 29import { 30 TS2ABC, 31 ESMODULE, 32 NODE_MODULES, 33 OH_MODULES, 34 OBFUSCATION_TOOL 35} from './ark_define'; 36import { 37 isAotMode, 38 isDebug, 39 isBranchElimination 40} from '../utils'; 41import { 42 isHarmonyOs, 43 isLinux, 44 isMac, 45 isWindows, 46 toUnixPath 47} from '../../../utils'; 48import { getArkBuildDir } from '../../../ark_utils'; 49import { checkAotConfig } from '../../../gen_aot'; 50import { projectConfig as mainProjectConfig } from '../../../../main'; 51import type { MergedConfig } from './ob_config_resolver'; 52import type { ReseverdSetForArkguard } from 'arkguard'; 53import { MemoryMonitor } from '../../meomry_monitor/rollup-plugin-memory-monitor'; 54import { MemoryDefine } from '../../meomry_monitor/memory_define'; 55import { initObfLogger, printObfLogger } from './ob_config_resolver'; 56 57type ArkConfig = { 58 arkRootPath: string; 59 ts2abcPath: string; 60 js2abcPath: string; 61 mergeAbcPath: string; 62 es2abcPath: string; 63 aotCompilerPath: string; 64 nodePath: string; 65 isDebug: boolean; 66 isBranchElimination: boolean; 67 optTryCatchFunc: boolean; 68}; 69 70export function initArkConfig(projectConfig: Object): ArkConfig { 71 let arkRootPath: string = path.join(__dirname, '..', '..', '..', '..', 'bin', 'ark'); 72 if (projectConfig.arkFrontendDir) { 73 arkRootPath = projectConfig.arkFrontendDir; 74 } 75 let arkConfig: ArkConfig = { 76 arkRootPath: '', 77 ts2abcPath: '', 78 js2abcPath: '', 79 mergeAbcPath: '', 80 es2abcPath: '', 81 aotCompilerPath: '', 82 nodePath: '', 83 isDebug: false, 84 isBranchElimination: false, 85 optTryCatchFunc: false 86 }; 87 arkConfig.nodePath = 'node'; 88 if (projectConfig.nodeJs) { 89 arkConfig.nodePath = projectConfig.nodePath; 90 } 91 arkConfig.isDebug = isDebug(projectConfig); 92 arkConfig.isBranchElimination = isBranchElimination(projectConfig); 93 arkConfig.optTryCatchFunc = mainProjectConfig.optTryCatchFunc; 94 arkConfig.arkRootPath = arkRootPath; 95 processPlatformInfo(arkConfig); 96 processCompatibleVersion(projectConfig, arkConfig); 97 return arkConfig; 98} 99 100export function initArkProjectConfig(share: Object): Object { 101 let projectConfig: Object = share.projectConfig; 102 let arkProjectConfig: Object = {}; 103 let entryPackageName: string = share.projectConfig.entryPackageName || ''; 104 let entryModuleVersion: string = share.projectConfig.entryModuleVersion || ''; 105 arkProjectConfig.entryPackageInfo = `${entryPackageName}|${entryModuleVersion}`; 106 arkProjectConfig.projectRootPath = share.projectConfig.projectTopDir; 107 if (projectConfig.aceBuildJson && fs.existsSync(projectConfig.aceBuildJson)) { 108 const buildJsonInfo = JSON.parse(fs.readFileSync(projectConfig.aceBuildJson).toString()); 109 arkProjectConfig.projectRootPath = buildJsonInfo.projectRootPath; 110 arkProjectConfig.modulePathMap = buildJsonInfo.modulePathMap; 111 arkProjectConfig.isOhosTest = buildJsonInfo.isOhosTest; 112 arkProjectConfig.arkRouterMap = buildJsonInfo.routerMap; 113 // Collect bytecode har's declaration files entries include dynamic import and workers, use 114 // by es2abc for dependency resolution. 115 arkProjectConfig.declarationEntry = buildJsonInfo.declarationEntry; 116 if (buildJsonInfo.patchConfig) { 117 arkProjectConfig.oldMapFilePath = buildJsonInfo.patchConfig.oldMapFilePath; 118 } 119 if (checkAotConfig(projectConfig.compileMode, buildJsonInfo, 120 (error: string) => { share.throwArkTsCompilerError(error) })) { 121 arkProjectConfig.processTs = true; 122 arkProjectConfig.pandaMode = TS2ABC; 123 arkProjectConfig.anBuildOutPut = buildJsonInfo.anBuildOutPut; 124 arkProjectConfig.anBuildMode = buildJsonInfo.anBuildMode; 125 arkProjectConfig.apPath = buildJsonInfo.apPath; 126 } else { 127 arkProjectConfig.processTs = false; 128 arkProjectConfig.pandaMode = buildJsonInfo.pandaMode; 129 } 130 131 if (projectConfig.compileMode === ESMODULE) { 132 arkProjectConfig.nodeModulesPath = buildJsonInfo.nodeModulesPath; 133 // harNameOhmMap stores har packages that are dependent for bytecode har when compile bytecode har. 134 arkProjectConfig.harNameOhmMap = buildJsonInfo.harNameOhmMap; 135 arkProjectConfig.hspNameOhmMap = buildJsonInfo.hspNameOhmMap; 136 projectConfig.packageDir = buildJsonInfo.packageManagerType === 'ohpm' ? OH_MODULES : NODE_MODULES; 137 } 138 if (buildJsonInfo.dynamicImportLibInfo) { 139 arkProjectConfig.dynamicImportLibInfo = buildJsonInfo.dynamicImportLibInfo; 140 } 141 if (buildJsonInfo.byteCodeHarInfo) { 142 arkProjectConfig.byteCodeHarInfo = buildJsonInfo.byteCodeHarInfo; 143 } 144 // Currently, the IDE does not have this configuration option, and cacheBytecodeHar is true by default. 145 arkProjectConfig.cacheBytecodeHar = !Object.prototype.hasOwnProperty.call(buildJsonInfo, 'cacheBytecodeHar') || 146 buildJsonInfo.cacheBytecodeHar; 147 } 148 if (projectConfig.aceManifestPath && fs.existsSync(projectConfig.aceManifestPath)) { 149 const manifestJsonInfo = JSON.parse(fs.readFileSync(projectConfig.aceManifestPath).toString()); 150 if (manifestJsonInfo.minPlatformVersion) { 151 arkProjectConfig.minPlatformVersion = manifestJsonInfo.minPlatformVersion; 152 } 153 } 154 if (projectConfig.aceModuleJsonPath && fs.existsSync(projectConfig.aceModuleJsonPath)) { 155 const moduleJsonInfo = JSON.parse(fs.readFileSync(projectConfig.aceModuleJsonPath).toString()); 156 if (moduleJsonInfo.app.minAPIVersion) { 157 arkProjectConfig.minPlatformVersion = moduleJsonInfo.app.minAPIVersion; 158 } 159 if (moduleJsonInfo.module) { 160 arkProjectConfig.moduleName = moduleJsonInfo.module.name; 161 } 162 if (moduleJsonInfo.app) { 163 arkProjectConfig.bundleName = moduleJsonInfo.app.bundleName; 164 } 165 } 166 167 // Hotreload attributes are initialized by arkui in main.js, just copy them. 168 arkProjectConfig.hotReload = mainProjectConfig.hotReload; 169 arkProjectConfig.coldReload = mainProjectConfig.coldReload; 170 arkProjectConfig.isFirstBuild = mainProjectConfig.isFirstBuild; 171 arkProjectConfig.patchAbcPath = mainProjectConfig.patchAbcPath; 172 arkProjectConfig.changedFileList = mainProjectConfig.changedFileList; 173 174 if (mainProjectConfig.es2abcCompileTsInAotMode || mainProjectConfig.es2abcCompileTsInNonAotMode) { 175 arkProjectConfig.pandaMode = mainProjectConfig.pandaMode; 176 arkProjectConfig.processTs = mainProjectConfig.processTs; 177 } 178 arkProjectConfig.compileMode = projectConfig.compileMode; 179 arkProjectConfig.entryObj = mainProjectConfig.entryObj; 180 arkProjectConfig.entryArrayForObf = mainProjectConfig.entryArrayForObf; 181 arkProjectConfig.cardEntryObj = mainProjectConfig.cardEntryObj; 182 if (mainProjectConfig.updateVersionInfo) { 183 arkProjectConfig.updateVersionInfo = mainProjectConfig.updateVersionInfo; 184 } 185 if (!isDebug(projectConfig)) { 186 arkProjectConfig.useTsHar = mainProjectConfig.useTsHar; 187 startFilesEvent(EventList.OBFUSCATION_INITIALIZATION, performancePrinter.timeSumPrinter); 188 const recordInfo = MemoryMonitor.recordStage(MemoryDefine.INIT_ARK_PROJECT_CONFIG); 189 MemoryMonitor.stopRecordStage(recordInfo); 190 initObfLogger(share); 191 initObfuscationConfig(projectConfig, arkProjectConfig, printObfLogger); 192 endFilesEvent(EventList.OBFUSCATION_INITIALIZATION, performancePrinter.timeSumPrinter); 193 } else { 194 // Set performance printer to undefined in case we cannot disable it without obfuscation initialization 195 blockPrinter(); 196 } 197 return arkProjectConfig; 198} 199 200function initTerserConfig(projectConfig: any, logger: any, mergedObConfig: MergedConfig, isHarCompiled: boolean): any { 201 const isCompact = projectConfig.obfuscationOptions ? mergedObConfig.options.compact : isHarCompiled; 202 const minifyOptions = { 203 format: { 204 beautify: !isCompact, 205 indent_level: 2 206 }, 207 compress: { 208 join_vars: false, 209 sequences: 0, 210 directives: false, 211 drop_console: mergedObConfig.options.removeLog 212 }, 213 mangle: { 214 reserved: mergedObConfig.reservedNames, 215 toplevel: mergedObConfig.options.enableToplevelObfuscation 216 } 217 }; 218 const applyNameCache: string | undefined = mergedObConfig.options.applyNameCache; 219 if (applyNameCache && applyNameCache.length > 0) { 220 if (fs.existsSync(applyNameCache)) { 221 minifyOptions.nameCache = JSON.parse(fs.readFileSync(applyNameCache, 'utf-8')); 222 } else { 223 logger.error(`ArkTS:ERROR Namecache file ${applyNameCache} does not exist`); 224 } 225 } else { 226 if (projectConfig.obfuscationOptions && projectConfig.obfuscationOptions.obfuscationCacheDir) { 227 const defaultNameCachePath: string = path.join(projectConfig.obfuscationOptions.obfuscationCacheDir, 'nameCache.json'); 228 if (fs.existsSync(defaultNameCachePath)) { 229 minifyOptions.nameCache = JSON.parse(fs.readFileSync(defaultNameCachePath, 'utf-8')); 230 } else { 231 minifyOptions.nameCache = {}; 232 } 233 } 234 } 235 236 if (mergedObConfig.options.enablePropertyObfuscation) { 237 minifyOptions.mangle.properties = { 238 reserved: mergedObConfig.reservedPropertyNames, 239 keep_quoted: !mergedObConfig.options.enableStringPropertyObfuscation 240 }; 241 } 242 return minifyOptions; 243} 244 245// Scan the source code of project and libraries to collect whitelists. 246export function readProjectAndLibsSource(allFiles: Set<string>, mergedObConfig: MergedConfig, arkObfuscator: ArkObfuscator, isHarCompiled: boolean, 247 keepFilesAndDependencies: Set<string>): void { 248 if (mergedObConfig?.options === undefined || mergedObConfig.options.disableObfuscation || allFiles.size === 0) { 249 return; 250 } 251 const obfOptions = mergedObConfig.options; 252 let projectAndLibs: ReseverdSetForArkguard = readProjectPropertiesByCollectedPaths(allFiles, 253 { 254 mNameObfuscation: { 255 mEnable: true, 256 mReservedProperties: [], 257 mRenameProperties: obfOptions.enablePropertyObfuscation, 258 mKeepStringProperty: !obfOptions.enableStringPropertyObfuscation, 259 mEnableAtKeep: obfOptions.enableAtKeep 260 }, 261 mExportObfuscation: obfOptions.enableExportObfuscation, 262 mKeepFileSourceCode: { 263 mKeepSourceOfPaths: new Set(), 264 mkeepFilesAndDependencies: keepFilesAndDependencies, 265 } 266 }, isHarCompiled); 267 if (obfOptions.enablePropertyObfuscation) { 268 arkObfuscator.addReservedSetForPropertyObf(projectAndLibs); 269 } 270 if (obfOptions.enableExportObfuscation) { 271 arkObfuscator.addReservedSetForDefaultObf(projectAndLibs); 272 } 273 if (obfOptions.enableAtKeep) { 274 // emit atKeep names and consumer configs 275 arkObfuscator.obfConfigResolver.emitConsumerConfigFiles(); 276 } 277} 278 279function processPlatformInfo(arkConfig: ArkConfig): void { 280 const arkPlatformPath: string = getArkBuildDir(arkConfig.arkRootPath); 281 if (isWindows()) { 282 arkConfig.es2abcPath = path.join(arkPlatformPath, 'bin', 'es2abc.exe'); 283 arkConfig.ts2abcPath = path.join(arkPlatformPath, 'src', 'index.js'); 284 arkConfig.mergeAbcPath = path.join(arkPlatformPath, 'bin', 'merge_abc.exe'); 285 arkConfig.js2abcPath = path.join(arkPlatformPath, 'bin', 'js2abc.exe'); 286 arkConfig.aotCompilerPath = path.join(arkPlatformPath, 'bin', 'ark_aot_compiler.exe'); 287 return; 288 } 289 if (isLinux() || isMac()) { 290 arkConfig.es2abcPath = path.join(arkPlatformPath, 'bin', 'es2abc'); 291 arkConfig.ts2abcPath = path.join(arkPlatformPath, 'src', 'index.js'); 292 arkConfig.mergeAbcPath = path.join(arkPlatformPath, 'bin', 'merge_abc'); 293 arkConfig.js2abcPath = path.join(arkPlatformPath, 'bin', 'js2abc'); 294 arkConfig.aotCompilerPath = path.join(arkPlatformPath, 'bin', 'ark_aot_compiler'); 295 return; 296 } 297 if (isHarmonyOs()) { 298 arkConfig.es2abcPath = path.join(arkPlatformPath, 'bin', 'es2abc'); 299 return; 300 } 301} 302 303function processCompatibleVersion(projectConfig: Object, arkConfig: ArkConfig): void { 304 const platformPath: string = getArkBuildDir(arkConfig.arkRootPath); 305 if (projectConfig.minPlatformVersion && projectConfig.minPlatformVersion.toString() === '8') { 306 // use ts2abc to compile apps with 'CompatibleSdkVersion' set to 8 307 arkConfig.ts2abcPath = path.join(platformPath, 'legacy_api8', 'src', 'index.js'); 308 projectConfig.pandaMode = TS2ABC; 309 } 310} 311 312export const utProcessArkConfig = { 313 processCompatibleVersion, 314 initTerserConfig 315}; 316