1 /* 2 * Copyright (c) 2021-2025 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 package ohos; 17 18 import java.io.BufferedInputStream; 19 import java.io.BufferedReader; 20 import java.io.BufferedWriter; 21 import java.io.File; 22 import java.io.FileInputStream; 23 import java.io.FileNotFoundException; 24 import java.io.FileOutputStream; 25 import java.io.FileWriter; 26 import java.io.IOException; 27 import java.io.InputStream; 28 import java.io.InputStreamReader; 29 import java.io.OutputStream; 30 import java.io.OutputStreamWriter; 31 import java.nio.charset.StandardCharsets; 32 import java.nio.file.Files; 33 import java.nio.file.Path; 34 import java.nio.file.Paths; 35 import java.security.MessageDigest; 36 import java.security.NoSuchAlgorithmException; 37 import java.util.ArrayList; 38 import java.util.Arrays; 39 import java.util.concurrent.ExecutionException; 40 import java.util.Enumeration; 41 import java.util.HashMap; 42 import java.util.Map; 43 import java.util.List; 44 import java.util.Locale; 45 import java.util.Optional; 46 import java.util.concurrent.LinkedBlockingQueue; 47 import java.util.concurrent.ThreadPoolExecutor; 48 import java.util.concurrent.TimeUnit; 49 import java.util.regex.Matcher; 50 import java.util.regex.Pattern; 51 import java.util.UUID; 52 import java.util.stream.Stream; 53 import java.util.zip.CRC32; 54 import java.util.zip.CheckedOutputStream; 55 import java.util.zip.ZipInputStream; 56 import java.util.zip.ZipEntry; 57 import java.util.zip.ZipFile; 58 import java.util.zip.ZipOutputStream; 59 import com.alibaba.fastjson.JSON; 60 import com.alibaba.fastjson.JSONArray; 61 import com.alibaba.fastjson.JSONException; 62 import com.alibaba.fastjson.JSONObject; 63 import com.alibaba.fastjson.serializer.SerializerFeature; 64 import org.apache.commons.compress.archivers.zip.DefaultBackingStoreSupplier; 65 import org.apache.commons.compress.archivers.zip.ParallelScatterZipCreator; 66 import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; 67 import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream; 68 import org.apache.commons.compress.parallel.InputStreamSupplier; 69 70 /** 71 * bundle compressor class, compress file and directory. 72 * 73 */ 74 public class Compressor { 75 private static final String HAP_SUFFIX = ".hap"; 76 private static final String HSP_SUFFIX = ".hsp"; 77 private static final String PNG_SUFFIX = ".png"; 78 private static final String UPPERCASE_PNG_SUFFIX = ".PNG"; 79 private static final String CONFIG_JSON = "config.json"; 80 private static final String MODULE_JSON = "module.json"; 81 private static final String PATCH_JSON = "patch.json"; 82 private static final String ADDITION_JSON = "addition.json"; 83 private static final String PKG_CONTEXT_INFO = "pkgContextInfo.json"; 84 private static final String NAME = "name"; 85 private static final String NULL_DIR_NAME = ""; 86 private static final String RES_DIR_NAME = "res/"; 87 private static final String RESOURCES_DIR_NAME = "resources/"; 88 private static final String LIBS_DIR_NAME = "libs/"; 89 private static final String AN_DIR_NAME = "an/"; 90 private static final String AP_PATH_NAME = "ap/"; 91 private static final String ASSETS_DIR_NAME = "assets/"; 92 private static final String SO_DIR_NAME = "maple/"; 93 private static final String SO_ARM64_DIR_NAME = "maple/arm64/"; 94 private static final String LINUX_FILE_SEPARATOR = "/"; 95 private static final String DISTRO = "distro"; 96 private static final String FORMS = "forms"; 97 private static final String MODULE_NAME = "module-name"; 98 private static final String MODULE_NAME_NEW = "moduleName"; 99 private static final String JSON_END = "}"; 100 private static final String SEMICOLON = "\""; 101 private static final String COMPRESS_NATIVE_LIBS = "compressNativeLibs"; 102 private static final String SHARED_LIBS_DIR_NAME = "shared_libs/"; 103 private static final String DEVICE_TYPE = "deviceType"; 104 private static final String DEVICE_TYPE_FITNESSWATCH = "fitnessWatch"; 105 private static final String DEVICE_TYPE_FITNESSWATCH_NEW = "liteWearable"; 106 private static final String ENTRYCARD_NAME = "EntryCard/"; 107 private static final String PACKINFO_NAME = "pack.info"; 108 private static final String ENTRYCARD_BASE_NAME = "base"; 109 private static final String ENTRYCARD_SNAPSHOT_NAME = "snapshot"; 110 private static final String PIC_1X2 = "1x2"; 111 private static final String PIC_2X2 = "2x2"; 112 private static final String PIC_2X4 = "2x4"; 113 private static final String PIC_4X4 = "4x4"; 114 private static final String PIC_1X1 = "1x1"; 115 private static final String PIC_6X4 = "6x4"; 116 private static final String REGEX_LANGUAGE = "^[a-z]{2}$"; 117 private static final String REGEX_SCRIPT = "^[A-Z][a-z]{3}$"; 118 private static final String REGEX_COUNTRY = "^[A-Z]{2,3}|[0-9]{3}$"; 119 private static final String REGEX_ORIENTATION = "^vertical|horizontal$"; 120 private static final String REGEX_DEVICE_TYPE = "^phone|tablet|car|tv|wearable|liteWearable|2in1$"; 121 private static final String REGEX_SCREEN_DENSITY = "^sdpi|mdpi|ldpi|xldpi|xxldpi$"; 122 private static final String REGEX_COLOR_MODE = "^light|dark$"; 123 private static final String REGEX_SHAPE = "^circle$"; 124 private static final String JS_PATH = "js/"; 125 private static final String ETS_PATH = "ets/"; 126 private static final String HNP_PATH = "hnp/"; 127 private static final String TEMP_HAP_DIR = "tempHapDir"; 128 private static final String TEMP_HSP_DIR = "tempHspDir"; 129 private static final String TEMP_SELECTED_HAP_DIR = "tempSelectedHapDir"; 130 private static final String EMPTY_STRING = ""; 131 private static final String RELEASE = "Release"; 132 private static final String TYPE_SHARED = "shared"; 133 private static final String APP = "app"; 134 private static final String TYPE_APP_PLUGIN = "appPlugin"; 135 private static final String REQUEST_PERMISSIONS = "requestPermissions"; 136 private static final String PERMISSION_SUPPORT_PLUGIN = "ohos.permission.kernel.SUPPORT_PLUGIN"; 137 private static final String EXTENSION_ABILITIES = "extensionAbilities"; 138 private static final String MODULE = "module"; 139 private static final String MODULES = "modules"; 140 private static final String GENERATE_BUILD_HASH = "generateBuildHash"; 141 private static final String BUILD_HASH = "buildHash"; 142 private static final String TEMP_DIR = "temp"; 143 private static final String SHA_256 = "SHA-256"; 144 private static final String JSON_SUFFIX = ".json"; 145 private static final String ATOMIC_SERVICE = "atomicService"; 146 private static final String RAW_FILE_PATH = "resources/rawfile"; 147 private static final String RES_FILE_PATH = "resources/resfile"; 148 private static final String SUMMARY = "summary"; 149 private static final String VERSION_CODE = "versionCode"; 150 private static final String VERSION_NAME = "versionName"; 151 private static final String DEVICE_TYPES = "deviceTypes"; 152 private static final String BUNDLE_NAME = "bundleName"; 153 private static final String MIN_COMPATIBLE_VERSION_CODE = "minCompatibleVersionCode"; 154 private static final String MIN_API_VERSION = "minAPIVersion"; 155 private static final String TARGET_API_VERSION = "targetAPIVersion"; 156 private static final String API_RELEASE_TYPE = "apiReleaseType"; 157 private static final String BUNDLE_TYPE = "bundleType"; 158 private static final String INSTALLATION_FREE = "installationFree"; 159 private static final String DELIVERY_WITH_INSTALL = "deliveryWithInstall"; 160 private static final String API_VERSION = "apiVersion"; 161 private static final String RELEASE_TYPE = "releaseType"; 162 private static final String TARGET = "target"; 163 private static final String COMPATIBLE = "compatible"; 164 private static final String PACKAGES = "packages"; 165 private static final String VERSION = "version"; 166 private static final String CODE = "code"; 167 private static final String VERSION_RECORD = "version_record.json"; 168 private static final String GENERAL_RECORD = "general_record.json"; 169 private static final String RES_INDEX = "resources.index"; 170 private static final String ETS_FILE_NAME = "ets"; 171 private static final String HNP_FILE_NAME = "hnp"; 172 private static final String DIR_FILE_NAME = "dir"; 173 private static final String AN_FILE_NAME = "an"; 174 private static final String AP_FILE_NAME = "ap"; 175 private static final String RESOURCE_FILE_NAME = "resources"; 176 private static final String JS_FILE_NAME = "js"; 177 private static final String ASSETS_FILE_NAME = "assets"; 178 private static final String MAPLE_FILE_NAME = "maple"; 179 private static final String SHARED_LIBS_FILE_NAME = "shared_libs"; 180 private static final String LIBS_DIR = "libs"; 181 private static final String RPCID = "rpcid.sc"; 182 private static final String HAPADDITION_FOLDER_NAME = "hapAddition"; 183 private static final String TARGET_FILE_PATH = HAPADDITION_FOLDER_NAME + LINUX_FILE_SEPARATOR + "resources" 184 + LINUX_FILE_SEPARATOR + "base" + LINUX_FILE_SEPARATOR + "profile"; 185 private static final String BACKUP_PREFIX = "backup"; 186 187 // set timestamp to get fixed MD5 188 private static final int ATOMIC_SERVICE_ENTRY_SIZE_LIMIT_DEFAULT = 2048; // 2MB;unit is KB 189 private static final int ATOMIC_SERVICE_NON_ENTRY_SIZE_LIMIT_DEFAULT = 2048; // 2MB;unit is KB 190 private static final int ATOMIC_SERVICE_TOTAL_SIZE_LIMIT_DEFAULT = 4194304; // 4GB;unit is KB 191 private static final int ATOMIC_SERVICE_TOTAL_SIZE_LIMIT_MAX = 4194304; // 4GB;unit is KB 192 private static final int SHA256_BASE = 0xff; 193 private static final int SHA256_OFFSET = 0x100; 194 private static final int RADIX = 16; 195 private static final int BEGIN_INDEX = 1; 196 private static final int BUFFER_BYTE_SIZE = 1024; 197 private static final int BUFFER_WRITE_SIZE = 1444; 198 199 // set buffer size of each read 200 private static final int BUFFER_SIZE = 40 * 1024; 201 private static final Log LOG = new Log(Compressor.class.toString()); 202 private static final int SHARED_APP_HSP_LIMIT = 1; 203 204 private static int entryModuleSizeLimit = 2048; 205 private static int notEntryModuleSizeLimit = 2048; 206 private static int sumModuleSizeLimit = 10240; 207 private static final int INVALID_VERSION = -1; 208 private static boolean isOverlay = false; 209 210 private ZipArchiveOutputStream zipOut = null; 211 private boolean mIsContain2x2EntryCard = true; 212 private boolean isEntryOpen = false; 213 private List<String> list = new ArrayList<String>(); 214 private List<String> formNamesList = new ArrayList<String>(); 215 private List<String> fileNameList = new ArrayList<String>(); 216 private List<String> supportDimensionsList = Arrays.asList(PIC_1X2, PIC_2X2, PIC_2X4, PIC_4X4, PIC_1X1, PIC_6X4); 217 private HashMap<String, HapVerifyInfo> hapVerifyInfoMap = new HashMap<>(); 218 getEntryModuleSizeLimit()219 public static int getEntryModuleSizeLimit() { 220 return entryModuleSizeLimit; 221 } 222 setEntryModuleSizeLimit(int entry)223 public static void setEntryModuleSizeLimit(int entry) { 224 entryModuleSizeLimit = entry; 225 } 226 getNotEntryModuleSizeLimit()227 public static int getNotEntryModuleSizeLimit() { 228 return notEntryModuleSizeLimit; 229 } 230 setNotEntryModuleSizeLimit(int notEntry)231 public static void setNotEntryModuleSizeLimit(int notEntry) { 232 notEntryModuleSizeLimit = notEntry; 233 } 234 getSumModuleSizeLimit()235 public static int getSumModuleSizeLimit() { 236 return sumModuleSizeLimit; 237 } 238 setSumModuleSizeLimit(int sumModule)239 public static void setSumModuleSizeLimit(int sumModule) { 240 sumModuleSizeLimit = sumModule; 241 } 242 243 private static class VersionNormalizeUtil { 244 private int originVersionCode = INVALID_VERSION; 245 private String originVersionName = ""; 246 private String moduleName = ""; 247 getOriginVersionCode()248 public int getOriginVersionCode() { 249 return originVersionCode; 250 } 251 setOriginVersionCode(int originVersionCode)252 public void setOriginVersionCode(int originVersionCode) { 253 this.originVersionCode = originVersionCode; 254 } 255 getModuleName()256 public String getModuleName() { 257 return moduleName; 258 } 259 setModuleName(String name)260 public void setModuleName(String name) { 261 this.moduleName = name; 262 } 263 getOriginVersionName()264 public String getOriginVersionName() { 265 return originVersionName; 266 } 267 setOriginVersionName(String originVersionName)268 public void setOriginVersionName(String originVersionName) { 269 this.originVersionName = originVersionName; 270 } 271 } 272 273 private static class GeneralNormalizeUtil { 274 private int originVersionCode = INVALID_VERSION; 275 private String originVersionName = ""; 276 private String moduleName = ""; 277 private String originBundleName = ""; 278 private int originMinCompatibleVersionCode = INVALID_VERSION; 279 private int originMinAPIVersion = INVALID_VERSION; 280 private int originTargetAPIVersion = INVALID_VERSION; 281 private String originApiReleaseType = ""; 282 private String originBundleType = ""; 283 private boolean originInstallationFree = false; 284 private boolean originDeliveryWithInstall = false; 285 private String originDeviceTypes = ""; 286 private boolean isInstallationFree = false; 287 private boolean isDeliveryWithInstall = false; 288 setOriginVersionCode(int originVersionCode)289 public void setOriginVersionCode(int originVersionCode) { 290 this.originVersionCode = originVersionCode; 291 } 292 setModuleName(String name)293 public void setModuleName(String name) { 294 this.moduleName = name; 295 } 296 setOriginVersionName(String originVersionName)297 public void setOriginVersionName(String originVersionName) { 298 this.originVersionName = originVersionName; 299 } 300 setOriginBundleName(String originBundleName )301 public void setOriginBundleName(String originBundleName ) { 302 this.originBundleName = originBundleName; 303 } 304 setOriginMinCompatibleVersionCode(int originMinCompatibleVersionCode)305 public void setOriginMinCompatibleVersionCode(int originMinCompatibleVersionCode) { 306 this.originMinCompatibleVersionCode = originMinCompatibleVersionCode; 307 } 308 setOriginMinAPIVersion(int originMinAPIVersion)309 public void setOriginMinAPIVersion(int originMinAPIVersion) { 310 this.originMinAPIVersion = originMinAPIVersion; 311 } 312 setOriginTargetAPIVersion(int originTargetAPIVersion)313 public void setOriginTargetAPIVersion(int originTargetAPIVersion) { 314 this.originTargetAPIVersion = originTargetAPIVersion; 315 } 316 setOriginApiReleaseType(String originApiReleaseType)317 public void setOriginApiReleaseType(String originApiReleaseType) { 318 this.originApiReleaseType = originApiReleaseType; 319 } 320 setOriginBundleType(String originBundleType)321 public void setOriginBundleType(String originBundleType) { 322 this.originBundleType = originBundleType; 323 } 324 setIsInstallationFree(boolean isInstallationFree)325 public void setIsInstallationFree(boolean isInstallationFree) { 326 this.isInstallationFree = isInstallationFree; 327 } 328 setOriginInstallationFree(boolean originInstallationFree)329 public void setOriginInstallationFree(boolean originInstallationFree) { 330 this.originInstallationFree = originInstallationFree; 331 } 332 setOriginDeliveryWithInstall(boolean originDeliveryWithInstall)333 public void setOriginDeliveryWithInstall(boolean originDeliveryWithInstall) { 334 this.originDeliveryWithInstall = originDeliveryWithInstall; 335 } 336 setIsDeliveryWithInstall(boolean isDeliveryWithInstall)337 public void setIsDeliveryWithInstall(boolean isDeliveryWithInstall) { 338 this.isDeliveryWithInstall = isDeliveryWithInstall; 339 } 340 setOriginDeviceTypes(String originDeviceTypes)341 public void setOriginDeviceTypes(String originDeviceTypes) { 342 this.originDeviceTypes = originDeviceTypes; 343 } 344 } 345 346 /** 347 * Parse atomicService size limit parameter from utility. 348 * 349 * @param utility Indicates the utility. 350 */ parseAtomicServiceSizeLimit(Utility utility)351 public void parseAtomicServiceSizeLimit(Utility utility) throws BundleException { 352 parseAtomicServiceEntrySizeLimitParameter(utility); 353 parseAtomicServiceNonEntrySizeLimitParameter(utility); 354 } 355 parseAtomicServiceSumSizeLimitParameter(Utility utility)356 private int parseAtomicServiceSumSizeLimitParameter(Utility utility) throws BundleException{ 357 int sumLimit = ATOMIC_SERVICE_TOTAL_SIZE_LIMIT_DEFAULT; 358 String totalLimit = utility.getAtomicServiceTotalSizeLimit(); 359 if (!totalLimit.isEmpty()) { 360 try { 361 sumLimit = Integer.parseInt(totalLimit); 362 } catch (NumberFormatException e) { 363 String errMsg = "parseAtomicServiceSumSizeLimitParameter failed, input --atomic-service-total-size-limit invalid."; 364 String solution = "Check the --atomic-service-total-size-limit parameter."; 365 LOG.error(PackingToolErrMsg.PARSE_ATOMIC_SERVICE_SIZE_LIMIT_FAILED.toString(errMsg, solution)); 366 throw new BundleException("parseAtomicServiceSumSizeLimitParameter failed, " + 367 "input --atomic-service-total-size-limit invalid."); 368 } 369 if (sumLimit < 0 || sumLimit > ATOMIC_SERVICE_TOTAL_SIZE_LIMIT_MAX) { 370 String errMsg = "parseAtomicServiceSumSizeLimitParameter failed, " + 371 "input --atomic-service-total-size-limit value out of range [0,4194304]."; 372 String solution = "Check the --atomic-service-total-size-limit parameter is " + 373 "within the range of [0,4194304]."; 374 LOG.error(PackingToolErrMsg.PARSE_ATOMIC_SERVICE_SIZE_LIMIT_FAILED.toString(errMsg, solution)); 375 throw new BundleException("parseAtomicServiceSumSizeLimitParameter failed, " + 376 "input --atomic-service-total-size-limit value out of range [0,4194304]."); 377 } 378 } 379 setSumModuleSizeLimit(sumLimit); 380 return sumLimit; 381 } 382 parseAtomicServiceEntrySizeLimitParameter(Utility utility)383 private void parseAtomicServiceEntrySizeLimitParameter(Utility utility) throws BundleException{ 384 String entrySizeLimitParamValue = utility.getAtomicServiceEntrySizeLimit(); 385 int entryLimit = ATOMIC_SERVICE_ENTRY_SIZE_LIMIT_DEFAULT; 386 if (!entrySizeLimitParamValue.isEmpty()) { 387 try { 388 entryLimit = Integer.parseInt(entrySizeLimitParamValue); 389 } catch (NumberFormatException e) { 390 String errMsg = "parseAtomicServiceEntrySizeLimitParameter failed, " + 391 "input --atomic-service-entry-size-limit invalid."; 392 String solution = "Check the --atomic-service-entry-size-limit parameter is invalid"; 393 LOG.error(PackingToolErrMsg.PARSE_ATOMIC_SERVICE_SIZE_LIMIT_FAILED.toString(errMsg, solution)); 394 throw new BundleException("parseAtomicServiceEntrySizeLimitParameter failed, " + 395 "input --atomic-service-entry-size-limit invalid."); 396 } 397 if (entryLimit < 0 || entryLimit > ATOMIC_SERVICE_TOTAL_SIZE_LIMIT_MAX) { 398 String errMsg = "parseAtomicServiceEntrySizeLimitParameter failed, " + 399 "input --atomic-service-entry-size-limit value out of range [0,4194304]."; 400 String solution = "Check the --atomic-service-entry-size-limit parameter is " + 401 "within the valid range [0,4194304]."; 402 LOG.error(PackingToolErrMsg.PARSE_ATOMIC_SERVICE_SIZE_LIMIT_FAILED.toString(errMsg, solution)); 403 throw new BundleException("parseAtomicServiceEntrySizeLimitParameter failed, " + 404 "input --atomic-service-entry-size-limit value out of range [0,4194304]."); 405 } 406 } 407 setEntryModuleSizeLimit(entryLimit); 408 } 409 parseAtomicServiceNonEntrySizeLimitParameter(Utility utility)410 private void parseAtomicServiceNonEntrySizeLimitParameter(Utility utility) throws BundleException{ 411 String nonEntryLimitParamValue = utility.getAtomicServiceNonEntrySizeLimit(); 412 int notEntryLimit = ATOMIC_SERVICE_NON_ENTRY_SIZE_LIMIT_DEFAULT; 413 if (!nonEntryLimitParamValue.isEmpty()) { 414 try { 415 notEntryLimit = Integer.parseInt(nonEntryLimitParamValue); 416 } catch (NumberFormatException e) { 417 String errMsg = "parseAtomicServiceSizeLimit failed, " + 418 "input --atomic-service-non-entry-size-limit invalid."; 419 String solution = "Check the --atomic-service-non-entry-size-limit parameter"; 420 LOG.error(PackingToolErrMsg.PARSE_ATOMIC_SERVICE_SIZE_LIMIT_FAILED.toString(errMsg, solution)); 421 throw new BundleException("parseAtomicServiceSizeLimit failed, " + 422 "input --atomic-service-non-entry-size-limit invalid."); 423 } 424 if (notEntryLimit < 0 || notEntryLimit > ATOMIC_SERVICE_TOTAL_SIZE_LIMIT_MAX) { 425 String errMsg = "parseAtomicServiceSizeLimit failed, " + 426 "input --atomic-service-non-entry-size-limit value out of range [0,4194304]."; 427 String solution = "Check the --atomic-service-non-entry-size-limit parameter is " + 428 "within the valid range [0,4194304]."; 429 LOG.error(PackingToolErrMsg.PARSE_ATOMIC_SERVICE_SIZE_LIMIT_FAILED.toString(errMsg, solution)); 430 throw new BundleException("parseAtomicServiceSizeLimit failed, " + 431 "input --atomic-service-non-entry-size-limit value out of range [0,4194304]."); 432 } 433 } 434 setNotEntryModuleSizeLimit(notEntryLimit); 435 } 436 437 /** 438 * check path if is a module.json file 439 * 440 * @param path path input 441 * @return true if path is a module file 442 */ isModuleJSON(String path)443 private static boolean isModuleJSON(String path) 444 { 445 File file = new File(path); 446 if ((file.isFile()) && MODULE_JSON.equals(file.getName())) { 447 return true; 448 } 449 return false; 450 } 451 452 /** 453 * start compress. 454 * file orders as follows: 455 * for hap: 1.config.json 2.lib 3.res 4.assets 5.*.so 6.*.dex 7.*.apk 8.resources.index 456 * for app: 1.certificate 2.signature 3.pack.info 4.hap (1 and 2 may not be used) 457 * 458 * @param utility common data 459 * @return compressProcess if compress succeed 460 */ compressProcess(Utility utility)461 public boolean compressProcess(Utility utility) { 462 switch (utility.getMode()) { 463 case Utility.VERSION_NORMALIZE: 464 versionNormalize(utility); 465 return true; 466 case Utility.MODE_HAPADDITION: 467 hapAddition(utility); 468 return true; 469 case Utility.PACKAGE_NORMALIZE: 470 return PackageNormalize.normalize(utility); 471 case Utility.GENERAL_NORMALIZE: 472 generalNormalize(utility); 473 return true; 474 default: 475 return defaultProcess(utility); 476 } 477 } 478 defaultProcess(Utility utility)479 private boolean defaultProcess(Utility utility) { 480 File destFile = new File(utility.getOutPath()); 481 // if out file directory not exist, mkdirs. 482 File outParentFile = destFile.getParentFile(); 483 if ((outParentFile != null) && (!outParentFile.exists())) { 484 if (!outParentFile.mkdirs()) { 485 String errMsg = "Create output file's parent directory failed."; 486 String solution = "Check the --out-path parameter."; 487 LOG.error(PackingToolErrMsg.COMPRESS_PROCESS_FAILED.toString(errMsg, solution)); 488 return false; 489 } 490 } 491 boolean compressResult = true; 492 FileOutputStream fileOut = null; 493 CheckedOutputStream checkedOut = null; 494 try { 495 parseAtomicServiceSizeLimit(utility); 496 497 fileOut = new FileOutputStream(destFile); 498 checkedOut = new CheckedOutputStream(fileOut, new CRC32()); 499 zipOut = new ZipArchiveOutputStream(checkedOut); 500 zipOut.setLevel(utility.getCompressLevel()); 501 compressExcute(utility); 502 } catch (FileNotFoundException exception) { 503 compressResult = false; 504 LOG.error(PackingToolErrMsg.FILE_NOT_FOUND.toString( 505 "Compress exist FileNotFoundException: " + exception.getMessage())); 506 } catch (BundleException ex) { 507 compressResult = false; 508 LOG.error(PackingToolErrMsg.COMPRESS_PROCESS_EXCEPTION.toString( 509 "Compress exist BundleException: " + ex.getMessage())); 510 } finally { 511 closeZipOutputStream(); 512 Utility.closeStream(zipOut); 513 Utility.closeStream(checkedOut); 514 Utility.closeStream(fileOut); 515 } 516 517 if (compressResult && !checkAppAtomicServiceCompressedSizeValid(utility)) { 518 compressResult = false; 519 String errMsg = "The size of a single module, or the size of a module plus its dependencies, " + 520 "exceeds the maximum."; 521 LOG.error(PackingToolErrMsg.CHECK_ATOMIC_SERVICE_SIZE_FAILED.toString(errMsg)); 522 } 523 524 // if compress failed, delete out file. 525 if (!compressResult) { 526 String errMsg = "Compress process failed."; 527 String solution = "Please check the first error message for more details and modify accordingly."; 528 LOG.error(PackingToolErrMsg.COMPRESS_PROCESS_FAILED.toString(errMsg, solution)); 529 if (!destFile.delete()) { 530 errMsg = "Delete the output file " + utility.getOutPath() + " failed."; 531 solution = "Try to close the output file using programme."; 532 LOG.error(PackingToolErrMsg.FILE_DELETE_FAILED.toString(errMsg, solution)); 533 } 534 } 535 return compressResult; 536 } 537 compressExcute(Utility utility)538 private void compressExcute(Utility utility) throws BundleException { 539 switch (utility.getMode()) { 540 case Utility.MODE_HAP: 541 compressHap(utility); 542 break; 543 case Utility.MODE_HAR: 544 compressHarMode(utility); 545 break; 546 case Utility.MODE_APP: 547 compressAppMode(utility); 548 break; 549 case Utility.MODE_FAST_APP: 550 compressFastAppMode(utility); 551 break; 552 case Utility.MODE_MULTI_APP: 553 compressAppModeForMultiProject(utility); 554 break; 555 case Utility.MODE_HQF: 556 compressHQFMode(utility); 557 break; 558 case Utility.MODE_APPQF: 559 compressAPPQFMode(utility); 560 break; 561 case Utility.MODE_HSP: 562 compressHsp(utility); 563 break; 564 default: 565 compressPackResMode(utility); 566 } 567 } 568 compressHsp(Utility utility)569 private void compressHsp(Utility utility) throws BundleException { 570 setGenerateBuildHash(utility); 571 if (isModuleJSON(utility.getJsonPath())) { 572 Optional<String> optional = FileUtils.getFileContent(utility.getJsonPath()); 573 String jsonString = optional.get(); 574 if (!checkStageAsanTsanEnabledValid(jsonString)) { 575 LOG.error(PackingToolErrMsg.COMPRESS_HSP_FAILED.toString( 576 "Check the asanTsanEnabled parameter in the Stage module failed.")); 577 throw new BundleException("Compress hsp failed."); 578 } 579 if (!checkStageHwasanEnabledValid(jsonString)) { 580 LOG.error(PackingToolErrMsg.COMPRESS_HSP_FAILED.toString( 581 "Check the hwasanEnabled parameter in the Stage module failed.")); 582 throw new BundleException("Compress hsp failed."); 583 } 584 if (!checkStageUbsanEnabledValid(jsonString)) { 585 LOG.error(PackingToolErrMsg.COMPRESS_HSP_FAILED.toString( 586 "Check the ubsanEnabled parameter in the Stage module failed.")); 587 throw new BundleException("Compress hsp failed."); 588 } 589 if (!checkStageAtomicService(jsonString)) { 590 LOG.error(PackingToolErrMsg.COMPRESS_HSP_FAILED.toString( 591 "Check the atomicService parameter in the Stage module failed.")); 592 throw new BundleException("Check stage AtomicService failed."); 593 } 594 // check continueBundleName in module.json 595 if (!checkContinueBundleNameIsValid(jsonString)) { 596 LOG.error(PackingToolErrMsg.COMPRESS_HSP_FAILED.toString( 597 "Check the continueBundleName parameter in the Stage module failed.")); 598 throw new BundleException("Compress hsp failed."); 599 } 600 // check whether is an overlay hsp or not 601 if (!checkStageOverlayCfg(jsonString)) { 602 LOG.error(PackingToolErrMsg.COMPRESS_HSP_FAILED.toString( 603 "Check the overlay config in the Stage module failed.")); 604 throw new BundleException("Compress hsp failed."); 605 } 606 String moduleType = ModuleJsonUtil.parseModuleType(jsonString); 607 if (!TYPE_SHARED.equals(moduleType)) { 608 LOG.error(PackingToolErrMsg.COMPRESS_HSP_FAILED.toString("Module type must be shared.")); 609 throw new BundleException("Compress hsp failed."); 610 } 611 } 612 if (!checkAppPlugin(utility)) { 613 LOG.error(PackingToolErrMsg.COMPRESS_HSP_FAILED.toString("plugin package packaging failed.")); 614 throw new BundleException("Compress hsp failed."); 615 } 616 compressHSPMode(utility); 617 buildHash(utility); 618 } 619 compressHap(Utility utility)620 private void compressHap(Utility utility) throws BundleException { 621 if (utility.getJsonPath().isEmpty() && !utility.getBinPath().isEmpty()) { 622 // only for slim device 623 compressHapMode(utility); 624 return; 625 } 626 setGenerateBuildHash(utility); 627 if (isModuleJSON(utility.getJsonPath())) { 628 if (!checkStageHap(utility)) { 629 LOG.error(PackingToolErrMsg.COMPRESS_HAP_FAILED.toString( 630 "Verify the module.json file of the Stage HAP package failed.")); 631 throw new BundleException("Verify the module.json file of the Stage HAP package failed."); 632 } 633 Optional<String> optional = FileUtils.getFileContent(utility.getJsonPath()); 634 String jsonString = optional.get(); 635 String moduleType = ModuleJsonUtil.parseModuleType(jsonString); 636 if (TYPE_SHARED.equals(moduleType)) { 637 LOG.warning("Compress mode is hap, but module type is shared."); 638 } 639 String bundleType = ModuleJsonUtil.parseStageBundleType(jsonString); 640 if (TYPE_SHARED.equals(bundleType)) { 641 LOG.warning("Compress mode is hap, but app type is shared."); 642 } 643 if (!TYPE_APP_PLUGIN.equals(bundleType)) { 644 if (!isPluginHost(utility)) { 645 if (!checkPkgContext(utility)) { 646 LOG.error(PackingToolErrMsg.COMPRESS_HAP_FAILED.toString( 647 "plugin package packing failed, the pkgContextInfo.json not exist.")); 648 throw new BundleException("Compress hap failed."); 649 } 650 } 651 } else { 652 LOG.error(PackingToolErrMsg.COMPRESS_HAP_FAILED.toString("hap can not plugin.")); 653 throw new BundleException("Compress hap failed."); 654 } 655 compressHapModeForModule(utility); 656 buildHash(utility); 657 } else { 658 compressHapMode(utility); 659 buildHash(utility); 660 } 661 } 662 isPluginHost(Utility utility)663 private static boolean isPluginHost(Utility utility) throws BundleException { 664 File file = new File(utility.getJsonPath()); 665 if (!file.exists()) { 666 String errMsg = "The --json-path file does not exist."; 667 LOG.error(PackingToolErrMsg.FILE_NOT_EXIST.toString(errMsg)); 668 throw new BundleException("Verify has generate build hash failed for --json-path file does not exist."); 669 } 670 try (InputStream json = new FileInputStream(file)) { 671 JSONObject jsonObject = JSON.parseObject(json, JSONObject.class); 672 if (jsonObject == null || !jsonObject.containsKey(MODULE)) { 673 LOG.error(PackingToolErrMsg.IS_PLUGIN_HOST_FAILED.toString("The --json-path file is invalid.")); 674 throw new BundleException("Parse --json-path file is invalid."); 675 } 676 JSONObject moduleJson = jsonObject.getJSONObject(MODULE); 677 if (moduleJson.containsKey(REQUEST_PERMISSIONS)) { 678 JSONArray requestPermissions = moduleJson.getJSONArray(REQUEST_PERMISSIONS); 679 for (int i = 0; i < requestPermissions.size(); ++i) { 680 JSONObject requestPermission = requestPermissions.getJSONObject(i); 681 if (isPermissionSupportPlugin(requestPermission)) { 682 return false; 683 } 684 } 685 } 686 return true; 687 } catch (IOException e) { 688 LOG.error(PackingToolErrMsg.IO_EXCEPTION.toString( 689 "check is plugin host exist IOException: " + e.getMessage())); 690 } 691 return true; 692 } 693 isPermissionSupportPlugin(JSONObject requestPermission)694 private static boolean isPermissionSupportPlugin(JSONObject requestPermission) throws BundleException { 695 String reqPermissionName = getJsonString(requestPermission, NAME); 696 if (reqPermissionName.equals(PERMISSION_SUPPORT_PLUGIN)) { 697 return true; 698 } 699 return false; 700 } 701 checkPkgContext(Utility utility)702 private static boolean checkPkgContext(Utility utility) throws BundleException { 703 if (!utility.getPkgContextPath().isEmpty()) { 704 File file = new File(utility.getPkgContextPath()); 705 if (!file.isFile() || !PKG_CONTEXT_INFO.equals(file.getName())) { 706 String errMsg = "--pkg-context-path file must be the pkgContextInfo.json file."; 707 LOG.error(PackingToolErrMsg.CHECK_PKG_CONTEXT_FAILED.toString(errMsg)); 708 return false; 709 } 710 return true; 711 } 712 LOG.error(PackingToolErrMsg.CHECK_PKG_CONTEXT_FAILED.toString("no have pkgContextInfo.json file.")); 713 return false; 714 } 715 checkAppPlugin(Utility utility)716 private static boolean checkAppPlugin(Utility utility) throws BundleException { 717 File file = new File(utility.getJsonPath()); 718 if (!file.exists()) { 719 String errMsg = "The --json-path file does not exist."; 720 LOG.error(PackingToolErrMsg.CHECK_APP_PLUGIN_FAILED.toString(errMsg)); 721 throw new BundleException("Verify has generate build hash failed for --json-path file does not exist."); 722 } 723 try (InputStream json = new FileInputStream(file)) { 724 JSONObject jsonObject = JSON.parseObject(json, JSONObject.class); 725 if (jsonObject == null || !jsonObject.containsKey(MODULE)) { 726 LOG.error(PackingToolErrMsg.CHECK_APP_PLUGIN_FAILED.toString("The --json-path file is invalid.")); 727 throw new BundleException("Parse --json-path file is invalid."); 728 } 729 Optional<String> optional = FileUtils.getFileContent(utility.getJsonPath()); 730 String jsonString = optional.get(); 731 String bundleType = ModuleJsonUtil.parseStageBundleType(jsonString); 732 if (!TYPE_APP_PLUGIN.equals(bundleType)) { 733 if (isPluginHost(utility)) { 734 return true; 735 } 736 if (!checkPkgContext(utility)) { 737 LOG.error(PackingToolErrMsg.CHECK_APP_PLUGIN_FAILED.toString("checkPkgContext failed.")); 738 return false; 739 } 740 return true; 741 } 742 JSONObject moduleJson = jsonObject.getJSONObject(MODULE); 743 JSONArray extensionAbilityJsonList = moduleJson.getJSONArray(EXTENSION_ABILITIES); 744 if (extensionAbilityJsonList != null) { 745 for (int j = 0; j < extensionAbilityJsonList.size(); j++) { 746 JSONObject extensionAbilityJson = extensionAbilityJsonList.getJSONObject(j); 747 if (extensionAbilityJson != null) { 748 LOG.error(PackingToolErrMsg.CHECK_APP_PLUGIN_FAILED.toString("extensionAbilities is not null.")); 749 return false; 750 } 751 } 752 } 753 if (!checkPkgContext(utility)) { 754 LOG.error(PackingToolErrMsg.CHECK_APP_PLUGIN_FAILED.toString("checkPkgContext failed.")); 755 return false; 756 } 757 if (!isPluginHost(utility)) { 758 LOG.error(PackingToolErrMsg.CHECK_APP_PLUGIN_FAILED.toString("plugin package cannot be the host.")); 759 return false; 760 } 761 return true; 762 } catch (IOException e) { 763 LOG.error(PackingToolErrMsg.IO_EXCEPTION.toString( 764 "check app plugin exist IOException: " + e.getMessage())); 765 } 766 return true; 767 } 768 769 /** 770 * get the String from JSONObject by the key. 771 * 772 * @param jsonObject uncompress json object 773 * @param key value key 774 * @return the result 775 */ getJsonString(JSONObject jsonObject, String key)776 private static String getJsonString(JSONObject jsonObject, String key) { 777 String value = ""; 778 if (jsonObject != null && jsonObject.containsKey(key) && jsonObject.get(key) != null) { 779 value = jsonObject.get(key).toString(); 780 } 781 return value; 782 } 783 hasGenerateBuildHash(Utility utility)784 private static boolean hasGenerateBuildHash(Utility utility) throws BundleException { 785 File file = new File(utility.getJsonPath()); 786 if (!file.exists()) { 787 String errMsg = "The --json-path file does not exist."; 788 LOG.error(PackingToolErrMsg.HAS_GENERATE_BUILD_HASH.toString(errMsg)); 789 throw new BundleException("Verify has generate build hash failed for --json-path file does not exist."); 790 } 791 InputStream json = null; 792 boolean res = false; 793 try { 794 json = new FileInputStream(file); 795 JSONObject jsonObject = JSON.parseObject(json, JSONObject.class); 796 if (jsonObject == null || !jsonObject.containsKey(APP) || !jsonObject.containsKey(MODULE)) { 797 LOG.error(PackingToolErrMsg.HAS_GENERATE_BUILD_HASH.toString("The --json-path file is invalid.")); 798 throw new BundleException("Parse --json-path file is invalid."); 799 } 800 JSONObject appJson = jsonObject.getJSONObject(APP); 801 JSONObject moduleJson = jsonObject.getJSONObject(MODULE); 802 if (appJson.containsKey(GENERATE_BUILD_HASH) || moduleJson.containsKey(GENERATE_BUILD_HASH)) { 803 res = true; 804 } 805 } catch (BundleException exception) { 806 LOG.error(PackingToolErrMsg.HAS_GENERATE_BUILD_HASH.toString( 807 "Verify has generate build hash exist BundleException: " + exception.getMessage())); 808 throw new BundleException("Verify has generate build hash failed."); 809 } catch (JSONException | IOException e) { 810 LOG.error(PackingToolErrMsg.HAS_GENERATE_BUILD_HASH.toString( 811 "Verify has generate build hash exist Exception (JSONException | IOException): " + 812 e.getMessage())); 813 throw new BundleException("Verify has generate build hash failed."); 814 } finally { 815 FileUtils.closeStream(json); 816 } 817 818 return res; 819 } 820 setGenerateBuildHash(Utility utility)821 private static void setGenerateBuildHash(Utility utility) throws BundleException { 822 if (utility.isBuildHashFinish() || !hasGenerateBuildHash(utility)) { 823 return; 824 } 825 copyFileToTempDir(utility); 826 File file = new File(utility.getJsonPath()); 827 if (!file.exists()) { 828 String errMsg = "The --json-path file does not exist."; 829 LOG.error(PackingToolErrMsg.SET_GENERATE_BUILD_HASH.toString(errMsg)); 830 throw new BundleException("Set generate build hash failed for --json-path file does not exist."); 831 } 832 // 1. 解析 JSON 833 JSONObject jsonObject; 834 try (InputStream json = Files.newInputStream(file.toPath())) { 835 jsonObject = JSON.parseObject(json, JSONObject.class); 836 } catch (IOException | JSONException e) { 837 LOG.error(PackingToolErrMsg.SET_GENERATE_BUILD_HASH.toString( 838 "Failed to read JSON file: " + e.getMessage())); 839 throw new BundleException("Failed to read JSON file"); 840 } 841 //2. 检查必要字段 842 if (jsonObject == null || !jsonObject.containsKey(APP) || !jsonObject.containsKey(MODULE)) { 843 LOG.error(PackingToolErrMsg.SET_GENERATE_BUILD_HASH.toString("Parse --json-path file is invalid.")); 844 throw new BundleException("The --json-path file is invalid."); 845 } 846 //3. 处理 JSON 数据 847 processBuildHashFlags(utility, jsonObject); 848 //4. 写入修改后的 JSON 849 writeJsonFile(utility.getJsonPath(), jsonObject); 850 } 851 processBuildHashFlags(Utility utility, JSONObject jsonObject)852 private static void processBuildHashFlags(Utility utility, JSONObject jsonObject) { 853 JSONObject appJson = jsonObject.getJSONObject(APP); 854 JSONObject moduleJson = jsonObject.getJSONObject(MODULE); 855 if (appJson.containsKey(GENERATE_BUILD_HASH) && appJson.getBoolean(GENERATE_BUILD_HASH)) { 856 utility.setGenerateBuildHash(true); 857 } else if (moduleJson.containsKey(GENERATE_BUILD_HASH) && moduleJson.getBoolean(GENERATE_BUILD_HASH)) { 858 utility.setGenerateBuildHash(true); 859 } 860 appJson.remove(GENERATE_BUILD_HASH); 861 moduleJson.remove(GENERATE_BUILD_HASH); 862 } 863 writeJsonFile(String filePath, JSONObject jsonObject)864 private static void writeJsonFile(String filePath, JSONObject jsonObject) throws BundleException { 865 try (BufferedWriter bw = new BufferedWriter(new OutputStreamWriter( 866 Files.newOutputStream(Paths.get(filePath)), StandardCharsets.UTF_8))) { 867 String pretty = JSON.toJSONString(jsonObject, new SerializerFeature[]{ 868 SerializerFeature.PrettyFormat, 869 SerializerFeature.WriteMapNullValue, 870 SerializerFeature.WriteDateUseDateFormat}); 871 bw.write(pretty); 872 } catch (IOException e) { 873 LOG.error(PackingToolErrMsg.SET_GENERATE_BUILD_HASH.toString( 874 "Failed to write JSON file: " + e.getMessage())); 875 throw new BundleException("Failed to write JSON file"); 876 } 877 } 878 copyFileToTempDir(Utility utility)879 private static void copyFileToTempDir(Utility utility) throws BundleException { 880 String jsonPath = utility.getJsonPath(); 881 File oldfile = new File(jsonPath); 882 if (!oldfile.exists()) { 883 String errMsg = "Parse --json-path file does not found, parse json path is " + jsonPath + "."; 884 LOG.error(PackingToolErrMsg.FILE_NOT_EXIST.toString(errMsg)); 885 throw new BundleException("Copy file to temp dir failed for --json-path file not found."); 886 } 887 String oldFileParent = oldfile.getParent(); 888 String tempDir = TEMP_DIR + File.separator + UUID.randomUUID(); 889 mkdir(new File(oldFileParent + File.separator + tempDir)); 890 String fileName; 891 if (isModuleJSON(utility.getJsonPath())) { 892 fileName = MODULE_JSON; 893 } else { 894 fileName = CONFIG_JSON; 895 } 896 String tempPath = oldFileParent + File.separator + tempDir + File.separator + fileName; 897 898 try (InputStream inStream = new FileInputStream(jsonPath); 899 FileOutputStream fs = new FileOutputStream(tempPath)) { 900 byte[] buffer = new byte[BUFFER_WRITE_SIZE]; 901 int byteread; 902 while ((byteread = inStream.read(buffer)) != -1) { 903 fs.write(buffer, 0, byteread); 904 } 905 utility.setJsonPath(tempPath); 906 } catch (IOException e) { 907 LOG.error(PackingToolErrMsg.IO_EXCEPTION.toString( 908 "Copy file to temp dir exist IOException:" + e.getMessage())); 909 throw new BundleException("Copy file to temp dir failed."); 910 } 911 } 912 mkdir(File file)913 private static void mkdir(File file) { 914 if (null != file && !file.exists()) { 915 mkdir(file.getParentFile()); 916 file.mkdir(); 917 } 918 } 919 buildHash(Utility utility)920 private static void buildHash(Utility utility) throws BundleException { 921 if (utility.isBuildHashFinish() || (!utility.getGenerateBuildHash())) { 922 return; 923 } 924 String filePath = utility.getOutPath(); 925 String hash = getSHA256(filePath); 926 try { 927 putBuildHash(utility, hash); 928 } catch (IOException e) { 929 LOG.error(PackingToolErrMsg.IO_EXCEPTION.toString("Build hash exist IOException: " + e.getMessage())); 930 throw new BundleException("Put build hash failed."); 931 } 932 } 933 checkSum(String filename)934 private static byte[] checkSum(String filename) throws BundleException { 935 try (InputStream fis = new FileInputStream(filename)) { 936 byte[] buffer = new byte[BUFFER_BYTE_SIZE]; 937 MessageDigest complete = MessageDigest.getInstance(SHA_256); 938 int numRead; 939 do { 940 numRead = fis.read(buffer); 941 if (numRead > 0) { 942 complete.update(buffer, 0, numRead); 943 } 944 } while (numRead != -1); 945 return complete.digest(); 946 } catch (IOException | NoSuchAlgorithmException e) { 947 LOG.error(PackingToolErrMsg.SHA256_CALCULATION_FAILED.toString("SHA-256 checksum calculation exist " + 948 "Exception (IOException | NoSuchAlgorithmException): " + e.getMessage())); 949 throw new BundleException("Compressor::checkSum failed."); 950 } 951 } 952 953 /** 954 * get SHA256 of hap or hsp 955 * 956 * @param filePath the path of hap or hsp. 957 */ getSHA256(String filePath)958 public static String getSHA256(String filePath) throws BundleException { 959 byte[] byteSum = checkSum(filePath); 960 StringBuilder temp = new StringBuilder(); 961 for (int i = 0; i < byteSum.length; i++) { 962 temp.append( 963 Integer.toString((byteSum[i] & SHA256_BASE) + SHA256_OFFSET, RADIX).substring(BEGIN_INDEX)); 964 } 965 return temp.toString(); 966 } 967 putBuildHash(Utility utility, String hash)968 private static void putBuildHash(Utility utility, String hash) throws BundleException, IOException { 969 if (utility.isBuildHashFinish()) { 970 return; 971 } 972 String jsonPath = utility.getJsonPath(); 973 File file = new File(jsonPath); 974 if (!file.exists()) { 975 String errMsg = "The --json-path file does not exist."; 976 LOG.error(PackingToolErrMsg.FILE_NOT_EXIST.toString(errMsg)); 977 throw new BundleException("Put build hash failed for json file not exist."); 978 } 979 InputStream json = null; 980 BufferedWriter bw = null; 981 try { 982 json = new FileInputStream(file); 983 JSONObject jsonObject = JSON.parseObject(json, JSONObject.class); 984 JSONObject moduleJson = jsonObject.getJSONObject(MODULE); 985 moduleJson.put(BUILD_HASH, hash); 986 String pretty = JSON.toJSONString(jsonObject, SerializerFeature.PrettyFormat, 987 SerializerFeature.WriteMapNullValue, SerializerFeature.WriteDateUseDateFormat); 988 bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(jsonPath), StandardCharsets.UTF_8)); 989 bw.write(pretty); 990 } catch (IOException e) { 991 LOG.error(PackingToolErrMsg.IO_EXCEPTION.toString("Put build hash exist IOException: " + e.getMessage())); 992 throw new BundleException("Put build hash failed."); 993 } catch (NullPointerException e) { 994 LOG.error(PackingToolErrMsg.NULL_POINTER_EXCEPTION.toString( 995 "The json data err, exist NullPointerException: " + e.getMessage())); 996 throw new BundleException("Put build hash failed, json data err."); 997 } finally { 998 FileUtils.closeStream(json); 999 if (bw != null) { 1000 bw.flush(); 1001 bw.close(); 1002 } 1003 } 1004 utility.setBuildHashFinish(true); 1005 } 1006 checkAppAtomicServiceCompressedSizeValid(Utility utility)1007 private boolean checkAppAtomicServiceCompressedSizeValid(Utility utility) { 1008 if (!utility.getMode().equals(Utility.MODE_APP) && 1009 !utility.getMode().equals(Utility.MODE_FAST_APP) && 1010 !utility.getMode().equals(Utility.MODE_MULTI_APP)) { 1011 return true; 1012 } 1013 1014 File destFile = new File(utility.getOutPath()); 1015 List<HapVerifyInfo> hapVerifyInfos = new ArrayList<>(); 1016 try (ZipFile zipApp = new ZipFile(destFile)) { 1017 Enumeration<? extends ZipEntry> entries = zipApp.entries(); 1018 while (entries.hasMoreElements()) { 1019 ZipEntry entry = entries.nextElement(); 1020 if (entry != null && hapVerifyInfoMap.containsKey(entry.getName())) { 1021 hapVerifyInfoMap.get(entry.getName()).setFileLength(entry.getCompressedSize()); 1022 hapVerifyInfos.add(hapVerifyInfoMap.get(entry.getName())); 1023 } 1024 } 1025 1026 if (hapVerifyInfos.isEmpty()) { 1027 LOG.error(PackingToolErrMsg.CHECK_HAP_VERIFY_INFO_LIST_EMPTY.toString("Hap verify infos is empty")); 1028 return false; 1029 } 1030 1031 String bundleType = hapVerifyInfos.get(0).getBundleType(); 1032 if (!bundleType.equals(ATOMIC_SERVICE)) { 1033 return true; 1034 } 1035 boolean isStage = hapVerifyInfos.get(0).isStageModule(); 1036 if (!isStage) { 1037 return true; 1038 } 1039 1040 return HapVerify.checkFileSizeIsValid(hapVerifyInfos); 1041 } catch (IOException exception) { 1042 LOG.error(PackingToolErrMsg.APP_ATOMICSERVICE_COMPRESSED_SIZE_INVALID.toString( 1043 "IOException: " + exception.getMessage())); 1044 return false; 1045 } catch (BundleException ignored) { 1046 LOG.error(PackingToolErrMsg.APP_ATOMICSERVICE_COMPRESSED_SIZE_INVALID.toString( 1047 "BundleException: " + ignored.getMessage())); 1048 return false; 1049 } 1050 } 1051 checkStageHap(Utility utility)1052 private static boolean checkStageHap(Utility utility) throws BundleException { 1053 Optional<String> optional = FileUtils.getFileContent(utility.getJsonPath()); 1054 String jsonString = optional.get(); 1055 if (!checkStageAsanTsanEnabledValid(jsonString)) { 1056 LOG.error(PackingToolErrMsg.CHECK_STAGE_HAP_FAILED.toString( 1057 "Check the asanTsanEnabled parameter in the Stage module failed.")); 1058 return false; 1059 } 1060 if (!checkStageHwasanEnabledValid(jsonString)) { 1061 LOG.error(PackingToolErrMsg.CHECK_STAGE_HAP_FAILED.toString( 1062 "Check the hwasanEnabled parameter in the Stage module failed.")); 1063 return false; 1064 } 1065 if (!checkStageUbsanEnabledValid(jsonString)) { 1066 LOG.error(PackingToolErrMsg.CHECK_STAGE_HAP_FAILED.toString( 1067 "Check the ubsanEnabled parameter in the Stage module failed.")); 1068 return false; 1069 } 1070 // check atomicService in module.json 1071 if (!checkStageAtomicService(jsonString)) { 1072 LOG.error(PackingToolErrMsg.CHECK_STAGE_HAP_FAILED.toString( 1073 "Check the atomicService parameter in the Stage module failed.")); 1074 return false; 1075 } 1076 // check continueBundleName in module.json 1077 if (!checkContinueBundleNameIsValid(jsonString)) { 1078 LOG.error(PackingToolErrMsg.CHECK_STAGE_HAP_FAILED.toString( 1079 "Check the continueBundleName parameter in the Stage module failed.")); 1080 return false; 1081 } 1082 return true; 1083 } 1084 checkStageAsanTsanEnabledValid(String jsonString)1085 private static boolean checkStageAsanTsanEnabledValid(String jsonString) throws BundleException { 1086 boolean asanEnabled = ModuleJsonUtil.getStageAsanEnabled(jsonString); 1087 boolean tsanEnabled = ModuleJsonUtil.getStageTsanEnabled(jsonString); 1088 if (asanEnabled && tsanEnabled) { 1089 LOG.error(PackingToolErrMsg.CHECK_AS_TSAN_ENABLED.toString( 1090 "asanEnabled and tsanEnabled cannot be true at the same time.")); 1091 return false; 1092 } 1093 return true; 1094 } 1095 checkStageHwasanEnabledValid(String jsonString)1096 private static boolean checkStageHwasanEnabledValid(String jsonString) throws BundleException { 1097 boolean asanEnabled = ModuleJsonUtil.getStageAsanEnabled(jsonString); 1098 boolean tsanEnabled = ModuleJsonUtil.getStageTsanEnabled(jsonString); 1099 boolean gwpAsanEnabled = ModuleJsonUtil.getStageGwpAsanEnabled(jsonString); 1100 boolean hwasanEnabled = ModuleJsonUtil.getStageHwasanEnabled(jsonString); 1101 if (hwasanEnabled && asanEnabled) { 1102 LOG.error(PackingToolErrMsg.CHECK_HWASAN_ENABLED_INVALID.toString( 1103 "hwasanEnabled and asanEnabled cannot be true at the same time.")); 1104 return false; 1105 } 1106 if (hwasanEnabled && tsanEnabled) { 1107 LOG.error(PackingToolErrMsg.CHECK_HWASAN_ENABLED_INVALID.toString( 1108 "hwasanEnabled and tsanEnabled cannot be true at the same time.")); 1109 return false; 1110 } 1111 if (hwasanEnabled && gwpAsanEnabled) { 1112 LOG.error(PackingToolErrMsg.CHECK_HWASAN_ENABLED_INVALID.toString( 1113 "hwasanEnabled and GWPAsanEnabled cannot be true at the same time.")); 1114 return false; 1115 } 1116 return true; 1117 } 1118 checkContinueBundleNameIsValid(String jsonString)1119 private static boolean checkContinueBundleNameIsValid(String jsonString) throws BundleException { 1120 Map<String, List<String>> continueBundleNameMap = ModuleJsonUtil.getAbilityContinueBundleNameMap(jsonString); 1121 String bundleName = ModuleJsonUtil.parseBundleName(jsonString); 1122 String moduleName = ModuleJsonUtil.parseStageModuleName(jsonString); 1123 for (Map.Entry<String, List<String>> entry : continueBundleNameMap.entrySet()) { 1124 List<String> continueBundleNameList = entry.getValue(); 1125 if (continueBundleNameList == null) { 1126 continue; 1127 } 1128 for (int i = 0; i < continueBundleNameList.size(); i++) { 1129 if (bundleName.equals(continueBundleNameList.get(i))) { 1130 LOG.error(PackingToolErrMsg.CHECK_CONTINUE_BUNDLENAME_INVALID.toString( 1131 "Module(" + moduleName + ") continueBundleName include self.")); 1132 return false; 1133 } 1134 } 1135 } 1136 return true; 1137 } 1138 checkStageUbsanEnabledValid(String jsonString)1139 private static boolean checkStageUbsanEnabledValid(String jsonString) throws BundleException { 1140 boolean asanEnabled = ModuleJsonUtil.getStageAsanEnabled(jsonString); 1141 boolean tsanEnabled = ModuleJsonUtil.getStageTsanEnabled(jsonString); 1142 boolean hwasanEnabled = ModuleJsonUtil.getStageHwasanEnabled(jsonString); 1143 boolean ubsanEnabled = ModuleJsonUtil.getStageUbsanEnabled(jsonString); 1144 if (ubsanEnabled && asanEnabled) { 1145 LOG.error(PackingToolErrMsg.CHECK_UBASAN_ENABLED_INVALID.toString( 1146 "ubsanEnabled and asanEnabled cannot be true at the same time.")); 1147 return false; 1148 } 1149 if (ubsanEnabled && tsanEnabled) { 1150 LOG.error(PackingToolErrMsg.CHECK_UBASAN_ENABLED_INVALID.toString( 1151 "ubsanEnabled and tsanEnabled cannot be true at the same time.")); 1152 return false; 1153 } 1154 if (ubsanEnabled && hwasanEnabled) { 1155 LOG.error(PackingToolErrMsg.CHECK_UBASAN_ENABLED_INVALID.toString( 1156 "ubsanEnabled and hwasanEnabled cannot be true at the same time.")); 1157 return false; 1158 } 1159 return true; 1160 } 1161 checkStageAtomicService(String jsonString)1162 private static boolean checkStageAtomicService(String jsonString) throws BundleException { 1163 // check consistency of atomicService 1164 if (!ModuleJsonUtil.isModuleAtomicServiceValid(jsonString)) { 1165 LOG.error(PackingToolErrMsg.CHECK_ATOMIC_SERVICE_FAILED.toString( 1166 "Check consistency of atomicService failed.")); 1167 return false; 1168 } 1169 // check entry module must have ability 1170 if (!ModuleJsonUtil.checkEntryInAtomicService(jsonString)) { 1171 LOG.error(PackingToolErrMsg.CHECK_ATOMIC_SERVICE_FAILED.toString( 1172 "Check the atomicService entry module failed.")); 1173 return false; 1174 } 1175 // check installationFree 1176 if (!ModuleJsonUtil.checkAtomicServiceInstallationFree(jsonString)) { 1177 LOG.error(PackingToolErrMsg.CHECK_ATOMIC_SERVICE_FAILED.toString( 1178 "Check the installationFree parameter failed.")); 1179 return false; 1180 } 1181 1182 return true; 1183 } 1184 checkStageOverlayCfg(String jsonString)1185 private static boolean checkStageOverlayCfg(String jsonString) throws BundleException { 1186 // check module 1187 String targetModuleName = ModuleJsonUtil.getStageTargetModuleName(jsonString); 1188 String moduleName = ModuleJsonUtil.parseStageModuleName(jsonString); 1189 if (!targetModuleName.isEmpty()) { 1190 // check targetModuleName and requestPermission 1191 if (ModuleJsonUtil.isExistedStageRequestPermissions(jsonString)) { 1192 LOG.error(PackingToolErrMsg.CHECK_OVERLAY_CFG_FAILED.toString( 1193 "The module(" + moduleName + ") targetModuleName and requestPermissions " + 1194 "cannot be configured at the same time.")); 1195 return false; 1196 } 1197 // check targetModuleName and name 1198 if (targetModuleName.equals(moduleName)) { 1199 LOG.error(PackingToolErrMsg.CHECK_OVERLAY_CFG_FAILED.toString( 1200 "The targetModuleName of module(" + moduleName + ") cannot be itself.")); 1201 return false; 1202 } 1203 } else { 1204 if (ModuleJsonUtil.isExistedStageModuleTargetPriority(jsonString)) { 1205 LOG.error(PackingToolErrMsg.CHECK_OVERLAY_CFG_FAILED.toString( 1206 "The targetPriority cannot be existed without the targetModuleName in module.json. " + 1207 "The moduleName is " + moduleName + ".")); 1208 return false; 1209 } 1210 } 1211 // check app 1212 String targetBundleName = ModuleJsonUtil.getStageTargetBundleName(jsonString); 1213 if (!targetBundleName.isEmpty()) { 1214 if (targetModuleName.isEmpty()) { 1215 LOG.error(PackingToolErrMsg.CHECK_OVERLAY_CFG_FAILED.toString("The module(" + moduleName + 1216 ") targetModuleName settings is necessary in the overlay bundle.")); 1217 return false; 1218 } 1219 if (targetBundleName.equals(ModuleJsonUtil.parseBundleName(jsonString))) { 1220 LOG.error(PackingToolErrMsg.CHECK_OVERLAY_CFG_FAILED.toString( 1221 "The module(" + moduleName + ") targetBundleName cannot be same with the bundleName.")); 1222 return false; 1223 } 1224 } else { 1225 if (ModuleJsonUtil.isExistedStageAppTargetPriority(jsonString)) { 1226 LOG.error(PackingToolErrMsg.CHECK_OVERLAY_CFG_FAILED.toString("The targetPriority cannot be existed " + 1227 "without the targetBundleName in app.json. The moduleName is " + moduleName + ".")); 1228 return false; 1229 } 1230 } 1231 return true; 1232 } 1233 checkFAHap(Utility utility)1234 private static boolean checkFAHap(Utility utility) throws BundleException { 1235 Optional<String> optional = FileUtils.getFileContent(utility.getJsonPath()); 1236 String jsonString = optional.get(); 1237 return checkFAAsanEnabledValid(jsonString); 1238 } 1239 checkFAAsanEnabledValid(String jsonString)1240 private static boolean checkFAAsanEnabledValid(String jsonString) throws BundleException { 1241 boolean asanEnabled = ModuleJsonUtil.getFAAsanEnabled(jsonString); 1242 boolean debug = ModuleJsonUtil.getFADebug(jsonString); 1243 if (asanEnabled && !debug) { 1244 LOG.error("asanEnabled is not supported for Release."); 1245 return false; 1246 } 1247 return true; 1248 } 1249 1250 /** 1251 * compress in hap mode. 1252 * 1253 * @param utility common data 1254 * @throws BundleException FileNotFoundException|IOException. 1255 */ compressHapMode(Utility utility)1256 private void compressHapMode(Utility utility) throws BundleException { 1257 pathToFile(utility, utility.getJsonPath(), NULL_DIR_NAME, false); 1258 1259 pathToFile(utility, utility.getProfilePath(), NULL_DIR_NAME, false); 1260 1261 if (!utility.getIndexPath().isEmpty() && !utility.getModuleName().isEmpty()) { 1262 String assetsPath = ASSETS_DIR_NAME + utility.getModuleName() + LINUX_FILE_SEPARATOR; 1263 pathToFile(utility, utility.getIndexPath(), assetsPath, false); 1264 } 1265 1266 if (!utility.getLibPath().isEmpty()) { 1267 pathToFile(utility, utility.getLibPath(), LIBS_DIR_NAME, utility.isCompressNativeLibs()); 1268 } 1269 1270 if (!utility.getFilePath().isEmpty()) { 1271 pathToFile(utility, utility.getFilePath(), NULL_DIR_NAME, false); 1272 } 1273 1274 if (!utility.getResPath().isEmpty() && !utility.getModuleName().isEmpty()) { 1275 String resPath = ASSETS_DIR_NAME + utility.getModuleName() + LINUX_FILE_SEPARATOR 1276 + RESOURCES_DIR_NAME; 1277 String deviceTypes = utility.getDeviceType().replace("\"", "").trim(); 1278 if (DEVICE_TYPE_FITNESSWATCH.equals(deviceTypes) || 1279 DEVICE_TYPE_FITNESSWATCH_NEW.equals(deviceTypes)) { 1280 resPath = RES_DIR_NAME; 1281 } 1282 pathToFile(utility, utility.getResPath(), resPath, false); 1283 } 1284 1285 if (!utility.getResourcesPath().isEmpty() && !utility.getModuleName().isEmpty()) { 1286 String resourcesPath = ASSETS_DIR_NAME + utility.getModuleName() + LINUX_FILE_SEPARATOR 1287 + RESOURCES_DIR_NAME; 1288 pathToFile(utility, utility.getResourcesPath(), resourcesPath, false); 1289 } 1290 1291 if (!utility.getRpcidPath().isEmpty()) { 1292 String rpcidPath = NULL_DIR_NAME; 1293 pathToFile(utility, utility.getRpcidPath(), rpcidPath, false); 1294 } 1295 1296 if (!utility.getPackInfoPath().isEmpty()) { 1297 String packInfoPath = NULL_DIR_NAME; 1298 pathToFile(utility, utility.getPackInfoPath(), packInfoPath, false); 1299 } 1300 1301 if (!utility.getAssetsPath().isEmpty()) { 1302 pathToFile(utility, utility.getAssetsPath(), ASSETS_DIR_NAME, false); 1303 } 1304 1305 if (!utility.getBinPath().isEmpty()) { 1306 pathToFile(utility, utility.getBinPath(), NULL_DIR_NAME, false); 1307 } 1308 // pack --dir-list 1309 if (!utility.getFormatedDirList().isEmpty()) { 1310 for (int i = 0; i < utility.getFormatedDirList().size(); ++i) { 1311 String baseDir = new File(utility.getFormatedDirList().get(i)).getName() + File.separator; 1312 pathToFile(utility, utility.getFormatedDirList().get(i), baseDir, false); 1313 } 1314 } 1315 1316 compressHapModeMultiple(utility); 1317 } 1318 1319 /** 1320 * compress in hap mode for module.json. 1321 * 1322 * @param utility common data 1323 * @throws BundleException FileNotFoundException|IOException. 1324 */ compressHapModeForModule(Utility utility)1325 private void compressHapModeForModule(Utility utility) throws BundleException { 1326 pathToFile(utility, utility.getJsonPath(), NULL_DIR_NAME, false); 1327 1328 pathToFile(utility, utility.getProfilePath(), NULL_DIR_NAME, false); 1329 1330 if (!utility.getIndexPath().isEmpty() && isModuleJSON(utility.getJsonPath())) { 1331 String assetsPath = NULL_DIR_NAME; 1332 pathToFile(utility, utility.getIndexPath(), assetsPath, false); 1333 } 1334 1335 if (!utility.getLibPath().isEmpty()) { 1336 pathToFile(utility, utility.getLibPath(), LIBS_DIR_NAME, utility.isCompressNativeLibs()); 1337 } 1338 1339 if (!utility.getANPath().isEmpty()) { 1340 pathToFile(utility, utility.getANPath(), AN_DIR_NAME, false); 1341 } 1342 1343 if (!utility.getAPPath().isEmpty()) { 1344 pathToFile(utility, utility.getAPPath(), AP_PATH_NAME, false); 1345 } 1346 1347 if (!utility.getFilePath().isEmpty()) { 1348 pathToFile(utility, utility.getFilePath(), NULL_DIR_NAME, false); 1349 } 1350 1351 if (!utility.getResPath().isEmpty() && !utility.getModuleName().isEmpty()) { 1352 String resPath = ASSETS_DIR_NAME + utility.getModuleName() + LINUX_FILE_SEPARATOR 1353 + RESOURCES_DIR_NAME; 1354 String deviceTypes = utility.getDeviceType().replace("\"", "").trim(); 1355 if (DEVICE_TYPE_FITNESSWATCH.equals(deviceTypes) || 1356 DEVICE_TYPE_FITNESSWATCH_NEW.equals(deviceTypes)) { 1357 resPath = RES_DIR_NAME; 1358 } 1359 pathToFile(utility, utility.getResPath(), resPath, false); 1360 } 1361 1362 if (!utility.getResourcesPath().isEmpty() && isModuleJSON(utility.getJsonPath())) { 1363 String resourcesPath = RESOURCES_DIR_NAME; 1364 pathToFile(utility, utility.getResourcesPath(), resourcesPath, false); 1365 } 1366 if (!utility.getJsPath().isEmpty() && isModuleJSON(utility.getJsonPath())) { 1367 String jsPath = JS_PATH; 1368 pathToFile(utility, utility.getJsPath(), jsPath, false); 1369 } 1370 1371 if (!utility.getEtsPath().isEmpty() && isModuleJSON(utility.getJsonPath())) { 1372 String etsPath = ETS_PATH; 1373 pathToFile(utility, utility.getEtsPath(), etsPath, false); 1374 } 1375 1376 if (!utility.getHnpPath().isEmpty() && isModuleJSON(utility.getJsonPath())) { 1377 String hnpPath = HNP_PATH; 1378 pathToFile(utility, utility.getHnpPath(), hnpPath, false); 1379 } 1380 1381 if (!utility.getRpcidPath().isEmpty()) { 1382 String rpcidPath = NULL_DIR_NAME; 1383 pathToFile(utility, utility.getRpcidPath(), rpcidPath, false); 1384 } 1385 1386 if (!utility.getAssetsPath().isEmpty()) { 1387 pathToFile(utility, utility.getAssetsPath(), ASSETS_DIR_NAME, false); 1388 } 1389 1390 if (!utility.getBinPath().isEmpty()) { 1391 pathToFile(utility, utility.getBinPath(), NULL_DIR_NAME, false); 1392 } 1393 1394 if (!utility.getPackInfoPath().isEmpty()) { 1395 pathToFile(utility, utility.getPackInfoPath(), NULL_DIR_NAME, false); 1396 } 1397 1398 // pack --dir-list 1399 if (!utility.getFormatedDirList().isEmpty()) { 1400 for (int i = 0; i < utility.getFormatedDirList().size(); ++i) { 1401 String baseDir = new File(utility.getFormatedDirList().get(i)).getName() + File.separator; 1402 pathToFile(utility, utility.getFormatedDirList().get(i), baseDir, false); 1403 } 1404 } 1405 if (!utility.getPkgContextPath().isEmpty()) { 1406 pathToFile(utility, utility.getPkgContextPath(), NULL_DIR_NAME, false); 1407 } 1408 1409 compressHapModeMultiple(utility); 1410 } 1411 1412 /** 1413 * compress in hap mode multiple path. 1414 * 1415 * @param utility common data 1416 * @throws BundleException FileNotFoundException|IOException. 1417 */ compressHapModeMultiple(Utility utility)1418 private void compressHapModeMultiple(Utility utility) throws BundleException { 1419 for (String soPathItem : utility.getFormattedSoPathList()) { 1420 pathToFile(utility, soPathItem, SO_ARM64_DIR_NAME, false); 1421 } 1422 1423 if (utility.getFormattedSoPathList().size() == 0 && !utility.getSoDir().isEmpty()) { 1424 pathToFile(utility, utility.getSoDir(), SO_DIR_NAME, false); 1425 } 1426 1427 for (String soPathItem : utility.getFormattedAbilitySoPathList()) { 1428 pathToFile(utility, soPathItem, NULL_DIR_NAME, false); 1429 } 1430 1431 for (String dexPathItem : utility.getFormattedDexPathList()) { 1432 pathToFile(utility, dexPathItem, NULL_DIR_NAME, false); 1433 } 1434 1435 for (String abcPathItem : utility.getFormattedAbcPathList()) { 1436 pathToFile(utility, abcPathItem, NULL_DIR_NAME, false); 1437 } 1438 1439 for (String apkPathItem : utility.getFormattedApkPathList()) { 1440 pathToFile(utility, apkPathItem, NULL_DIR_NAME, false); 1441 } 1442 1443 for (String jarPathItem : utility.getFormattedJarPathList()) { 1444 pathToFile(utility, jarPathItem, NULL_DIR_NAME, false); 1445 } 1446 1447 for (String txtPathItem : utility.getFormattedTxtPathList()) { 1448 pathToFile(utility, txtPathItem, NULL_DIR_NAME, false); 1449 } 1450 1451 if (!utility.getSharedLibsPath().isEmpty()) { 1452 pathToFile(utility, utility.getSharedLibsPath(), SHARED_LIBS_DIR_NAME, utility.isCompressNativeLibs()); 1453 } 1454 } 1455 1456 /** 1457 * compress in har mode. 1458 * 1459 * @param utility common data 1460 * @throws BundleException FileNotFoundException|IOException. 1461 */ compressHarMode(Utility utility)1462 private void compressHarMode(Utility utility) throws BundleException { 1463 pathToFile(utility, utility.getJsonPath(), NULL_DIR_NAME, false); 1464 1465 if (!utility.getLibPath().isEmpty()) { 1466 pathToFile(utility, utility.getLibPath(), LIBS_DIR_NAME, utility.isCompressNativeLibs()); 1467 } 1468 1469 if (!utility.getResPath().isEmpty()) { 1470 pathToFile(utility, utility.getResPath(), RESOURCES_DIR_NAME, false); 1471 } 1472 1473 if (!utility.getResourcesPath().isEmpty()) { 1474 pathToFile(utility, utility.getResourcesPath(), RESOURCES_DIR_NAME, false); 1475 } 1476 1477 if (!utility.getAssetsPath().isEmpty()) { 1478 pathToFile(utility, utility.getAssetsPath(), ASSETS_DIR_NAME, false); 1479 } 1480 1481 for (String jarPathItem : utility.getFormattedJarPathList()) { 1482 pathToFile(utility, jarPathItem, NULL_DIR_NAME, false); 1483 } 1484 1485 for (String txtPathItem : utility.getFormattedTxtPathList()) { 1486 pathToFile(utility, txtPathItem, NULL_DIR_NAME, false); 1487 } 1488 } 1489 1490 /** 1491 * compress in app mode. 1492 * 1493 * @param utility common data 1494 * @throws BundleException FileNotFoundException|IOException. 1495 */ compressAppMode(Utility utility)1496 private void compressAppMode(Utility utility) throws BundleException { 1497 List<String> fileList = new ArrayList<>(); 1498 File appOutputFile = new File(utility.getOutPath().trim()); 1499 String tempPath = appOutputFile.getParentFile().getParent() + File.separator + TEMP_HAP_DIR; 1500 String hspTempDirPath = appOutputFile.getParentFile().getParent() + File.separator + TEMP_HSP_DIR; 1501 try { 1502 pathToFile(utility, utility.getJsonPath(), NULL_DIR_NAME, false); 1503 1504 if (!utility.getCertificatePath().isEmpty()) { 1505 pathToFile(utility, utility.getCertificatePath(), NULL_DIR_NAME, false); 1506 } 1507 1508 if (!utility.getSignaturePath().isEmpty()) { 1509 pathToFile(utility, utility.getSignaturePath(), NULL_DIR_NAME, false); 1510 } 1511 1512 File tempDir = new File(tempPath); 1513 if (!tempDir.exists()) { 1514 tempDir.mkdirs(); 1515 } 1516 1517 for (String hapPathItem : utility.getFormattedHapPathList()) { 1518 File hapFile = new File(hapPathItem.trim()); 1519 String hapTempPath = tempDir + File.separator + hapFile.getName(); 1520 fileList.add(hapTempPath); 1521 try { 1522 compressPackinfoIntoHap(hapPathItem, hapTempPath, utility.getPackInfoPath(), 1523 utility.getCompressLevel()); 1524 } catch (IOException e) { 1525 LOG.error(PackingToolErrMsg.COMPRESS_APP_IO_EXCEPTION.toString( 1526 "Compress pack.info into hap exist IOException: " + e.getMessage())); 1527 throw new BundleException("Compress pack.info into hap failed."); 1528 } 1529 } 1530 1531 File hspTempDir = new File(hspTempDirPath); 1532 if (!hspTempDir.exists()) { 1533 hspTempDir.mkdirs(); 1534 } 1535 for (String hspPathItem : utility.getFormattedHspPathList()) { 1536 File hspFile = new File(hspPathItem.trim()); 1537 String hspTempPath = hspTempDir + File.separator + hspFile.getName(); 1538 fileList.add(hspTempPath); 1539 try { 1540 compressPackinfoIntoHap(hspPathItem, hspTempPath, utility.getPackInfoPath(), 1541 utility.getCompressLevel()); 1542 } catch (IOException e) { 1543 LOG.error(PackingToolErrMsg.COMPRESS_APP_IO_EXCEPTION.toString( 1544 "Compress pack.info into hsp exist IOException: " + e.getMessage())); 1545 throw new BundleException("Compress pack.info into hsp failed."); 1546 } 1547 } 1548 // check hap is valid 1549 if (!checkHapIsValid(fileList, utility.getSharedApp())) { 1550 throw new BundleException("Verify failed when compress app."); 1551 } 1552 1553 for (String hapPath : fileList) { 1554 HapVerifyInfo hapVerifyInfo = hapVerifyInfoMap.get(getFileNameByPath(hapPath)); 1555 if (hapVerifyInfo != null && !hapVerifyInfo.isDebug()) { 1556 pathToFile(utility, hapPath, NULL_DIR_NAME, true); 1557 } else { 1558 pathToFile(utility, hapPath, NULL_DIR_NAME, false); 1559 } 1560 } 1561 1562 if (!utility.getEntryCardPath().isEmpty()) { 1563 String entryCardPath = ENTRYCARD_NAME + utility.getModuleName() + LINUX_FILE_SEPARATOR 1564 + ENTRYCARD_BASE_NAME + ENTRYCARD_SNAPSHOT_NAME; 1565 for (String entryCardPathItem : utility.getformattedEntryCardPathList()) { 1566 pathToFile(utility, entryCardPathItem, entryCardPath, true); 1567 } 1568 } 1569 1570 if (!utility.getPackResPath().isEmpty()) { 1571 pathToFile(utility, utility.getPackResPath(), NULL_DIR_NAME, false); 1572 } 1573 File file = new File(utility.getPackInfoPath()); 1574 compressFile(utility, file, NULL_DIR_NAME, false); 1575 // pack encrypt.json file 1576 packEncryptJsonFile(utility); 1577 // pack pac.json file 1578 packPacJsonFile(utility); 1579 } catch (BundleException e) { 1580 LOG.error(PackingToolErrMsg.COMPRESS_APP_FAILED.toString( 1581 "Compress app file exist BundleException: " + e.getMessage())); 1582 throw new BundleException("Compress app failed."); 1583 } finally { 1584 // delete temp file 1585 for (String path : fileList) { 1586 deleteFile(path); 1587 } 1588 deleteFile(tempPath); 1589 deleteFile(hspTempDirPath); 1590 } 1591 } 1592 compressFastAppMode(Utility utility)1593 private void compressFastAppMode(Utility utility) throws BundleException { 1594 Path appOutPath = Paths.get(utility.getOutPath().trim()); 1595 Path tmpDir = null; 1596 try { 1597 tmpDir = Files.createTempDirectory(appOutPath.getParent(), TEMP_DIR); 1598 Path appPackInfo = Paths.get(utility.getPackInfoPath()); 1599 List<String> fileList = new ArrayList<>(); 1600 for (String hapPath : utility.getFormattedHapPathList()) { 1601 Path path = Paths.get(hapPath); 1602 Path hap = PackageUtil.pack(path, appPackInfo, tmpDir, utility.getCompressLevel()); 1603 if (hap != null) { 1604 fileList.add(hap.toString()); 1605 } 1606 } 1607 for (String hspPath : utility.getFormattedHspPathList()) { 1608 Path path = Paths.get(hspPath); 1609 Path hsp = PackageUtil.pack(path, appPackInfo, tmpDir, utility.getCompressLevel()); 1610 if (hsp != null) { 1611 fileList.add(hsp.toString()); 1612 } 1613 } 1614 // check hap is valid 1615 if (!checkHapIsValid(fileList, utility.getSharedApp())) { 1616 throw new BundleException("Verify failed when compress fast app."); 1617 } 1618 // packApp 1619 packFastApp(utility, fileList); 1620 } catch (IOException ex) { 1621 LOG.error(PackingToolErrMsg.IO_EXCEPTION.toString("Compress fast app exist IOException: " + 1622 ex.getMessage())); 1623 throw new BundleException("Compressor::compressAppMode compress failed."); 1624 } finally { 1625 if (tmpDir != null) { 1626 PackageUtil.rmdir(tmpDir); 1627 } 1628 } 1629 } 1630 packFastApp(Utility utility, List<String> fileList)1631 private void packFastApp(Utility utility, List<String> fileList) throws BundleException { 1632 // pack.info 1633 pathToFile(utility, utility.getPackInfoPath(), NULL_DIR_NAME, false); 1634 // pack encrypt.json file 1635 packEncryptJsonFile(utility); 1636 // pack pac.json file 1637 packPacJsonFile(utility); 1638 // hap/hsp 1639 for (String hapPath : fileList) { 1640 HapVerifyInfo hapVerifyInfo = hapVerifyInfoMap.get(getFileNameByPath(hapPath)); 1641 if (hapVerifyInfo != null && !hapVerifyInfo.isDebug()) { 1642 pathToFile(utility, hapPath, NULL_DIR_NAME, true); 1643 } else { 1644 pathToFile(utility, hapPath, NULL_DIR_NAME, false); 1645 } 1646 } 1647 // form/card 1648 if (!utility.getEntryCardPath().isEmpty()) { 1649 String entryCardPath = ENTRYCARD_NAME + utility.getModuleName() + LINUX_FILE_SEPARATOR 1650 + ENTRYCARD_BASE_NAME + ENTRYCARD_SNAPSHOT_NAME; 1651 for (String entryCardPathItem : utility.getformattedEntryCardPathList()) { 1652 pathToFile(utility, entryCardPathItem, entryCardPath, true); 1653 } 1654 } 1655 if (!utility.getPackResPath().isEmpty()) { 1656 pathToFile(utility, utility.getPackResPath(), NULL_DIR_NAME, false); 1657 } 1658 // others 1659 if (!utility.getCertificatePath().isEmpty()) { 1660 pathToFile(utility, utility.getCertificatePath(), NULL_DIR_NAME, false); 1661 } 1662 if (!utility.getSignaturePath().isEmpty()) { 1663 pathToFile(utility, utility.getSignaturePath(), NULL_DIR_NAME, false); 1664 } 1665 } 1666 1667 /** 1668 * compress in app mode for multi project. 1669 * 1670 * @param utility common data 1671 * @throws BundleException FileNotFoundException|IOException. 1672 */ compressAppModeForMultiProject(Utility utility)1673 private void compressAppModeForMultiProject(Utility utility) throws BundleException { 1674 List<String> fileList = new ArrayList<>(); 1675 File appOutputFile = new File(utility.getOutPath().trim()); 1676 String tempPath = appOutputFile.getParentFile().getParent() + File.separator + TEMP_HAP_DIR; 1677 String tempSelectedHapPath = appOutputFile.getParentFile().getParent() +File.separator + TEMP_SELECTED_HAP_DIR; 1678 try { 1679 File tempSelectedHapDir = new File(tempSelectedHapPath); 1680 FileUtils.makeDir(tempSelectedHapDir); 1681 File tempHapDir = new File(tempPath); 1682 FileUtils.makeDir(tempHapDir); 1683 // pack app and dispose conflict 1684 // save hap name into list 1685 List<String> seletedHaps = new ArrayList<>(); 1686 String finalPackInfoStr = disposeApp(utility, seletedHaps, tempSelectedHapPath); 1687 // pack hap and dispose conflict 1688 finalPackInfoStr = disposeHap(utility, seletedHaps, tempSelectedHapPath, finalPackInfoStr); 1689 1690 // save final pack.info file 1691 String finalPackInfoPath = tempSelectedHapDir.getPath() + File.separator + PACKINFO_NAME; 1692 writePackInfo(finalPackInfoPath, finalPackInfoStr); 1693 // pack haps 1694 for (String selectedHapName : seletedHaps) { 1695 String hapPathItem = tempSelectedHapDir.getPath() + File.separator + selectedHapName; 1696 File hapFile = new File(hapPathItem.trim()); 1697 String hapTempPath = tempHapDir.getPath() + File.separator + hapFile.getName(); 1698 fileList.add(hapTempPath); 1699 compressPackinfoIntoHap(hapPathItem, hapTempPath, finalPackInfoPath, utility.getCompressLevel()); 1700 } 1701 // check hap is valid 1702 if (!checkHapIsValid(fileList, false)) { 1703 String errMsg = "Compressor::compressAppModeForMultiProject There are some " + 1704 "haps with different version code or duplicated moduleName or packageName."; 1705 throw new BundleException(errMsg); 1706 } 1707 for (String hapPath : fileList) { 1708 pathToFile(utility, hapPath, NULL_DIR_NAME, false); 1709 } 1710 File file = new File(finalPackInfoPath); 1711 compressFile(utility, file, NULL_DIR_NAME, false); 1712 //pack encrypt.json file 1713 packEncryptJsonFile(utility); 1714 // pack pac.json file 1715 packPacJsonFile(utility); 1716 } catch (BundleException | IOException exception) { 1717 String errMsg = "Compress app mode for multi project file exist Exception (BundleException | IOException): " 1718 + exception.getMessage(); 1719 LOG.error(PackingToolErrMsg.COMPRESS_APP_MODE_FORMULTI_PROJECT_FAILED.toString(errMsg)); 1720 throw new BundleException(errMsg); 1721 } finally { 1722 deleteFile(tempPath); 1723 deleteFile(tempSelectedHapPath); 1724 } 1725 } 1726 1727 /** 1728 * compress in hapAddition mode. 1729 * 1730 * @param utility common data 1731 */ hapAddition(Utility utility)1732 private void hapAddition(Utility utility) { 1733 File hapPath = new File(utility.getAbsoluteHapPath()); 1734 String hapFileName = hapPath.getName(); 1735 1736 File destFile = new File(utility.getOutPath() + LINUX_FILE_SEPARATOR + hapFileName); 1737 File outParentFile = destFile.getParentFile(); 1738 if ((outParentFile != null) && (!outParentFile.exists())) { 1739 if (!outParentFile.mkdirs()) { 1740 LOG.error(PackingToolErrMsg.HAP_ADDITION_FAILED.toString("Create out file parent directory failed.")); 1741 } 1742 } 1743 FileOutputStream fileOut = null; 1744 CheckedOutputStream checkedOut = null; 1745 String currentDir = System.getProperty("user.dir"); 1746 String hapAdditionPath = currentDir + LINUX_FILE_SEPARATOR + HAPADDITION_FOLDER_NAME; 1747 String backName = BACKUP_PREFIX + hapFileName; 1748 String hapPathOri = utility.getHapPath(); 1749 try { 1750 copyHapFile(utility, backName); 1751 fileOut = new FileOutputStream(destFile); 1752 checkedOut = new CheckedOutputStream(fileOut, new CRC32()); 1753 zipOut = new ZipArchiveOutputStream(checkedOut); 1754 1755 compressHapAddition(utility, hapAdditionPath); 1756 } catch (BundleException | IOException exception) { 1757 LOG.error(PackingToolErrMsg.HAP_ADDITION_FAILED.toString("Hap addition exist Exception " + 1758 "(BundleException | IOException): " + exception.getMessage())); 1759 copyFileSafely(backName, hapPathOri); 1760 } finally { 1761 closeZipOutputStream(); 1762 Utility.closeStream(zipOut); 1763 Utility.closeStream(checkedOut); 1764 Utility.closeStream(fileOut); 1765 // delete packaging and unpacking process files 1766 deleteFile(backName); 1767 deleteFile(hapAdditionPath); 1768 } 1769 } 1770 copyHapFile(Utility utility, String backName)1771 private void copyHapFile(Utility utility, String backName) throws IOException, BundleException { 1772 File hapFile = new File(utility.getAbsoluteHapPath()); 1773 String currentDir = System.getProperty("user.dir"); 1774 String backupPath = currentDir + LINUX_FILE_SEPARATOR + backName; 1775 File backupFile = new File(backupPath); 1776 FileUtils.copyFile(hapFile, backupFile); 1777 utility.setHapPath(backName); 1778 } 1779 copyFileSafely(String source, String dest)1780 private void copyFileSafely(String source, String dest) { 1781 try { 1782 File sourceFile = new File(source); 1783 File destFile = new File(dest); 1784 FileUtils.copyFile(sourceFile, destFile); 1785 } catch (IOException | BundleException e) { 1786 LOG.error(PackingToolErrMsg.COPY_FILE_SAFELY_FAILED.toString("Copy file exist Exception " + 1787 "(IOException | BundleException): " + e.getMessage())); 1788 } 1789 } 1790 readerFile(String jsonPath)1791 private static String readerFile(String jsonPath) throws IOException { 1792 byte[] bytes = Files.readAllBytes(Paths.get(jsonPath)); 1793 return new String(bytes, StandardCharsets.UTF_8); 1794 } 1795 writeJsonFile(String dataJson, String targetPath)1796 private static void writeJsonFile(String dataJson, String targetPath) throws BundleException { 1797 try (FileWriter fileWriter = new FileWriter(targetPath)) { 1798 Object object = JSON.parse(dataJson); 1799 String jsonString = new String(); 1800 if (object instanceof JSONArray) { 1801 JSONArray jsonArray = JSONArray.parseArray(dataJson); 1802 jsonString = JSON.toJSONString( 1803 jsonArray, SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue); 1804 } else { 1805 JSONObject jsonObject = JSONObject.parseObject(dataJson); 1806 jsonString = JSON.toJSONString( 1807 jsonObject, SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue); 1808 } 1809 fileWriter.write(jsonString); 1810 fileWriter.flush(); 1811 } catch (IOException exception) { 1812 LOG.error(PackingToolErrMsg.IO_EXCEPTION.toString("Write json File exist IOException: " + 1813 exception.getMessage())); 1814 throw new BundleException(exception.getMessage()); 1815 } catch (JSONException e) { 1816 LOG.error(PackingToolErrMsg.WRITE_JSON_FILE_EXPECTION.toString("Write json file exist JSONException: " + 1817 e.getMessage())); 1818 throw new BundleException(e.getMessage()); 1819 } 1820 } 1821 setUtilityParameter(String hapAdditionPath, Utility utility)1822 private static void setUtilityParameter(String hapAdditionPath, Utility utility) throws IOException { 1823 Path basePath = Paths.get(hapAdditionPath); 1824 try (Stream<Path> pathStream = Files.walk(basePath, 1)) { 1825 pathStream.forEach(path -> { 1826 String fileName = path.getFileName().toString(); 1827 String filePath = path.toString(); 1828 switch (fileName) { 1829 case ETS_FILE_NAME: 1830 utility.setEtsPath(filePath); 1831 break; 1832 case DIR_FILE_NAME: 1833 utility.setLibPath(filePath); 1834 break; 1835 case AN_FILE_NAME: 1836 utility.setANPath(filePath); 1837 break; 1838 case AP_FILE_NAME: 1839 utility.setAPPath(filePath); 1840 break; 1841 case RESOURCE_FILE_NAME: 1842 utility.setResourcesPath(filePath); 1843 break; 1844 case JS_FILE_NAME: 1845 utility.setJsPath(filePath); 1846 break; 1847 case ASSETS_FILE_NAME: 1848 utility.setAssetsPath(filePath); 1849 break; 1850 case MAPLE_FILE_NAME: 1851 utility.setSoDir(filePath); 1852 break; 1853 case SHARED_LIBS_FILE_NAME: 1854 utility.setSharedLibsPath(filePath); 1855 break; 1856 case MODULE_JSON: 1857 utility.setJsonPath(filePath); 1858 break; 1859 case RES_INDEX: 1860 utility.setIndexPath(filePath); 1861 break; 1862 case PACKINFO_NAME: 1863 utility.setPackInfoPath(filePath); 1864 break; 1865 } 1866 }); 1867 } 1868 } 1869 compressHapAddition(Utility utility, String hapAdditionPath)1870 private void compressHapAddition(Utility utility, String hapAdditionPath) throws BundleException { 1871 // decompression hap file to hapAddition 1872 1873 unpackHap(utility.getHapPath(), hapAdditionPath); 1874 1875 // generate addition.json file 1876 try { 1877 String data = readerFile(utility.getJsonPath()); 1878 String currentDir = System.getProperty("user.dir"); 1879 String targetParentPath = currentDir + LINUX_FILE_SEPARATOR + TARGET_FILE_PATH; 1880 File targetParent = new File(targetParentPath); 1881 if (!targetParent.exists()) { 1882 if (!targetParent.mkdirs()) { 1883 LOG.error(PackingToolErrMsg.COMPRESS_HAP_ADDITION_FAILED.toString( 1884 "Create target file parent directory failed.")); 1885 } 1886 } 1887 String targetPath = targetParentPath + LINUX_FILE_SEPARATOR + ADDITION_JSON; 1888 writeJsonFile(data, targetPath); 1889 } catch (IOException | JSONException | BundleException e) { 1890 String errMsg = "Generate addition.json file exist Exception" + 1891 " (IOException | JSONException | BundleException): " + e.getMessage(); 1892 LOG.error(PackingToolErrMsg.COMPRESS_HAP_ADDITION_FAILED.toString(errMsg)); 1893 throw new BundleException(errMsg); 1894 } 1895 1896 // package a new hap file 1897 try { 1898 setUtilityParameter(hapAdditionPath, utility); 1899 } catch (IOException e) { 1900 String errMsg = "Set utility parameter exist IOException: " + e.getMessage(); 1901 LOG.error(PackingToolErrMsg.IO_EXCEPTION.toString(errMsg)); 1902 throw new BundleException(errMsg); 1903 } 1904 if (utility.getHapPath().endsWith(HAP_SUFFIX)) { 1905 compressHap(utility); 1906 } else if (utility.getHapPath().endsWith(HSP_SUFFIX)) { 1907 compressHsp(utility); 1908 } else { 1909 String errMsg = "Compression add failed because file (" + utility.getHapPath() + 1910 ") is an unsupported file type."; 1911 LOG.error(PackingToolErrMsg.COMPRESS_HAP_ADDITION_FAILED.toString(errMsg)); 1912 throw new BundleException(errMsg); 1913 } 1914 } 1915 1916 /** 1917 * pack hap in app to selectedHaps 1918 * 1919 * @param utility is common data 1920 * @param seletedHaps is seleted haps should be pack into app 1921 * @return the final pack.info string after dispose app 1922 * @throws BundleException FileNotFoundException|IOException. 1923 */ disposeApp(Utility utility, List<String> seletedHaps, String tempDir)1924 private static String disposeApp(Utility utility, List<String> seletedHaps, 1925 String tempDir) throws BundleException { 1926 // dispose app conflict 1927 if (utility.getFormattedAppList().isEmpty()) { 1928 return ""; 1929 } 1930 String finalAppPackInfo = ""; 1931 try { 1932 for (String appPath : utility.getFormattedAppList()) { 1933 // select hap in app 1934 finalAppPackInfo = selectHapInApp(appPath, seletedHaps, tempDir, finalAppPackInfo); 1935 } 1936 } catch (BundleException | IOException e) { 1937 String errMsg = "Dispose app exist Exception (BundleException | IOException): " + e.getMessage(); 1938 LOG.error(PackingToolErrMsg.DISPOSE_APP_FAILED.toString(errMsg)); 1939 throw new BundleException(errMsg); 1940 } 1941 return finalAppPackInfo; 1942 } 1943 1944 /** 1945 * select hap from app file list 1946 * 1947 * @param appPath is common data 1948 * @param selectedHaps is list of packInfos 1949 * @throws BundleException FileNotFoundException|IOException. 1950 */ selectHapInApp(String appPath, List<String> selectedHaps, String tempDir, String finalAppPackInfo)1951 private static String selectHapInApp(String appPath, List<String> selectedHaps, String tempDir, 1952 String finalAppPackInfo) throws BundleException, IOException { 1953 List<String> selectedHapsInApp = new ArrayList<>(); 1954 // classify hap in app 1955 copyHapAndHspFromApp(appPath, selectedHapsInApp, selectedHaps, tempDir); 1956 // rebuild pack.info 1957 String packInfoStr = FileUtils.getJsonInZips(new File(appPath), PACKINFO_NAME); 1958 if (packInfoStr.isEmpty()) { 1959 String errorMsg = "Select hap from app find that app does not have pack.info."; 1960 LOG.error(PackingToolErrMsg.NO_PACK_INFO.toString(errorMsg)); 1961 throw new BundleException(errorMsg); 1962 } 1963 if (finalAppPackInfo.isEmpty()) { 1964 finalAppPackInfo = packInfoStr; 1965 return finalAppPackInfo; 1966 } 1967 // read selected module in temp hap 1968 HashMap<String, String> packagePair = new HashMap<>(); 1969 for (String hapName : selectedHapsInApp) { 1970 packagePair.put(hapName, readModlueNameFromHap(tempDir + File.separator + hapName)); 1971 } 1972 return ModuleJsonUtil.mergeTwoPackInfoByPackagePair(finalAppPackInfo, packInfoStr, packagePair); 1973 } 1974 1975 /** 1976 * copy hap from app file 1977 * 1978 * @param appPath is common data 1979 * @param selectedHapsInApp is list of haps and hsps selected in app file 1980 * @param selectedHaps is the list of haps and hsps selected in input 1981 * @throws BundleException FileNotFoundException|IOException. 1982 */ copyHapAndHspFromApp(String appPath, List<String> selectedHapsInApp, List<String> selectedHaps, String tempDir)1983 private static void copyHapAndHspFromApp(String appPath, List<String> selectedHapsInApp, List<String> selectedHaps, 1984 String tempDir) throws BundleException { 1985 ZipInputStream zipInput = null; 1986 ZipFile zipFile = null; 1987 OutputStream outputStream = null; 1988 InputStream inputStream = null; 1989 ZipEntry zipEntry = null; 1990 try { 1991 zipInput = new ZipInputStream(new FileInputStream(appPath)); 1992 zipFile = new ZipFile(appPath); 1993 while ((zipEntry = zipInput.getNextEntry()) != null) { 1994 File file = null; 1995 if (!zipEntry.getName().endsWith(HAP_SUFFIX) && !zipEntry.getName().endsWith(HSP_SUFFIX)) { 1996 continue; 1997 } 1998 // copy duplicated hap to duplicated dir and get moduleName of duplicated hap 1999 if (selectedHaps.contains(zipEntry.getName())) { 2000 LOG.error(PackingToolErrMsg.COMPRESS_FILE_DUPLICATE.toString("Copy hap from app file exist hap " + 2001 "with duplicate file names. file is " + zipEntry.getName() + ".")); 2002 throw new BundleException("Compressor::copyHapFromApp file duplicated, file is " 2003 + zipEntry.getName() + "."); 2004 } else { 2005 // copy selectedHap to tempDir 2006 file = new File(tempDir + File.separator + zipEntry.getName()); 2007 selectedHaps.add(file.getName()); 2008 selectedHapsInApp.add(file.getName()); 2009 } 2010 outputStream = new FileOutputStream(file); 2011 inputStream = zipFile.getInputStream(zipEntry); 2012 int len; 2013 byte[] buf = new byte[BUFFER_SIZE]; 2014 while ((len = inputStream.read(buf)) != -1) { 2015 outputStream.write(buf, 0, len); 2016 } 2017 outputStream.close(); 2018 inputStream.close(); 2019 } 2020 } catch (IOException e) { 2021 String errMsg = "Copy hap and hsp from app exist IOException: " + e.getMessage(); 2022 LOG.error(PackingToolErrMsg.IO_EXCEPTION.toString(errMsg)); 2023 throw new BundleException(errMsg); 2024 } finally { 2025 Utility.closeStream(zipInput); 2026 Utility.closeStream(zipFile); 2027 Utility.closeStream(outputStream); 2028 Utility.closeStream(inputStream); 2029 } 2030 } 2031 2032 /** 2033 * read moduleName in hap 2034 * 2035 * @param hapPath is path of hap file 2036 * @throws BundleException FileNotFoundException|IOException. 2037 */ readModlueNameFromHap(String hapPath)2038 private static String readModlueNameFromHap(String hapPath) throws BundleException { 2039 String moduleName = ""; 2040 File hapFile = new File(hapPath); 2041 if (isModuleHap(hapPath)) { 2042 String jsonString = FileUtils.getJsonInZips(hapFile, MODULE_JSON); 2043 moduleName = ModuleJsonUtil.parseStageModuleName(jsonString); 2044 } else { 2045 String jsonString = FileUtils.getJsonInZips(hapFile, CONFIG_JSON); 2046 moduleName = ModuleJsonUtil.parseFaModuleName(jsonString); 2047 } 2048 return moduleName; 2049 } 2050 2051 /** 2052 * dispose input of hap 2053 * 2054 * @param utility is common data 2055 * @param seletedHaps is the selected haps of all input 2056 * @param tempDir is the path of temp directory 2057 * @param finalPackInfoStr is the pack.info of the final app 2058 * @throws BundleException FileNotFoundException|IOException. 2059 */ disposeHap(Utility utility, List<String> seletedHaps, String tempDir, String finalPackInfoStr)2060 private static String disposeHap(Utility utility, List<String> seletedHaps, String tempDir, 2061 String finalPackInfoStr) throws BundleException, IOException { 2062 // dispose hap conflict 2063 if (utility.getFormattedHapList().isEmpty()) { 2064 return finalPackInfoStr; 2065 } 2066 for (String hapPath : utility.getFormattedHapList()) { 2067 if (seletedHaps.contains(new File(hapPath).getName())) { 2068 LOG.error(PackingToolErrMsg.COMPRESS_FILE_DUPLICATE.toString("Dispose hap exist duplicate file " + 2069 "names, file is " + new File(hapPath).getName() + ".")); 2070 throw new BundleException("Compressor::disposeHap file duplicated, file is " 2071 + new File(hapPath).getName() + "."); 2072 } 2073 File hapFile = new File(hapPath); 2074 seletedHaps.add(hapFile.getName()); 2075 // copy hap to tempDir 2076 FileUtils.copyFile(hapFile, new File((tempDir +File.separator + hapFile.getName()))); 2077 String packInfo = FileUtils.getJsonInZips(hapFile, PACKINFO_NAME); 2078 2079 if (packInfo.isEmpty()) { 2080 String errMsg = "Hap does not have pack.info."; 2081 LOG.error(PackingToolErrMsg.NO_PACK_INFO.toString(errMsg)); 2082 throw new BundleException(errMsg); 2083 } 2084 if (finalPackInfoStr.isEmpty()) { 2085 finalPackInfoStr = packInfo; 2086 } else { 2087 finalPackInfoStr = ModuleJsonUtil.mergeTwoPackInfo(finalPackInfoStr, packInfo); 2088 } 2089 } 2090 return finalPackInfoStr; 2091 } 2092 2093 /** 2094 * write string to pack.info 2095 * 2096 * @param filePath pack.info file path 2097 * @param packInfoStr is the string of pack.info 2098 * @throws BundleException FileNotFoundException|IOException. 2099 */ writePackInfo(String filePath, String packInfoStr)2100 private void writePackInfo(String filePath, String packInfoStr) throws BundleException, IOException { 2101 FileWriter fwriter = null; 2102 try { 2103 fwriter = new FileWriter(filePath); 2104 fwriter.write(packInfoStr); 2105 } catch (IOException e) { 2106 String errMsg = "Write pack info exist IOException: " + e.getMessage(); 2107 LOG.error(PackingToolErrMsg.IO_EXCEPTION.toString(errMsg)); 2108 throw new BundleException(errMsg); 2109 } finally { 2110 if (fwriter != null) { 2111 fwriter.flush(); 2112 fwriter.close(); 2113 } 2114 } 2115 } 2116 copy(InputStream input, OutputStream output)2117 private void copy(InputStream input, OutputStream output) throws IOException { 2118 int bytesRead; 2119 byte[] data = new byte[BUFFER_SIZE]; 2120 while ((bytesRead = input.read(data, 0, BUFFER_SIZE)) != -1) { 2121 output.write(data, 0, bytesRead); 2122 } 2123 } 2124 compressPackinfoIntoHap(String hapPathItem, String outPathString, String packInfo, int compressLevel)2125 private void compressPackinfoIntoHap(String hapPathItem, String outPathString, String packInfo, int compressLevel) 2126 throws IOException, BundleException { 2127 ZipFile sourceHapFile = new ZipFile(hapPathItem); 2128 ZipOutputStream append = new ZipOutputStream(new FileOutputStream(outPathString)); 2129 append.setLevel(compressLevel); 2130 try { 2131 Enumeration<? extends ZipEntry> entries = sourceHapFile.entries(); 2132 while (entries.hasMoreElements()) { 2133 ZipEntry zipEntry = new ZipEntry(entries.nextElement()); 2134 if (PACKINFO_NAME.equals(zipEntry.getName())) { 2135 continue; 2136 } 2137 ZipEntry newEntry = zipEntry.getMethod() == 2138 ZipEntry.STORED ? new ZipEntry(zipEntry) : new ZipEntry(zipEntry.getName()); 2139 append.putNextEntry(newEntry); 2140 if (!zipEntry.isDirectory()) { 2141 copy(sourceHapFile.getInputStream(zipEntry), append); 2142 } 2143 append.closeEntry(); 2144 } 2145 File packInfoFile = new File(packInfo); 2146 ZipEntry zipEntry = getStoredZipEntry(packInfoFile, PACKINFO_NAME); 2147 append.putNextEntry(zipEntry); 2148 FileInputStream in = new FileInputStream(packInfoFile); 2149 try { 2150 byte[] buf = new byte[BUFFER_SIZE]; 2151 int len; 2152 while ((len = in.read(buf)) != -1) { 2153 append.write(buf, 0, len); 2154 } 2155 } finally { 2156 in.close(); 2157 } 2158 append.closeEntry(); 2159 } catch (IOException exception) { 2160 LOG.error(PackingToolErrMsg.COMPRESS_FILE_EXCEPTION.toString( 2161 "Compress pack.info into hap exist IOException: " + exception.getMessage())); 2162 throw new BundleException("Compress PackInfo into hap IOException."); 2163 } finally { 2164 sourceHapFile.close(); 2165 append.close(); 2166 } 2167 } 2168 2169 /** 2170 * delete file 2171 * 2172 * @param path file path which will be deleted 2173 */ deleteFile(final String path)2174 private static void deleteFile(final String path) { 2175 File file = new File(path); 2176 if (file.exists()) { 2177 if (file.isDirectory()) { 2178 File[] files = file.listFiles(); 2179 for (int i = 0; i < files.length; i++) { 2180 deleteFile(files[i].toString()); 2181 } 2182 } 2183 file.delete(); 2184 } 2185 } 2186 2187 /** 2188 * compress in res mode. 2189 * 2190 * @param utility common data 2191 * @throws BundleException FileNotFoundException|IOException. 2192 */ compressPackResMode(Utility utility)2193 private void compressPackResMode(Utility utility) throws BundleException { 2194 if (!utility.getPackInfoPath().isEmpty()) { 2195 parsePackInfoJsonFile(utility, utility.getPackInfoPath()); 2196 File file = new File(utility.getPackInfoPath()); 2197 infoSpecialProcess(utility, file); 2198 } 2199 if (!utility.getEntryCardPath().isEmpty()) { 2200 getFileList(utility.getEntryCardPath()); 2201 List<String> snapshotNameList = new ArrayList<>(); 2202 for (String fileName : fileNameList) { 2203 if (fileName.endsWith(PNG_SUFFIX) || fileName.endsWith(UPPERCASE_PNG_SUFFIX)) { 2204 String fName = fileName.trim(); 2205 String[] temp = fName.replace("\\", "/").split("/"); 2206 if (temp.length < 4) { 2207 LOG.error(PackingToolErrMsg.COMPRESS_PACK_RES_MODE_FAILED.toString("The hap file path is " 2208 + "invalid, length is " + temp.length + ", expected at least 4.")); 2209 continue; 2210 } 2211 String fileLanguageCountryName = temp[temp.length - 3]; 2212 if (!isThirdLevelDirectoryNameValid(fileLanguageCountryName)) { 2213 LOG.error(PackingToolErrMsg.COMPRESS_PACK_RES_MODE_FAILED.toString("Third level " 2214 + "directory name: " + fileLanguageCountryName + " is invalid, please check it with " 2215 + "reference to this example: zh_Hani_CN-vertical-car-mdpi-dark or " 2216 + "zh_Hani_CN-vertical-car-mdpi.")); 2217 throw new BundleException("Compress failed third level directory name Error."); 2218 } 2219 String filePicturingName = temp[temp.length - 1]; 2220 if (!isPicturing(filePicturingName, utility)) { 2221 LOG.error(PackingToolErrMsg.COMPRESS_PACK_RES_MODE_FAILED.toString("Invalid resource file" 2222 + " name: " + filePicturingName + ", correct format example is formName-2x2.png.")); 2223 throw new BundleException("Compress pack.res failed, Invalid resource file name: " 2224 + filePicturingName + ", correct format example is formName-2x2.png."); 2225 } 2226 2227 String fullSnapshotName = temp[temp.length - 4] + "/" + 2228 filePicturingName.substring(0, filePicturingName.lastIndexOf(".")); 2229 snapshotNameList.add(fullSnapshotName); 2230 2231 } else { 2232 LOG.error(PackingToolErrMsg.COMPRESS_PACK_RES_MODE_FAILED.toString("No PNG format image found.")); 2233 throw new BundleException("Compress pack.res failed, compress failed No image in" 2234 + " PNG format is found."); 2235 } 2236 } 2237 2238 for (String formName : formNamesList) { 2239 if (!snapshotNameList.contains(formName)) { 2240 LOG.error(PackingToolErrMsg.COMPRESS_PACK_RES_MODE_FAILED.toString("EntryCard has no related " 2241 + "snapshot. " + formName + " has no related snapshot " 2242 + snapshotNameList.toString() + ".")); 2243 throw new BundleException("Compress pack.res failed, compress failed entryCard has no related snapshot."); 2244 } 2245 } 2246 pathToFileResMode(utility, utility.getEntryCardPath(), ENTRYCARD_NAME, false); 2247 } 2248 } 2249 2250 /** 2251 * Check whether modelname meets specifications. 2252 * 2253 * @param name modelName 2254 * @return false and true 2255 */ isModelName(String name)2256 private boolean isModelName(String name) { 2257 for (String listName : list) { 2258 if (name.equals(listName)) { 2259 return true; 2260 } 2261 } 2262 return false; 2263 } 2264 isThirdLevelDirectoryNameValid(String thirdLevelDirectoryName)2265 private boolean isThirdLevelDirectoryNameValid(String thirdLevelDirectoryName) { 2266 if (thirdLevelDirectoryName == null || thirdLevelDirectoryName.isEmpty()) { 2267 return false; 2268 } 2269 if (ENTRYCARD_BASE_NAME.equals(thirdLevelDirectoryName)) { 2270 return true; 2271 } 2272 // example: zh_Hani_CN-vertical-car-mdpi-dark or zh_Hani_CN-vertical-car-mdpi 2273 int firstDelimiterIndex = thirdLevelDirectoryName.indexOf("_"); 2274 if (firstDelimiterIndex < 0) { 2275 return false; 2276 } 2277 String language = thirdLevelDirectoryName.substring(0, firstDelimiterIndex); 2278 int secondDelimiterIndex = thirdLevelDirectoryName.indexOf("_", firstDelimiterIndex + 1); 2279 if (secondDelimiterIndex < 0) { 2280 return false; 2281 } 2282 String script = thirdLevelDirectoryName.substring(firstDelimiterIndex + 1, secondDelimiterIndex); 2283 int thirdDelimiterIndex = thirdLevelDirectoryName.indexOf("-", secondDelimiterIndex + 1); 2284 if (thirdDelimiterIndex < 0) { 2285 return false; 2286 } 2287 String country = thirdLevelDirectoryName.substring(secondDelimiterIndex + 1, thirdDelimiterIndex); 2288 if (!checkLanguage(language) || !checkScript(script) || !checkCountry(country)) { 2289 return false; 2290 } 2291 int forthDelimiterIndex = thirdLevelDirectoryName.indexOf("-", thirdDelimiterIndex + 1); 2292 if (forthDelimiterIndex < 0) { 2293 return false; 2294 } 2295 String orientation = thirdLevelDirectoryName.substring(thirdDelimiterIndex + 1, forthDelimiterIndex); 2296 int fifthDelimiterIndex = thirdLevelDirectoryName.indexOf("-", forthDelimiterIndex + 1); 2297 if (fifthDelimiterIndex < 0) { 2298 return false; 2299 } 2300 String deviceType = thirdLevelDirectoryName.substring(forthDelimiterIndex + 1, fifthDelimiterIndex); 2301 if (!checkOrientation(orientation) || !checkDeviceType(deviceType)) { 2302 return false; 2303 } 2304 int sixthDelimiterIndex = thirdLevelDirectoryName.indexOf("-", fifthDelimiterIndex + 1); 2305 if (sixthDelimiterIndex < 0) { 2306 String screenDensity = thirdLevelDirectoryName.substring(fifthDelimiterIndex + 1, 2307 thirdLevelDirectoryName.length()); 2308 return checkScreenDensity(screenDensity); 2309 } else { 2310 String screenDensity = thirdLevelDirectoryName.substring(fifthDelimiterIndex + 1, sixthDelimiterIndex); 2311 if (!checkScreenDensity(screenDensity)) { 2312 return false; 2313 } 2314 } 2315 int seventhDelimiterIndex = thirdLevelDirectoryName.indexOf("-", sixthDelimiterIndex + 1); 2316 if (seventhDelimiterIndex < 0) { 2317 String tmp = thirdLevelDirectoryName.substring(sixthDelimiterIndex + 1, thirdLevelDirectoryName.length()); 2318 return checkColorModeOrShape(tmp); 2319 } 2320 if (!checkColorMode(thirdLevelDirectoryName.substring(sixthDelimiterIndex + 1, seventhDelimiterIndex))) { 2321 return false; 2322 } 2323 String shape = thirdLevelDirectoryName.substring(seventhDelimiterIndex + 1, thirdLevelDirectoryName.length()); 2324 return checkShape(shape); 2325 } 2326 checkLanguage(String language)2327 private boolean checkLanguage(String language) { 2328 if (!Pattern.compile(REGEX_LANGUAGE).matcher(language).matches()) { 2329 LOG.error(PackingToolErrMsg.INVALID_THIRD_LEVEL_DIRECTORY_NAME.toString("The language " + language + 2330 " is not in ISO 639-1 list.")); 2331 return false; 2332 } 2333 return true; 2334 } 2335 checkScript(String script)2336 private boolean checkScript(String script) { 2337 if (!Pattern.compile(REGEX_SCRIPT).matcher(script).matches()) { 2338 LOG.error(PackingToolErrMsg.INVALID_THIRD_LEVEL_DIRECTORY_NAME.toString("The script " + script + 2339 " is not in ISO 15924 list.")); 2340 return false; 2341 } 2342 return true; 2343 } 2344 checkCountry(String country)2345 private boolean checkCountry(String country) { 2346 if (!Pattern.compile(REGEX_COUNTRY).matcher(country).matches()) { 2347 LOG.error(PackingToolErrMsg.INVALID_THIRD_LEVEL_DIRECTORY_NAME.toString("The country " + country + 2348 " is not in ISO 3166-1 list.")); 2349 return false; 2350 } 2351 return true; 2352 } 2353 checkOrientation(String orientation)2354 private boolean checkOrientation(String orientation) { 2355 if (!Pattern.compile(REGEX_ORIENTATION).matcher(orientation).matches()) { 2356 LOG.error(PackingToolErrMsg.INVALID_THIRD_LEVEL_DIRECTORY_NAME.toString("The orientation " + orientation + 2357 " is not in {vertical, horizontal} list.")); 2358 return false; 2359 } 2360 return true; 2361 } 2362 checkDeviceType(String deviceType)2363 private boolean checkDeviceType(String deviceType) { 2364 if (!Pattern.compile(REGEX_DEVICE_TYPE).matcher(deviceType).matches()) { 2365 LOG.error(PackingToolErrMsg.INVALID_THIRD_LEVEL_DIRECTORY_NAME.toString("The deviceType " + deviceType + 2366 " is not in {phone, tablet, car, tv, wearable, liteWearable, 2in1} list.")); 2367 return false; 2368 } 2369 return true; 2370 } 2371 checkScreenDensity(String screenDensity)2372 private boolean checkScreenDensity(String screenDensity) { 2373 if (!Pattern.compile(REGEX_SCREEN_DENSITY).matcher(screenDensity).matches()) { 2374 LOG.error(PackingToolErrMsg.INVALID_THIRD_LEVEL_DIRECTORY_NAME.toString("The screenDensity " + 2375 screenDensity + " is not in {sdpi, mdpi, ldpi, xldpi, xxldpi} list.")); 2376 return false; 2377 } 2378 return true; 2379 } 2380 checkColorMode(String colorMode)2381 private boolean checkColorMode(String colorMode) { 2382 if (!Pattern.compile(REGEX_COLOR_MODE).matcher(colorMode).matches()) { 2383 LOG.error(PackingToolErrMsg.INVALID_THIRD_LEVEL_DIRECTORY_NAME.toString("The colorMode " + colorMode + 2384 " is not in {light, dark} list.")); 2385 return false; 2386 } 2387 return true; 2388 } 2389 checkColorModeOrShape(String tmp)2390 private boolean checkColorModeOrShape(String tmp) { 2391 if (Pattern.compile(REGEX_COLOR_MODE).matcher(tmp).matches() || 2392 Pattern.compile(REGEX_SHAPE).matcher(tmp).matches()) { 2393 return true; 2394 } 2395 LOG.error(PackingToolErrMsg.INVALID_THIRD_LEVEL_DIRECTORY_NAME.toString("The colorMode or shape " + tmp + 2396 " is neither in colorMode list {light, dark} nor in shape list {circle}.")); 2397 return false; 2398 } 2399 checkShape(String shape)2400 private boolean checkShape(String shape) { 2401 if (Pattern.compile(REGEX_SHAPE).matcher(shape).matches()) { 2402 return true; 2403 } 2404 LOG.error(PackingToolErrMsg.INVALID_THIRD_LEVEL_DIRECTORY_NAME.toString("The shape " + shape + 2405 " is not in {circle} list.")); 2406 return false; 2407 } 2408 2409 /** 2410 * Check whether picturingName meets specifications. 2411 * 2412 * @param name picturingName 2413 * @param utility common data 2414 * @return false and true 2415 */ isPicturing(String name, Utility utility)2416 private boolean isPicturing(String name, Utility utility) { 2417 boolean isSpecifications = false; 2418 if (name == null || name.isEmpty()) { 2419 return isSpecifications; 2420 } 2421 if (!name.endsWith(PNG_SUFFIX) && !name.endsWith(UPPERCASE_PNG_SUFFIX)) { 2422 LOG.error(PackingToolErrMsg.IS_PICTURING_FAILED.toString("The suffix is not .png or .PNG.")); 2423 return false; 2424 } 2425 int delimiterIndex = name.lastIndexOf("-"); 2426 if (delimiterIndex < 0) { 2427 LOG.error(PackingToolErrMsg.IS_PICTURING_FAILED.toString( 2428 "The entry card naming format is invalid and should be separated by '-'.")); 2429 return false; 2430 } 2431 String formName = name.substring(0, delimiterIndex); 2432 if (!utility.getFormNameList().contains(formName)) { 2433 LOG.error(PackingToolErrMsg.IS_PICTURING_FAILED.toString( 2434 "The name is not same as formName, name: " + formName + " is not in " 2435 + utility.getFormNameList().toString() + ".")); 2436 return false; 2437 } 2438 String dimension = name.substring(delimiterIndex + 1, name.lastIndexOf(".")); 2439 if (!supportDimensionsList.contains(dimension)) { 2440 LOG.error(PackingToolErrMsg.IS_PICTURING_FAILED.toString("The dimension " + dimension + 2441 " is invalid, is not in the following list: {1X2, 2X2, 2X4, 4X4, 1X1, 6X4}.")); 2442 return false; 2443 } 2444 2445 return true; 2446 } 2447 getFileList(final String filePath)2448 private void getFileList(final String filePath) throws BundleException { 2449 File file = new File(filePath); 2450 if (!file.exists()) { 2451 LOG.error(PackingToolErrMsg.FILE_NOT_EXIST.toString("File does not exist. File path is " 2452 + filePath + ".")); 2453 return; 2454 } 2455 File[] files = file.listFiles(); 2456 if (files == null) { 2457 LOG.error(PackingToolErrMsg.GET_FILE_LIST_FAILED.toString("No files found in the specified path: " 2458 + filePath + ".")); 2459 return; 2460 } 2461 for (File f : files) { 2462 try { 2463 if (f.isFile()) { 2464 if (f.getName().endsWith(".DS_Store")) { 2465 deleteFile(f.getCanonicalPath()); 2466 continue; 2467 } 2468 String snapshotDirectoryName = f.getParentFile().getName(); 2469 if (!ENTRYCARD_SNAPSHOT_NAME.equals(snapshotDirectoryName)) { 2470 LOG.error(PackingToolErrMsg.GET_FILE_LIST_FAILED.toString("The level-4 directory of EntryCard " 2471 + "must be named as snapshot, but current is: " + snapshotDirectoryName + ".")); 2472 throw new BundleException("The level-4 directory of EntryCard must be named as snapshot" + 2473 ", but current is: " + snapshotDirectoryName + "."); 2474 } 2475 fileNameList.add(f.getCanonicalPath()); 2476 } else if (f.isDirectory()) { 2477 getFileList(f.getCanonicalPath()); 2478 } else { 2479 LOG.error(PackingToolErrMsg.GET_FILE_LIST_FAILED.toString("It's not file or directory.")); 2480 } 2481 } catch (IOException msg) { 2482 LOG.error(PackingToolErrMsg.IO_EXCEPTION.toString("Get file list exist IOException: " 2483 + msg.getMessage())); 2484 return; 2485 } 2486 } 2487 } 2488 checkContain2x2EntryCard(final File snapshotDirectory)2489 private void checkContain2x2EntryCard(final File snapshotDirectory) throws IOException, BundleException { 2490 if (!snapshotDirectory.exists()) { 2491 LOG.error("checkContain2x2EntryCard: file is not exist: " + snapshotDirectory.getName() + "."); 2492 throw new BundleException("checkContain2x2EntryCard: file is not exist."); 2493 } 2494 File[] files = snapshotDirectory.listFiles(); 2495 if (files == null) { 2496 LOG.error("checkContain2x2EntryCard: no file in this file path."); 2497 throw new BundleException("checkContain2x2EntryCard: no file in this file path."); 2498 } 2499 2500 for (File entryCardFile : files) { 2501 if (entryCardFile.isFile() && entryCardFile.getName().contains(PIC_2X2)) { 2502 return; 2503 } 2504 } 2505 mIsContain2x2EntryCard = false; 2506 LOG.error("checkContain2x2EntryCard: must contain 2x2 entryCard, please check it in " 2507 + snapshotDirectory.getCanonicalPath() + "."); 2508 throw new BundleException("checkContain2x2EntryCard: must contain 2x2 entryCard, please check it in " 2509 + snapshotDirectory.getCanonicalPath() + "."); 2510 } 2511 2512 /** 2513 * compress file or directory. 2514 * 2515 * @param utility common data 2516 * @param path create new file by path 2517 * @param baseDir base path for file 2518 * @param isCompression if need compression 2519 * @throws BundleException FileNotFoundException|IOException. 2520 */ pathToFile(Utility utility, String path, String baseDir, boolean isCompression)2521 private void pathToFile(Utility utility, String path, String baseDir, boolean isCompression) 2522 throws BundleException { 2523 if (path.isEmpty()) { 2524 return; 2525 } 2526 if (isCompression && LIBS_DIR_NAME.equals(baseDir)) { 2527 compressNativeLibsParallel(path, baseDir, utility.getCompressLevel()); 2528 return; 2529 } 2530 File fileItem = new File(path); 2531 if (fileItem.isDirectory()) { 2532 File[] files = fileItem.listFiles(); 2533 if (files == null) { 2534 return; 2535 } 2536 for (File file : files) { 2537 if (file.isDirectory()) { 2538 compressDirectory(utility, file, baseDir, isCompression); 2539 } else if (isCompression) { 2540 compressFile(utility, file, baseDir, isCompression); 2541 } else { 2542 compressFile(utility, file, baseDir, isCompression); 2543 } 2544 } 2545 } else { 2546 compressFile(utility, fileItem, baseDir, isCompression); 2547 } 2548 } 2549 compressNativeLibsParallel(String path, String baseDir, int compressLevel)2550 private void compressNativeLibsParallel(String path, String baseDir, int compressLevel) 2551 throws BundleException { 2552 try { 2553 int cores = Runtime.getRuntime().availableProcessors(); 2554 ThreadPoolExecutor executorService = new ThreadPoolExecutor(cores, cores, 60L, 2555 TimeUnit.SECONDS, new LinkedBlockingQueue<>()); 2556 ParallelScatterZipCreator zipCreator = new ParallelScatterZipCreator( 2557 executorService, new DefaultBackingStoreSupplier(null), compressLevel); 2558 File file = new File(path); 2559 if (file.isDirectory()) { 2560 File[] files = file.listFiles(); 2561 if (files == null) { 2562 return; 2563 } 2564 for (File f : files) { 2565 addArchiveEntry(f, baseDir, zipCreator); 2566 } 2567 } else { 2568 addArchiveEntry(file, baseDir, zipCreator); 2569 } 2570 zipCreator.writeTo(zipOut); 2571 } catch (IOException | InterruptedException | ExecutionException e) { 2572 LOG.error(PackingToolErrMsg.COMPRESS_PARALLEL_EXCEPTION.toString( 2573 "Parallel compress exist Exception (IOException | InterruptedException | ExecutionException): " + 2574 e.getMessage())); 2575 throw new BundleException("Parallel compress exception. " + e.getMessage()); 2576 } 2577 } 2578 addArchiveEntry(File file, String baseDir, ParallelScatterZipCreator zipCreator)2579 private void addArchiveEntry(File file, String baseDir, ParallelScatterZipCreator zipCreator) 2580 throws IOException { 2581 if (file.isDirectory()) { 2582 File[] files = file.listFiles(); 2583 if (files == null) { 2584 return; 2585 } 2586 for (File f : files) { 2587 addArchiveEntry(f, baseDir + file.getName() + File.separator, zipCreator); 2588 } 2589 } else { 2590 String entryName = (baseDir + file.getName()).replace(File.separator, LINUX_FILE_SEPARATOR); 2591 ZipArchiveEntry zipEntry = new ZipArchiveEntry(entryName); 2592 zipEntry.setMethod(ZipArchiveEntry.DEFLATED); 2593 InputStreamSupplier supplier = () -> { 2594 try { 2595 return Files.newInputStream(file.toPath()); 2596 } catch (IOException e) { 2597 LOG.error(PackingToolErrMsg.IO_EXCEPTION.toString( 2598 "Add archive entry exist IOException: " + e.getMessage())); 2599 return null; 2600 } 2601 }; 2602 zipCreator.addArchiveEntry(zipEntry, supplier); 2603 } 2604 } 2605 2606 /** 2607 * compress file or directory, res mode 2608 * 2609 * @param utility common data 2610 * @param path create new file by path 2611 * @param baseDir base path for file 2612 * @param isCompression if need compression 2613 * @throws BundleException FileNotFoundException|IOException. 2614 */ pathToFileResMode(Utility utility, String path, String baseDir, boolean isCompression)2615 private void pathToFileResMode(Utility utility, String path, String baseDir, boolean isCompression) 2616 throws BundleException { 2617 if (path.isEmpty()) { 2618 return; 2619 } 2620 File fileItem = new File(path); 2621 if (fileItem.isDirectory()) { 2622 File[] files = fileItem.listFiles(); 2623 if (files == null) { 2624 return; 2625 } 2626 for (File file : files) { 2627 if (!list.contains(file.getName())) { 2628 // moduleName not in pack.info 2629 continue; 2630 } 2631 if (file.isDirectory()) { 2632 compressDirectory(utility, file, baseDir, isCompression); 2633 } else if (isCompression) { 2634 compressFile(utility, file, baseDir, isCompression); 2635 } else { 2636 compressFile(utility, file, baseDir, isCompression); 2637 } 2638 } 2639 } else { 2640 compressFile(utility, fileItem, baseDir, isCompression); 2641 } 2642 } 2643 2644 /** 2645 * compress file directory. 2646 * 2647 * @param utility common data 2648 * @param dir file directory 2649 * @param baseDir current directory name 2650 * @param isCompression if need compression 2651 * @throws BundleException FileNotFoundException|IOException. 2652 */ compressDirectory(Utility utility, File dir, String baseDir, boolean isCompression)2653 private void compressDirectory(Utility utility, File dir, String baseDir, boolean isCompression) 2654 throws BundleException { 2655 File[] files = dir.listFiles(); 2656 if (files == null) { 2657 return; 2658 } 2659 for (File file : files) { 2660 if (file.isDirectory()) { 2661 compressDirectory(utility, file, baseDir + dir.getName() + File.separator, isCompression); 2662 } else { 2663 compressFile(utility, file, baseDir + dir.getName() + File.separator, isCompression); 2664 } 2665 } 2666 } 2667 2668 /** 2669 * compress pack.info 2670 * 2671 * @param sourceFile source 2672 * @param zipOutputStream ZipOutputStream 2673 * @param name filename 2674 * @param keepDirStructure Empty File 2675 */ compress(File sourceFile, ZipOutputStream zipOutputStream, String name, boolean keepDirStructure)2676 private void compress(File sourceFile, ZipOutputStream zipOutputStream, String name, boolean keepDirStructure) { 2677 FileInputStream in = null; 2678 try { 2679 byte[] buf = new byte[BUFFER_SIZE]; 2680 if (sourceFile.isFile()) { 2681 ZipEntry zipEntry = getStoredZipEntry(sourceFile, name); 2682 zipOutputStream.putNextEntry(zipEntry); 2683 in = new FileInputStream(sourceFile); 2684 int len; 2685 while ((len = in.read(buf)) != -1) { 2686 zipOutputStream.write(buf, 0, len); 2687 } 2688 zipOutputStream.closeEntry(); 2689 } else { 2690 File[] listFiles = sourceFile.listFiles(); 2691 if (listFiles == null || listFiles.length == 0) { 2692 if (keepDirStructure) { 2693 if (!name.isEmpty()) { 2694 ZipEntry zipEntry = getStoredZipEntry(sourceFile, name + "/"); 2695 zipOutputStream.putNextEntry(zipEntry); 2696 } else { 2697 ZipEntry zipEntry = getStoredZipEntry(sourceFile, name); 2698 zipOutputStream.putNextEntry(zipEntry); 2699 } 2700 zipOutputStream.closeEntry(); 2701 } 2702 } else { 2703 for (File file : listFiles) { 2704 if (keepDirStructure) { 2705 isNameEmpty(zipOutputStream, name, keepDirStructure, file); 2706 } else { 2707 compress(file, zipOutputStream, file.getName(), keepDirStructure); 2708 } 2709 } 2710 } 2711 } 2712 } catch (FileNotFoundException ignored) { 2713 LOG.error("Compressor::compressFile file not found exception."); 2714 } catch (IOException exception) { 2715 LOG.error("Compressor::compressFile io exception: " + exception.getMessage()); 2716 } catch (BundleException bundleException) { 2717 LOG.error("Compressor::compressFile bundle exception" + bundleException.getMessage()); 2718 } finally { 2719 Utility.closeStream(in); 2720 } 2721 } 2722 getStoredZipEntry(File sourceFile, String name)2723 private ZipEntry getStoredZipEntry(File sourceFile, String name) throws BundleException { 2724 ZipEntry zipEntry = new ZipEntry(name); 2725 zipEntry.setMethod(ZipEntry.STORED); 2726 zipEntry.setCompressedSize(sourceFile.length()); 2727 zipEntry.setSize(sourceFile.length()); 2728 CRC32 crc = getCrcFromFile(sourceFile); 2729 zipEntry.setCrc(crc.getValue()); 2730 return zipEntry; 2731 } 2732 getCrcFromFile(File file)2733 private CRC32 getCrcFromFile(File file) throws BundleException { 2734 FileInputStream fileInputStream = null; 2735 CRC32 crc = new CRC32(); 2736 try { 2737 fileInputStream = new FileInputStream(file); 2738 byte[] buffer = new byte[BUFFER_SIZE]; 2739 2740 int count = fileInputStream.read(buffer); 2741 while (count > 0) { 2742 crc.update(buffer, 0, count); 2743 count = fileInputStream.read(buffer); 2744 } 2745 } catch (FileNotFoundException ignored) { 2746 LOG.error(PackingToolErrMsg.FILE_NOT_FOUND.toString("File not found when getting Crc.")); 2747 throw new BundleException("Get Crc from file failed."); 2748 } catch (IOException exception) { 2749 LOG.error(PackingToolErrMsg.IO_EXCEPTION.toString( 2750 "Get Crc from file exist IOException: " + exception.getMessage())); 2751 throw new BundleException("Get Crc from file failed."); 2752 } finally { 2753 Utility.closeStream(fileInputStream); 2754 } 2755 return crc; 2756 } 2757 2758 /** 2759 * isNameEmpty 2760 * 2761 * @param zipOutputStream ZipOutputStream 2762 * @param name filename 2763 * @param keepDirStructure KeepDirStructure 2764 * @param file file 2765 */ isNameEmpty(ZipOutputStream zipOutputStream, String name, boolean keepDirStructure, File file)2766 private void isNameEmpty(ZipOutputStream zipOutputStream, String name, boolean keepDirStructure, File file) { 2767 if (!name.isEmpty()) { 2768 compress(file, zipOutputStream, name + "/" + file.getName(), keepDirStructure); 2769 } else { 2770 compress(file, zipOutputStream, file.getName(), keepDirStructure); 2771 } 2772 } 2773 2774 /** 2775 * compress process. 2776 * 2777 * @param utility common data 2778 * @param srcFile source file to zip 2779 * @param baseDir current directory name of file 2780 * @param isCompression if need compression 2781 * @throws BundleException FileNotFoundException|IOException. 2782 */ compressFile(Utility utility, File srcFile, String baseDir, boolean isCompression)2783 private void compressFile(Utility utility, File srcFile, String baseDir, boolean isCompression) 2784 throws BundleException { 2785 BufferedInputStream bufferedInputStream = null; 2786 FileInputStream fileInputStream = null; 2787 try { 2788 String entryName = (baseDir + srcFile.getName()).replace(File.separator, LINUX_FILE_SEPARATOR); 2789 ZipArchiveEntry zipEntry = new ZipArchiveEntry(entryName); 2790 isEntryOpen = true; 2791 if (!entryName.contains(RAW_FILE_PATH) 2792 && !entryName.contains(RES_FILE_PATH) 2793 && srcFile.getName().toLowerCase(Locale.ENGLISH).endsWith(JSON_SUFFIX) 2794 && !entryName.equals(Constants.FILE_ENCRYPT_JSON) 2795 && !entryName.equals(Constants.FILE_PAC_JSON)) { 2796 zipEntry.setMethod(ZipEntry.STORED); 2797 if (jsonSpecialProcess(utility, srcFile, zipEntry)) { 2798 return; 2799 } 2800 } 2801 2802 if (isCompression) { 2803 zipEntry.setMethod(ZipEntry.DEFLATED); 2804 } else { 2805 zipEntry.setMethod(ZipEntry.STORED); 2806 2807 // update size 2808 zipEntry.setCompressedSize(srcFile.length()); 2809 zipEntry.setSize(srcFile.length()); 2810 2811 // update crc 2812 CRC32 crc = getCrcFromFile(utility, srcFile); 2813 zipEntry.setCrc(crc.getValue()); 2814 } 2815 2816 zipOut.putArchiveEntry(zipEntry); 2817 byte[] data = new byte[BUFFER_SIZE]; 2818 fileInputStream = new FileInputStream(srcFile); 2819 bufferedInputStream = new BufferedInputStream(fileInputStream); 2820 2821 int count = bufferedInputStream.read(data); 2822 while (count > 0) { 2823 zipOut.write(data, 0, count); 2824 count = bufferedInputStream.read(data); 2825 } 2826 } catch (FileNotFoundException ignored) { 2827 throw new BundleException("CompressFile failed."); 2828 } catch (IOException exception) { 2829 LOG.error(PackingToolErrMsg.COMPRESS_FILE_EXCEPTION.toString( 2830 "IOException: " + exception.getMessage())); 2831 throw new BundleException("CompressFile failed."); 2832 } finally { 2833 Utility.closeStream(bufferedInputStream); 2834 Utility.closeStream(fileInputStream); 2835 } 2836 } 2837 2838 /** 2839 * check hap type for pack app. 2840 * 2841 * @param hapPath source file to zip 2842 * @return true is for is stage type and false is for FA type 2843 * @throws BundleException FileNotFoundException|IOException. 2844 */ isModuleHap(String hapPath)2845 public static boolean isModuleHap(String hapPath) throws BundleException { 2846 if (!hapPath.toLowerCase(Locale.ENGLISH).endsWith(HAP_SUFFIX)) { 2847 return true; 2848 } 2849 2850 FileInputStream zipInput = null; 2851 ZipInputStream zin = null; 2852 ZipEntry entry = null; 2853 try { 2854 zipInput = new FileInputStream(hapPath); 2855 zin = new ZipInputStream(zipInput); 2856 while ((entry = zin.getNextEntry()) != null) { 2857 if (MODULE_JSON.equals(entry.getName().toLowerCase())) { 2858 return true; 2859 } 2860 } 2861 } catch (IOException exception) { 2862 LOG.error(PackingToolErrMsg.FILE_IO_EXCEPTION.toString( 2863 "Check module type exist IOException: " + exception.getMessage())); 2864 throw new BundleException("Check module type for pack app failed."); 2865 } finally { 2866 Utility.closeStream(zipInput); 2867 Utility.closeStream(zin); 2868 } 2869 return false; 2870 } 2871 2872 /** 2873 * get CRC32 from file. 2874 * 2875 * @param utility common data 2876 * @param file source file 2877 * @return CRC32 2878 * @throws BundleException FileNotFoundException|IOException. 2879 */ getCrcFromFile(Utility utility, File file)2880 private CRC32 getCrcFromFile(Utility utility, File file) throws BundleException { 2881 FileInputStream fileInputStream = null; 2882 CRC32 crc = new CRC32(); 2883 try { 2884 fileInputStream = new FileInputStream(file); 2885 byte[] buffer = new byte[BUFFER_SIZE]; 2886 2887 int count = fileInputStream.read(buffer); 2888 while (count > 0) { 2889 crc.update(buffer, 0, count); 2890 count = fileInputStream.read(buffer); 2891 } 2892 } catch (FileNotFoundException ignored) { 2893 LOG.error(PackingToolErrMsg.FILE_NOT_FOUND.toString("File not found when getting Crc.")); 2894 throw new BundleException("Get Crc from file failed: " + file.getName()); 2895 } catch (IOException exception) { 2896 LOG.error(PackingToolErrMsg.FILE_IO_EXCEPTION.toString( 2897 "Get Crc32 from file exist IOException: " + exception.getMessage())); 2898 throw new BundleException("Get Crc from file failed."); 2899 } finally { 2900 Utility.closeStream(fileInputStream); 2901 } 2902 return crc; 2903 } 2904 parsePackInfoJsonFile(Utility utility, String jsonPath)2905 private void parsePackInfoJsonFile(Utility utility, String jsonPath) 2906 throws BundleException { 2907 try { 2908 String jsonString = FileUtils.getFileContent(jsonPath).get(); 2909 List<String> nameList = new ArrayList<>(); 2910 ModuleJsonUtil.parsePackInfoFormsName(jsonString, nameList, formNamesList); 2911 for (String formName : nameList) { 2912 if (formName.isEmpty()) { 2913 LOG.error(PackingToolErrMsg.PARSE_PACK_INFO_JSON_FAILED.toString("Form name parsed from " + 2914 "pack.info is empty.")); 2915 continue; 2916 } 2917 2918 utility.addFormNameList(formName); 2919 } 2920 } catch (JSONException e) { 2921 LOG.error(PackingToolErrMsg.PARSE_PACK_INFO_JSON_FAILED.toString("Parse pack.info eixst JSONException: " + 2922 e.getMessage())); 2923 } 2924 } 2925 infoSpecialProcess(Utility utility, File srcFile)2926 private void infoSpecialProcess(Utility utility, File srcFile) 2927 throws BundleException { 2928 FileInputStream fileInputStream = null; 2929 BufferedReader bufferedReader = null; 2930 InputStreamReader inputStreamReader = null; 2931 2932 try { 2933 fileInputStream = new FileInputStream(srcFile); 2934 inputStreamReader = new InputStreamReader(fileInputStream, StandardCharsets.UTF_8); 2935 bufferedReader = new BufferedReader(inputStreamReader); 2936 bufferedReader.mark((int) srcFile.length() + 1); 2937 // parse moduleName from pack.info 2938 parsePackModuleName(bufferedReader, utility); 2939 bufferedReader.reset(); 2940 parseDeviceType(bufferedReader, utility); 2941 bufferedReader.reset(); 2942 2943 Pattern pattern = Pattern.compile(System.lineSeparator()); 2944 String str = bufferedReader.readLine(); 2945 StringBuilder builder = new StringBuilder(); 2946 while (str != null) { 2947 Matcher matcher = pattern.matcher(str.trim()); 2948 String dest = matcher.replaceAll(""); 2949 builder.append(dest); 2950 str = bufferedReader.readLine(); 2951 } 2952 } catch (IOException exception) { 2953 LOG.error(PackingToolErrMsg.IO_EXCEPTION.toString("pack.info special process exist IOException: " 2954 + exception.getMessage())); 2955 throw new BundleException("Json special process failed."); 2956 } finally { 2957 Utility.closeStream(bufferedReader); 2958 Utility.closeStream(inputStreamReader); 2959 Utility.closeStream(fileInputStream); 2960 } 2961 } 2962 2963 /** 2964 * trim and remove "\r\n" in *.json file. 2965 * 2966 * @param utility common data 2967 * @param srcFile file input 2968 * @param entry zip file entry 2969 * @return true if process success 2970 */ jsonSpecialProcess(Utility utility, File srcFile, ZipArchiveEntry entry)2971 private boolean jsonSpecialProcess(Utility utility, File srcFile, ZipArchiveEntry entry) { 2972 FileInputStream fileInputStream = null; 2973 BufferedReader bufferedReader = null; 2974 InputStreamReader inputStreamReader = null; 2975 2976 try { 2977 fileInputStream = new FileInputStream(srcFile); 2978 inputStreamReader = new InputStreamReader(fileInputStream, StandardCharsets.UTF_8); 2979 bufferedReader = new BufferedReader(inputStreamReader); 2980 bufferedReader.mark((int) srcFile.length() + 1); 2981 bufferedReader.reset(); 2982 Optional<String> optional = FileUtils.getFileContent(utility.getJsonPath()); 2983 String jsonString = optional.get(); 2984 String jsonName = new File(utility.getJsonPath()).getName().toLowerCase(Locale.ENGLISH); 2985 if (CONFIG_JSON.equals(jsonName)) { 2986 parseCompressNativeLibs(bufferedReader, utility); 2987 utility.setModuleName(ModuleJsonUtil.parseFaModuleName(jsonString)); 2988 } else if (MODULE_JSON.equals(jsonName)) { 2989 utility.setIsCompressNativeLibs(ModuleJsonUtil.stageIsCompressNativeLibs(jsonString)); 2990 utility.setModuleName(ModuleJsonUtil.parseStageModuleName(jsonString)); 2991 } else if (PATCH_JSON.equals(jsonName)) { 2992 utility.setModuleName(ModuleJsonUtil.parsePatchModuleName(jsonString)); 2993 } 2994 bufferedReader.reset(); 2995 parseDeviceType(bufferedReader, utility); 2996 bufferedReader.reset(); 2997 2998 Pattern pattern = Pattern.compile(System.lineSeparator()); 2999 String str = bufferedReader.readLine(); 3000 StringBuilder builder = new StringBuilder(); 3001 while (str != null) { 3002 Matcher matcher = pattern.matcher(str.trim()); 3003 String dest = matcher.replaceAll(""); 3004 builder.append(dest); 3005 str = bufferedReader.readLine(); 3006 } 3007 Object jsonObject = JSON.parse(builder.toString()); 3008 byte[] trimJson = JSON.toJSONBytes(jsonObject, 3009 SerializerFeature.WriteMapNullValue, SerializerFeature.WriteDateUseDateFormat); 3010 3011 // update crc 3012 CRC32 crc = new CRC32(); 3013 crc.update(trimJson); 3014 entry.setCrc(crc.getValue()); 3015 3016 // update size 3017 entry.setSize(trimJson.length); 3018 entry.setCompressedSize(trimJson.length); 3019 3020 // compress data 3021 zipOut.putArchiveEntry(entry); 3022 zipOut.write(trimJson); 3023 } catch (Exception exception) { 3024 LOG.error(PackingToolErrMsg.JSON_SPECIAL_PROCESS_FAILED.toString("Exception: " + exception.getMessage())); 3025 LOG.warning("Json format err: " + srcFile.getAbsolutePath()); 3026 return false; 3027 } finally { 3028 Utility.closeStream(bufferedReader); 3029 Utility.closeStream(inputStreamReader); 3030 Utility.closeStream(fileInputStream); 3031 } 3032 return true; 3033 } 3034 3035 /** 3036 * Parse module name from pack.info 3037 * 3038 * @param bufferedReader pack.info buffered Reader 3039 * @param utility common data 3040 * @throws BundleException IOException 3041 */ parsePackModuleName(BufferedReader bufferedReader, Utility utility)3042 private void parsePackModuleName(BufferedReader bufferedReader, Utility utility) throws BundleException { 3043 String lineStr = null; 3044 try { 3045 while ((lineStr = bufferedReader.readLine()) != null) { 3046 if (lineStr.contains(DISTRO)) { 3047 continue; 3048 } 3049 if (lineStr.contains(JSON_END)) { 3050 continue; 3051 } 3052 if (lineStr.contains(MODULE_NAME_NEW) || lineStr.contains(MODULE_NAME)) { 3053 getModuleNameFromString(lineStr, utility); 3054 } 3055 } 3056 } catch (IOException exception) { 3057 LOG.error(PackingToolErrMsg.IO_EXCEPTION.toString("Parse module name exist IOException: " 3058 + exception.getMessage())); 3059 throw new BundleException("Parse module name failed."); 3060 } 3061 } 3062 3063 /** 3064 * Parse Forms name from pack.info 3065 * 3066 * @param bufferedReader pack.info buffered Reader 3067 * @param utility common data 3068 * @throws BundleException IOException 3069 */ parsePackFormName(BufferedReader bufferedReader, Utility utility)3070 private void parsePackFormName(BufferedReader bufferedReader, Utility utility) throws BundleException { 3071 String lineStr = null; 3072 try { 3073 while ((lineStr = bufferedReader.readLine()) != null) { 3074 if (lineStr.contains("abilities")) { 3075 continue; 3076 } 3077 if (lineStr.contains(FORMS)) { 3078 continue; 3079 } 3080 if (lineStr.contains(JSON_END)) { 3081 continue; 3082 } 3083 if (lineStr.contains(NAME)) { 3084 getNameFromString(lineStr, utility); 3085 } 3086 } 3087 } catch (IOException exception) { 3088 LOG.error("Compressor::parseModuleName io exception: " + exception.getMessage()); 3089 throw new BundleException("Parse module name failed."); 3090 } 3091 } 3092 3093 /** 3094 * Get name from line string 3095 * 3096 * @param lineStr line string 3097 * @param utility common data 3098 * @throws BundleException StringIndexOutOfBoundsException 3099 */ getNameFromString(String lineStr, Utility utility)3100 private void getNameFromString(String lineStr, Utility utility) throws BundleException { 3101 try { 3102 int endIndex = lineStr.lastIndexOf(SEMICOLON); 3103 if (endIndex <= 0) { 3104 LOG.error("Compressor::getModuleNameFromString field the json is not standard."); 3105 throw new BundleException("Parse module name failed, module-name is invalid."); 3106 } 3107 int startIndex = lineStr.lastIndexOf(SEMICOLON, endIndex - 1) + 1; 3108 String formName = lineStr.substring(startIndex, endIndex); 3109 if (formName == null || formName.isEmpty()) { 3110 LOG.error("Compressor::getModuleNameFromString field module-name is empty."); 3111 throw new BundleException("Parse module name failed, module-name is empty."); 3112 } 3113 String[] nameList = formName.split("\\."); 3114 if (nameList.length <= 1) { 3115 formNamesList.add(formName); 3116 utility.addFormNameList(formName); 3117 } 3118 } catch (StringIndexOutOfBoundsException exception) { 3119 LOG.error("Compressor::parseModuleName field module-name is fault: " + exception.getMessage()); 3120 throw new BundleException("Parse module name failed, module-name is invalid."); 3121 } 3122 } 3123 3124 /** 3125 * Get module name from line string 3126 * 3127 * @param lineStr line string 3128 * @param utility common data 3129 * @throws BundleException StringIndexOutOfBoundsException 3130 */ getModuleNameFromString(String lineStr, Utility utility)3131 private void getModuleNameFromString(String lineStr, Utility utility) throws BundleException { 3132 try { 3133 int endIndex = lineStr.lastIndexOf(SEMICOLON); 3134 if (endIndex <= 0) { 3135 LOG.error(PackingToolErrMsg.GET_MODULE_NAME_FROM_STRING_FAILED.toString("Unable to find '\"' " 3136 + "in the lineStr.")); 3137 throw new BundleException("Parse module name failed, module-name is invalid."); 3138 } 3139 int startIndex = lineStr.lastIndexOf(SEMICOLON, endIndex - 1) + 1; 3140 String moduleName = lineStr.substring(startIndex, endIndex); 3141 list.add(moduleName); 3142 if (moduleName == null || moduleName.isEmpty()) { 3143 LOG.error(PackingToolErrMsg.GET_MODULE_NAME_FROM_STRING_FAILED.toString("moduleName or module-name " 3144 + "is empty.")); 3145 throw new BundleException("Parse module name failed, module-name is empty."); 3146 } 3147 utility.setModuleName(moduleName); 3148 } catch (StringIndexOutOfBoundsException exception) { 3149 LOG.error(PackingToolErrMsg.GET_MODULE_NAME_FROM_STRING_FAILED.toString("Get Module name from line string " 3150 + "exist StringIndexOutOfBoundsException: " + exception.getMessage())); 3151 throw new BundleException("Parse module name failed, module-name is invalid."); 3152 } 3153 } 3154 parseCompressNativeLibs(BufferedReader bufferedReader, Utility utility)3155 private void parseCompressNativeLibs(BufferedReader bufferedReader, Utility utility) throws BundleException { 3156 String lineStr = null; 3157 try { 3158 while ((lineStr = bufferedReader.readLine()) != null) { 3159 if (lineStr.contains(COMPRESS_NATIVE_LIBS)) { 3160 if (lineStr.contains(Utility.TRUE_STRING)) { 3161 utility.setIsCompressNativeLibs(true); 3162 break; 3163 } 3164 } 3165 } 3166 } catch (IOException exception) { 3167 LOG.error(PackingToolErrMsg.IO_EXCEPTION.toString( 3168 "Parse compress native libs exist IOException: " + exception.getMessage())); 3169 throw new BundleException("Parse compress native libs failed."); 3170 } 3171 } 3172 3173 /** 3174 * ZipOutputStream flush, closeEntry and finish. 3175 */ closeZipOutputStream()3176 private void closeZipOutputStream() { 3177 try { 3178 if (zipOut != null) { 3179 zipOut.flush(); 3180 } 3181 } catch (IOException exception) { 3182 LOG.error(PackingToolErrMsg.CLOSE_ZIP_OUTPUT_STREAM_EXCEPTION.toString( 3183 "Close zip output stream flush IOException: " + exception.getMessage())); 3184 } 3185 try { 3186 if (zipOut != null && isEntryOpen) { 3187 zipOut.closeArchiveEntry(); 3188 } 3189 } catch (IOException exception) { 3190 LOG.error(PackingToolErrMsg.CLOSE_ZIP_OUTPUT_STREAM_EXCEPTION.toString( 3191 "Close entry IOException: " + exception.getMessage())); 3192 } 3193 try { 3194 if (zipOut != null) { 3195 zipOut.finish(); 3196 } 3197 } catch (IOException exception) { 3198 LOG.error(PackingToolErrMsg.CLOSE_ZIP_OUTPUT_STREAM_EXCEPTION.toString( 3199 "Close zip output stream flush IOException: " + exception.getMessage())); 3200 } 3201 } 3202 3203 /** 3204 * Parse device type from config.json 3205 * 3206 * @param bufferedReader config.json buffered Reader 3207 * @param utility common data 3208 * @throws BundleException IOException 3209 */ parseDeviceType(BufferedReader bufferedReader, Utility utility)3210 private void parseDeviceType(BufferedReader bufferedReader, Utility utility) throws BundleException { 3211 String lineStr = null; 3212 boolean isDeviceTypeStart = false; 3213 try { 3214 while ((lineStr = bufferedReader.readLine()) != null) { 3215 if (!isDeviceTypeStart) { 3216 if (lineStr.contains(DEVICE_TYPE)) { 3217 isDeviceTypeStart = true; 3218 } 3219 continue; 3220 } 3221 if (lineStr.contains(JSON_END)) { 3222 break; 3223 } 3224 utility.setDeviceType(lineStr); 3225 break; 3226 } 3227 } catch (IOException exception) { 3228 LOG.error(PackingToolErrMsg.IO_EXCEPTION.toString( 3229 "Parse device type exist IOException: " + exception.getMessage())); 3230 throw new BundleException("Parse device type failed."); 3231 } 3232 } 3233 3234 /** 3235 * check hap and hsp is valid in haps when pack app, check type has bundleName, 3236 * vendor, version, apiVersion moduleName, packageName. 3237 * 3238 * @param fileLists is the list of hapPath. 3239 * @return true is for successful and false is for failed 3240 * @throws BundleException FileNotFoundException|IOException. 3241 */ checkHapIsValid(List<String> fileLists, boolean isSharedApp)3242 private boolean checkHapIsValid(List<String> fileLists, boolean isSharedApp) throws BundleException { 3243 List<HapVerifyInfo> hapVerifyInfos = new ArrayList<>(); 3244 for (String hapPath : fileLists) { 3245 if (hapPath.isEmpty()) { 3246 LOG.error(PackingToolErrMsg.INVALID_HAP_FILE.toString("Invalid hap or hsp file input.")); 3247 throw new BundleException("The hap or hsp files are invalid, or the wrong file was provided."); 3248 } 3249 File srcFile = new File(hapPath); 3250 String fileStr = srcFile.getName(); 3251 if (fileStr.isEmpty()) { 3252 LOG.error(PackingToolErrMsg.INVALID_HAP_FILE.toString("Get file name failed.")); 3253 throw new BundleException("Get file name from the provided path failed."); 3254 } 3255 if (!fileStr.toLowerCase(Locale.ENGLISH).endsWith(HAP_SUFFIX) 3256 && !fileStr.toLowerCase(Locale.ENGLISH).endsWith(HSP_SUFFIX)) { 3257 LOG.error(PackingToolErrMsg.INVALID_HAP_FILE.toString("Invalid hap or hsp file input.")); 3258 throw new BundleException("The provided file is not a valid hap or hsp file."); 3259 } 3260 if (isModuleHap(hapPath)) { 3261 hapVerifyInfos.add(parseStageHapVerifyInfo(hapPath)); 3262 } else { 3263 hapVerifyInfos.add(parseFAHapVerifyInfo(hapPath)); 3264 } 3265 3266 if (!hapVerifyInfos.isEmpty()) { 3267 hapVerifyInfoMap.put(getFileNameByPath(hapPath), hapVerifyInfos.get(hapVerifyInfos.size() - 1)); 3268 } 3269 } 3270 3271 if (isSharedApp) { 3272 boolean res = checkSharedAppIsValid(hapVerifyInfos); 3273 if (!res) { 3274 return false; 3275 } 3276 if (!isOverlay) { 3277 return true; 3278 } 3279 } else { 3280 for (HapVerifyInfo hapVerifyInfo : hapVerifyInfos) { 3281 String bundleType = hapVerifyInfo.getBundleType(); 3282 if (TYPE_SHARED.equals(bundleType)) { 3283 String cause = "Only one item can be entered in the --hsp-path when bundleType is shared."; 3284 String solution = "Ensure that only one item entered in the --hsp-path when bundleType is shared."; 3285 LOG.error(PackingToolErrMsg.CHECK_BUNDLETYPE_INVALID.toString(cause, solution)); 3286 return false; 3287 } 3288 } 3289 } 3290 setAtomicServiceFileSizeLimit(hapVerifyInfos); 3291 if (!HapVerify.checkHapIsValid(hapVerifyInfos)) { 3292 return false; 3293 } 3294 return true; 3295 } 3296 3297 /** 3298 * parse stage file to hap verify info from hap path. 3299 * 3300 * @param filePath is the hap path 3301 * @return hapVerifyInfo 3302 */ parseStageHapVerifyInfo(String filePath)3303 public static HapVerifyInfo parseStageHapVerifyInfo(String filePath) throws BundleException { 3304 HapVerifyInfo hapVerifyInfo = readStageHapVerifyInfo(filePath); 3305 hapVerifyInfo.setStageModule(true); 3306 ModuleJsonUtil.parseStageHapVerifyInfo(hapVerifyInfo); 3307 hapVerifyInfo.setFileLength(FileUtils.getFileSize(filePath)); 3308 File srcFile = new File(filePath); 3309 String fileStr = srcFile.getName(); 3310 if (fileStr.toLowerCase(Locale.ENGLISH).endsWith(HAP_SUFFIX)) { 3311 hapVerifyInfo.setFileType(HAP_SUFFIX); 3312 } else if (fileStr.toLowerCase(Locale.ENGLISH).endsWith(HSP_SUFFIX)) { 3313 hapVerifyInfo.setFileType(HSP_SUFFIX); 3314 } 3315 return hapVerifyInfo; 3316 } 3317 3318 /** 3319 * set file size limit for each HapVerifyInfo. 3320 * 3321 * @param hapVerifyInfos Indicates hapVerifyInfo list. 3322 */ setAtomicServiceFileSizeLimit(List<HapVerifyInfo>hapVerifyInfos)3323 public static void setAtomicServiceFileSizeLimit(List<HapVerifyInfo>hapVerifyInfos) { 3324 for (HapVerifyInfo hapVerifyInfo : hapVerifyInfos) { 3325 if (!hapVerifyInfo.getBundleType().equals(ATOMIC_SERVICE)) { 3326 continue; 3327 } 3328 hapVerifyInfo.setEntrySizeLimit(getEntryModuleSizeLimit()); 3329 hapVerifyInfo.setNotEntrySizeLimit(getNotEntryModuleSizeLimit()); 3330 hapVerifyInfo.setSumSizeLimit(getSumModuleSizeLimit()); 3331 } 3332 } 3333 3334 /** 3335 * parse fa file to hap verify info from hap path. 3336 * 3337 * @param filePath is the hap path 3338 * @return hapVerifyInfo 3339 */ parseFAHapVerifyInfo(String filePath)3340 public static HapVerifyInfo parseFAHapVerifyInfo(String filePath) throws BundleException { 3341 HapVerifyInfo hapVerifyInfo = readFAHapVerifyInfo(filePath); 3342 hapVerifyInfo.setStageModule(false); 3343 hapVerifyInfo.setFileLength(FileUtils.getFileSize(filePath)); 3344 ModuleJsonUtil.parseFAHapVerifyInfo(hapVerifyInfo); 3345 return hapVerifyInfo; 3346 } 3347 3348 /** 3349 * read stage hap verify info from hap file. 3350 * 3351 * @param srcPath source file to zip 3352 * @return HapVerifyInfo of parse result 3353 * @throws BundleException FileNotFoundException|IOException. 3354 */ readStageHapVerifyInfo(String srcPath)3355 public static HapVerifyInfo readStageHapVerifyInfo(String srcPath) throws BundleException { 3356 HapVerifyInfo hapVerifyInfo = new HapVerifyInfo(); 3357 ZipFile zipFile = null; 3358 try { 3359 File srcFile = new File(srcPath); 3360 zipFile = new ZipFile(srcFile); 3361 hapVerifyInfo.setResourceMap(FileUtils.getProfileJson(zipFile)); 3362 hapVerifyInfo.setProfileStr(FileUtils.getFileStringFromZip(MODULE_JSON, zipFile)); 3363 } catch (IOException e) { 3364 LOG.error(PackingToolErrMsg.READ_STAGE_HAP_VERIFY_INFO_FAILED.toString( 3365 "Read Stage hap verify info file exist IOException: " + e.getMessage())); 3366 throw new BundleException("Parse Stage hap verify info file exist IOException."); 3367 } finally { 3368 Utility.closeStream(zipFile); 3369 } 3370 return hapVerifyInfo; 3371 } 3372 3373 /** 3374 * read fa hap verify info from hap file. 3375 * 3376 * @param srcPath source file to zip 3377 * @return HapVerifyInfo of parse result 3378 * @throws BundleException FileNotFoundException|IOException. 3379 */ readFAHapVerifyInfo(String srcPath)3380 public static HapVerifyInfo readFAHapVerifyInfo(String srcPath) throws BundleException { 3381 HapVerifyInfo hapVerifyInfo = new HapVerifyInfo(); 3382 ZipFile zipFile = null; 3383 try { 3384 File srcFile = new File(srcPath); 3385 zipFile = new ZipFile(srcFile); 3386 hapVerifyInfo.setProfileStr(FileUtils.getFileStringFromZip(CONFIG_JSON, zipFile)); 3387 } catch (IOException e) { 3388 LOG.error(PackingToolErrMsg.READ_FA_HAP_VERIFY_INFO_FAILED.toString( 3389 "Read FA hap verify info file exist IOException: " + e.getMessage())); 3390 throw new BundleException("Parse FA hap verify info file exist IOException."); 3391 } finally { 3392 Utility.closeStream(zipFile); 3393 } 3394 return hapVerifyInfo; 3395 } 3396 3397 /** 3398 * compress in hqf mode. 3399 * 3400 * @param utility common data 3401 * @throws BundleException FileNotFoundException|IOException. 3402 */ compressHQFMode(Utility utility)3403 private void compressHQFMode(Utility utility) throws BundleException { 3404 pathToFile(utility, utility.getJsonPath(), NULL_DIR_NAME, false); 3405 3406 if (!utility.getEtsPath().isEmpty()) { 3407 pathToFile(utility, utility.getEtsPath(), ETS_PATH, false); 3408 } 3409 if (!utility.getLibPath().isEmpty()) { 3410 pathToFile(utility, utility.getLibPath(), LIBS_DIR_NAME, false); 3411 } 3412 if (!utility.getResourcesPath().isEmpty()) { 3413 pathToFile(utility, utility.getResourcesPath(), RESOURCES_DIR_NAME, false); 3414 } 3415 } 3416 3417 /** 3418 * compress in appqf mode. 3419 * 3420 * @param utility common data 3421 * @throws BundleException FileNotFoundException|IOException. 3422 */ compressAPPQFMode(Utility utility)3423 private void compressAPPQFMode(Utility utility) throws BundleException { 3424 List<String> fileList = utility.getFormatedHQFList(); 3425 if (!checkHQFIsValid(fileList)) { 3426 LOG.error(PackingToolErrMsg.COMPRESS_APPQF_FAILED.toString("Verify failed when compress appqf.")); 3427 throw new BundleException("Verify failed when compress appqf."); 3428 } 3429 for (String hapPath : fileList) { 3430 pathToFile(utility, hapPath, NULL_DIR_NAME, false); 3431 } 3432 } 3433 3434 /** 3435 * check input hqf is valid. 3436 * 3437 * @param fileList is input path of hqf files 3438 * @throws BundleException FileNotFoundException|IOException. 3439 */ checkHQFIsValid(List<String> fileList)3440 private boolean checkHQFIsValid(List<String> fileList) throws BundleException { 3441 List<HQFInfo> hqfVerifyInfos = new ArrayList<>(); 3442 for (String file : fileList) { 3443 hqfVerifyInfos.add(ModuleJsonUtil.parseHQFInfo(file)); 3444 } 3445 if (!HQFVerify.checkHQFIsValid(hqfVerifyInfos)) { 3446 LOG.error(PackingToolErrMsg.CHECK_HQF_INVALID.toString("Input hqf is invalid.")); 3447 return false; 3448 } 3449 return true; 3450 } 3451 compressHSPMode(Utility utility)3452 private void compressHSPMode(Utility utility) throws BundleException { 3453 pathToFile(utility, utility.getJsonPath(), NULL_DIR_NAME, false); 3454 3455 pathToFile(utility, utility.getProfilePath(), NULL_DIR_NAME, false); 3456 3457 if (!utility.getIndexPath().isEmpty() && isModuleJSON(utility.getJsonPath())) { 3458 String assetsPath = NULL_DIR_NAME; 3459 pathToFile(utility, utility.getIndexPath(), assetsPath, false); 3460 } 3461 3462 if (!utility.getLibPath().isEmpty()) { 3463 pathToFile(utility, utility.getLibPath(), LIBS_DIR_NAME, utility.isCompressNativeLibs()); 3464 } 3465 3466 if (!utility.getANPath().isEmpty()) { 3467 pathToFile(utility, utility.getANPath(), AN_DIR_NAME, false); 3468 } 3469 3470 if (!utility.getAPPath().isEmpty()) { 3471 pathToFile(utility, utility.getAPPath(), AP_PATH_NAME, false); 3472 } 3473 3474 if (!utility.getFilePath().isEmpty()) { 3475 pathToFile(utility, utility.getFilePath(), NULL_DIR_NAME, false); 3476 } 3477 3478 if (!utility.getResPath().isEmpty() && !utility.getModuleName().isEmpty()) { 3479 String resPath = ASSETS_DIR_NAME + utility.getModuleName() + LINUX_FILE_SEPARATOR 3480 + RESOURCES_DIR_NAME; 3481 if (DEVICE_TYPE_FITNESSWATCH.equals( 3482 utility.getDeviceType().replace(SEMICOLON, EMPTY_STRING).trim()) || 3483 DEVICE_TYPE_FITNESSWATCH_NEW.equals( 3484 utility.getDeviceType().replace(SEMICOLON, EMPTY_STRING).trim())) { 3485 resPath = RES_DIR_NAME; 3486 } 3487 pathToFile(utility, utility.getResPath(), resPath, false); 3488 } 3489 3490 if (!utility.getResourcesPath().isEmpty() && isModuleJSON(utility.getJsonPath())) { 3491 String resourcesPath = RESOURCES_DIR_NAME; 3492 pathToFile(utility, utility.getResourcesPath(), resourcesPath, false); 3493 } 3494 if (!utility.getJsPath().isEmpty() && isModuleJSON(utility.getJsonPath())) { 3495 String jsPath = JS_PATH; 3496 pathToFile(utility, utility.getJsPath(), jsPath, false); 3497 } 3498 3499 if (!utility.getEtsPath().isEmpty() && isModuleJSON(utility.getJsonPath())) { 3500 String etsPath = ETS_PATH; 3501 pathToFile(utility, utility.getEtsPath(), etsPath, false); 3502 } 3503 3504 if (!utility.getRpcidPath().isEmpty()) { 3505 String rpcidPath = NULL_DIR_NAME; 3506 pathToFile(utility, utility.getRpcidPath(), rpcidPath, false); 3507 } 3508 3509 if (!utility.getAssetsPath().isEmpty()) { 3510 pathToFile(utility, utility.getAssetsPath(), ASSETS_DIR_NAME, false); 3511 } 3512 3513 if (!utility.getBinPath().isEmpty()) { 3514 pathToFile(utility, utility.getBinPath(), NULL_DIR_NAME, false); 3515 } 3516 3517 if (!utility.getPackInfoPath().isEmpty()) { 3518 pathToFile(utility, utility.getPackInfoPath(), NULL_DIR_NAME, false); 3519 } 3520 3521 // pack --dir-list 3522 if (!utility.getFormatedDirList().isEmpty()) { 3523 for (int i = 0; i < utility.getFormatedDirList().size(); ++i) { 3524 String baseDir = new File(utility.getFormatedDirList().get(i)).getName() + File.separator; 3525 pathToFile(utility, utility.getFormatedDirList().get(i), baseDir, false); 3526 } 3527 } 3528 if (!utility.getPkgContextPath().isEmpty()) { 3529 pathToFile(utility, utility.getPkgContextPath(), NULL_DIR_NAME, false); 3530 } 3531 3532 compressHapModeMultiple(utility); 3533 } 3534 checkSharedAppIsValid(List<HapVerifyInfo> hapVerifyInfos)3535 private static boolean checkSharedAppIsValid(List<HapVerifyInfo> hapVerifyInfos) throws BundleException { 3536 if (hapVerifyInfos.isEmpty()) { 3537 String cause = "Hap verify infos is empty."; 3538 LOG.error(PackingToolErrMsg.CHECK_HAP_VERIFY_INFO_LIST_EMPTY.toString(cause)); 3539 return false; 3540 } 3541 if (hapVerifyInfos.size() > SHARED_APP_HSP_LIMIT) { 3542 String cause = "The shared App only can contain one module."; 3543 String solution = "Please ensure that there is only one module in the shared App."; 3544 LOG.error(PackingToolErrMsg.CHECK_SHARED_APP_INVALID.toString(cause, solution)); 3545 return false; 3546 } 3547 for (HapVerifyInfo hapVerifyInfo : hapVerifyInfos) { 3548 if (!hapVerifyInfo.getTargetBundleName().isEmpty()) { 3549 isOverlay = true; 3550 return true; 3551 } 3552 } 3553 return HapVerify.checkSharedApppIsValid(hapVerifyInfos); 3554 } 3555 versionNormalize(Utility utility)3556 private void versionNormalize(Utility utility) { 3557 List<VersionNormalizeUtil> utils = new ArrayList<>(); 3558 Path tempDir = null; 3559 for (String hapPath : utility.getFormattedHapList()) { 3560 try { 3561 tempDir = Files.createTempDirectory(Paths.get(utility.getOutPath()), "temp"); 3562 3563 unpackHap(hapPath, tempDir.toAbsolutePath().toString()); 3564 VersionNormalizeUtil util = new VersionNormalizeUtil(); 3565 File moduleFile = new File( 3566 tempDir.toAbsolutePath() + LINUX_FILE_SEPARATOR + MODULE_JSON); 3567 File configFile = new File( 3568 tempDir.toAbsolutePath() + LINUX_FILE_SEPARATOR + CONFIG_JSON); 3569 File packInfoFile = new File( 3570 tempDir.toAbsolutePath() + LINUX_FILE_SEPARATOR + PACKINFO_NAME); 3571 3572 if (moduleFile.exists() && configFile.exists()) { 3573 LOG.error(PackingToolErrMsg.VERSION_NORMALIZE_FAILED.toString("Invalid hap structure.")); 3574 throw new BundleException("versionNormalize failed, invalid hap structure."); 3575 } 3576 if (moduleFile.exists()) { 3577 String moduleJsonPath = tempDir.resolve(MODULE_JSON).toString(); 3578 util = parseAndModifyModuleJson(moduleJsonPath, utility); 3579 } else if (configFile.exists()) { 3580 String configJsonPath = tempDir.resolve(CONFIG_JSON).toString(); 3581 util = parseAndModifyConfigJson(configJsonPath, utility); 3582 } else { 3583 LOG.error(PackingToolErrMsg.VERSION_NORMALIZE_FAILED.toString("Invalid hap structure.")); 3584 throw new BundleException("versionNormalize failed, invalid hap structure."); 3585 } 3586 if (packInfoFile.exists()) { 3587 String packInfoPath = tempDir.resolve(PACKINFO_NAME).toString(); 3588 parseAndModifyPackInfo(packInfoPath, utility); 3589 } 3590 3591 verifyModuleVersion(util, utility); 3592 utils.add(util); 3593 3594 String modifiedHapPath = Paths.get(utility.getOutPath()) + 3595 LINUX_FILE_SEPARATOR + Paths.get(hapPath).getFileName().toString(); 3596 compressDirToHap(tempDir, modifiedHapPath); 3597 } catch (IOException | BundleException e) { 3598 LOG.error(PackingToolErrMsg.VERSION_NORMALIZE_FAILED.toString( 3599 "Version normalize exist Exception (IOException | BundleException): " + e.getMessage())); 3600 } finally { 3601 if (tempDir != null) { 3602 deleteDirectory(tempDir.toFile()); 3603 } 3604 } 3605 } 3606 writeVersionRecord(utils, utility.getOutPath()); 3607 } 3608 parseAndModifyModuleJson(String jsonFilePath, Utility utility)3609 private VersionNormalizeUtil parseAndModifyModuleJson(String jsonFilePath, Utility utility) 3610 throws BundleException { 3611 VersionNormalizeUtil util = new VersionNormalizeUtil(); 3612 try (FileInputStream jsonStream = new FileInputStream(jsonFilePath)) { 3613 JSONObject jsonObject = JSON.parseObject(jsonStream, JSONObject.class); 3614 if (!jsonObject.containsKey(APP)) { 3615 LOG.error(PackingToolErrMsg.PARSE_AND_MODIFY_MODULEJSON_FAILED.toString("The module.json file " + 3616 "does not contain 'app'.")); 3617 throw new BundleException("The module.json file does not contain 'app'. "); 3618 } 3619 JSONObject appObject = jsonObject.getJSONObject(APP); 3620 if (!appObject.containsKey(VERSION_CODE)) { 3621 LOG.error(PackingToolErrMsg.PARSE_AND_MODIFY_MODULEJSON_FAILED.toString("The app object of " + 3622 "module.json file does not contain 'versionCode'.")); 3623 throw new BundleException("The app object of module.json file does not contain 'versionCode'."); 3624 } 3625 if (!appObject.containsKey(VERSION_NAME)) { 3626 LOG.error(PackingToolErrMsg.PARSE_AND_MODIFY_MODULEJSON_FAILED.toString("The app object of " + 3627 "module.json file does not contain 'versionName'.")); 3628 throw new BundleException("The app object of module.json file does not contain 'versionName'."); 3629 } 3630 util.setOriginVersionCode(appObject.getIntValue(VERSION_CODE)); 3631 util.setOriginVersionName(appObject.getString(VERSION_NAME)); 3632 3633 JSONObject moduleObject = jsonObject.getJSONObject(MODULE); 3634 if (!moduleObject.containsKey(NAME)) { 3635 LOG.error(PackingToolErrMsg.PARSE_AND_MODIFY_MODULEJSON_FAILED.toString("The module object of " + 3636 "module.json file does not contain 'name'.")); 3637 throw new BundleException("The module object of module.json file does not contain 'name'. "); 3638 } 3639 util.setModuleName(moduleObject.getString(NAME)); 3640 appObject.put(VERSION_CODE, utility.getVersionCode()); 3641 appObject.put(VERSION_NAME, utility.getVersionName()); 3642 writeJson(jsonFilePath, jsonObject); 3643 } catch (IOException e) { 3644 LOG.error(PackingToolErrMsg.IO_EXCEPTION.toString("Parse and modify module.json exist IOException: " + 3645 e.getMessage())); 3646 throw new BundleException("Parse and modify module.json exist IOException: " + e.getMessage()); 3647 } 3648 return util; 3649 } 3650 parseAndModifyPackInfo(String packInfoPath, Utility utility)3651 private void parseAndModifyPackInfo(String packInfoPath, Utility utility) 3652 throws BundleException { 3653 try (FileInputStream jsonStream = new FileInputStream(packInfoPath)) { 3654 JSONObject jsonObject = JSON.parseObject(jsonStream, JSONObject.class); 3655 if (jsonObject == null) { 3656 LOG.warning("parseAndModifyPackInfo failed, json format invalid."); 3657 return; 3658 } 3659 JSONObject summaryObject = jsonObject.getJSONObject(SUMMARY); 3660 if (summaryObject == null) { 3661 LOG.warning("parseAndModifyPackInfo failed, summary invalid."); 3662 return; 3663 } 3664 JSONObject appObject = summaryObject.getJSONObject(APP); 3665 if (appObject == null) { 3666 LOG.warning("parseAndModifyPackInfo failed, app invalid."); 3667 return; 3668 } 3669 JSONObject versionObject = appObject.getJSONObject(VERSION); 3670 if (versionObject == null) { 3671 LOG.warning("parseAndModifyPackInfo failed, version invalid."); 3672 return; 3673 } 3674 versionObject.put(CODE, utility.getVersionCode()); 3675 versionObject.put(NAME, utility.getVersionName()); 3676 writeJson(packInfoPath, jsonObject); 3677 } catch (IOException e) { 3678 LOG.warning("parseAndModifyPackInfo failed, IOException." + e.getMessage()); 3679 } 3680 } 3681 writeJson(String jsonFilePath, JSONObject jsonObject)3682 private void writeJson(String jsonFilePath, JSONObject jsonObject) throws IOException, BundleException { 3683 BufferedWriter bw = null; 3684 try { 3685 String pretty = JSON.toJSONString(jsonObject, SerializerFeature.WriteMapNullValue, 3686 SerializerFeature.WriteDateUseDateFormat); 3687 bw = new BufferedWriter(new OutputStreamWriter( 3688 new FileOutputStream(jsonFilePath), StandardCharsets.UTF_8)); 3689 bw.write(pretty); 3690 } catch (IOException exception) { 3691 LOG.error(PackingToolErrMsg.IO_EXCEPTION.toString("Write json exist IOException: " 3692 + exception.getMessage())); 3693 throw new BundleException("Compressor::writeJson failed for IOException"); 3694 } finally { 3695 if (bw != null) { 3696 bw.flush(); 3697 bw.close(); 3698 } 3699 } 3700 } 3701 parseAndModifyConfigJson(String jsonFilePath, Utility utility)3702 private VersionNormalizeUtil parseAndModifyConfigJson(String jsonFilePath, Utility utility) 3703 throws BundleException { 3704 VersionNormalizeUtil util = new VersionNormalizeUtil(); 3705 try (FileInputStream jsonStream = new FileInputStream(jsonFilePath)) { 3706 JSONObject jsonObject = JSON.parseObject(jsonStream, JSONObject.class); 3707 if (!jsonObject.containsKey(APP)) { 3708 LOG.error(PackingToolErrMsg.PARSE_MODIFY_CONFIG_JSON_FAILED.toString("The config.json file " + 3709 "does not contain 'app'.")); 3710 throw new BundleException("The config.json file does not contain 'app'. "); 3711 } 3712 JSONObject appObject = jsonObject.getJSONObject(APP); 3713 if (!appObject.containsKey(VERSION)) { 3714 LOG.error(PackingToolErrMsg.PARSE_MODIFY_CONFIG_JSON_FAILED.toString("The app object of config.json " + 3715 "file does not contain 'version'.")); 3716 throw new BundleException("The app object of config.json file does not contain 'version'. "); 3717 } 3718 JSONObject versionObj = appObject.getJSONObject(VERSION); 3719 if (!versionObj.containsKey(CODE)) { 3720 LOG.error(PackingToolErrMsg.PARSE_MODIFY_CONFIG_JSON_FAILED.toString("The version object of " + 3721 "config.json file does not contain 'code'.")); 3722 throw new BundleException("The version object of config.json file does not contain 'code'. "); 3723 } 3724 util.setOriginVersionCode(versionObj.getIntValue(CODE)); 3725 if (!versionObj.containsKey(NAME)) { 3726 LOG.error(PackingToolErrMsg.PARSE_MODIFY_CONFIG_JSON_FAILED.toString("The version object of " + 3727 "config.json file does not contain 'name'.")); 3728 throw new BundleException("The version object of config.json file does not contain 'name'. "); 3729 } 3730 util.setOriginVersionName(versionObj.getString(NAME)); 3731 3732 JSONObject moduleObject = jsonObject.getJSONObject(MODULE); 3733 if (!moduleObject.containsKey(NAME)) { 3734 LOG.error(PackingToolErrMsg.PARSE_MODIFY_CONFIG_JSON_FAILED.toString("The module object of " + 3735 "config.json file does not contain 'name'.")); 3736 throw new BundleException("The module object of config.json file does not contain 'name'. "); 3737 } 3738 util.setModuleName(moduleObject.getString(NAME)); 3739 3740 versionObj.put(CODE, utility.getVersionCode()); 3741 versionObj.put(NAME, utility.getVersionName()); 3742 writeJson(jsonFilePath, jsonObject); 3743 } catch (IOException e) { 3744 LOG.error(PackingToolErrMsg.IO_EXCEPTION.toString("Parse and modify config.json exist IOException: " 3745 + e.getMessage())); 3746 throw new BundleException("Parse and modify config.json exist IOException: " + e.getMessage()); 3747 } 3748 return util; 3749 } 3750 compressDirToHap(Path sourceDir, String zipFilePath)3751 private boolean compressDirToHap(Path sourceDir, String zipFilePath) 3752 throws IOException, BundleException { 3753 Utility utility = new Utility(); 3754 utility.setOutPath(zipFilePath); 3755 if (zipFilePath.endsWith(HAP_SUFFIX)) { 3756 utility.setMode(Utility.MODE_HAP); 3757 } else if (zipFilePath.endsWith(HSP_SUFFIX)) { 3758 utility.setMode(Utility.MODE_HSP); 3759 } 3760 try (Stream<Path> pathStream = Files.walk(sourceDir, 1)) { 3761 pathStream.forEach(path -> { 3762 String fileName = path.getFileName().toString(); 3763 String filePath = path.toString(); 3764 3765 switch (fileName) { 3766 case ETS_FILE_NAME: 3767 utility.setEtsPath(filePath); 3768 break; 3769 case HNP_FILE_NAME: 3770 utility.setHnpPath(filePath); 3771 break; 3772 case LIBS_DIR: 3773 utility.setLibPath(filePath); 3774 break; 3775 case AN_FILE_NAME: 3776 utility.setANPath(filePath); 3777 break; 3778 case AP_FILE_NAME: 3779 utility.setAPPath(filePath); 3780 break; 3781 case RESOURCE_FILE_NAME: 3782 utility.setResourcesPath(filePath); 3783 break; 3784 case JS_FILE_NAME: 3785 utility.setJsPath(filePath); 3786 break; 3787 case ASSETS_FILE_NAME: 3788 utility.setAssetsPath(filePath); 3789 break; 3790 case MAPLE_FILE_NAME: 3791 utility.setSoDir(filePath); 3792 break; 3793 case SHARED_LIBS_FILE_NAME: 3794 utility.setSharedLibsPath(filePath); 3795 break; 3796 case CONFIG_JSON: 3797 utility.setJsonPath(filePath); 3798 break; 3799 case MODULE_JSON: 3800 utility.setJsonPath(filePath); 3801 break; 3802 case RES_INDEX: 3803 utility.setIndexPath(filePath); 3804 break; 3805 case PACKINFO_NAME: 3806 utility.setPackInfoPath(filePath); 3807 break; 3808 case RPCID: 3809 utility.setRpcid(filePath); 3810 break; 3811 case PKG_CONTEXT_INFO: 3812 utility.setPkgContextPath(filePath); 3813 break; 3814 } 3815 }); 3816 } 3817 return compressProcess(utility); 3818 } 3819 deleteDirectory(File dir)3820 private static void deleteDirectory(File dir) { 3821 if (dir.isDirectory()) { 3822 File[] children = dir.listFiles(); 3823 if (children != null) { 3824 for (File child : children) { 3825 deleteDirectory(child); 3826 } 3827 } 3828 } 3829 dir.delete(); 3830 } 3831 writeVersionRecord(List<VersionNormalizeUtil> utils, String outPath)3832 private static void writeVersionRecord(List<VersionNormalizeUtil> utils, String outPath) { 3833 String jsonString = JSON.toJSONString(utils); 3834 try (FileWriter fileWriter = new FileWriter(outPath + LINUX_FILE_SEPARATOR + VERSION_RECORD)) { 3835 fileWriter.write(jsonString); 3836 } catch (IOException e) { 3837 LOG.error(PackingToolErrMsg.IO_EXCEPTION.toString("Write version record exist IOException: " 3838 + e.getMessage())); 3839 } 3840 } 3841 verifyModuleVersion(VersionNormalizeUtil versionNormalizeUtil, Utility utility)3842 private static void verifyModuleVersion(VersionNormalizeUtil versionNormalizeUtil, Utility utility) 3843 throws BundleException { 3844 if (versionNormalizeUtil.getOriginVersionCode() > utility.getVersionCode()) { 3845 String errorMsg = "Input version code less than module " + versionNormalizeUtil.getModuleName() 3846 + " version code."; 3847 LOG.error(PackingToolErrMsg.VERIFY_MODULE_VERSION_FAILED.toString(errorMsg)); 3848 throw new BundleException(errorMsg); 3849 } else if (versionNormalizeUtil.getOriginVersionCode() == utility.getVersionCode()) { 3850 LOG.warning("versionNormalize warning: module " + 3851 versionNormalizeUtil.getModuleName() + " version code not changed"); 3852 } 3853 if (versionNormalizeUtil.getOriginVersionName().equals(utility.getVersionName())) { 3854 LOG.warning("versionNormalize warning: module " + 3855 versionNormalizeUtil.getModuleName() + " version name not changed"); 3856 } 3857 } 3858 unpackHap(String srcPath, String outPath)3859 private static void unpackHap(String srcPath, String outPath) throws BundleException { 3860 try (FileInputStream fis = new FileInputStream(srcPath); 3861 ZipInputStream zipInputStream = new ZipInputStream(new BufferedInputStream(fis))) { 3862 File destDir = new File(outPath); 3863 if (!destDir.exists()) { 3864 destDir.mkdirs(); 3865 } 3866 3867 ZipEntry entry; 3868 while ((entry = zipInputStream.getNextEntry()) != null) { 3869 String entryName = entry.getName(); 3870 File entryFile = new File(outPath, entryName); 3871 3872 if (entry.isDirectory()) { 3873 entryFile.mkdirs(); 3874 zipInputStream.closeEntry(); 3875 continue; 3876 } 3877 File parent = entryFile.getParentFile(); 3878 if (!parent.exists()) { 3879 parent.mkdirs(); 3880 } 3881 3882 writeToFile(zipInputStream, entryFile); 3883 3884 zipInputStream.closeEntry(); 3885 } 3886 } catch (IOException e) { 3887 LOG.error(PackingToolErrMsg.IO_EXCEPTION.toString("Unpack hap exist IOException: " + e.getMessage())); 3888 throw new BundleException("unpack hap failed IOException " + e.getMessage()); 3889 } 3890 } 3891 writeToFile(ZipInputStream zipInputStream, File entryFile)3892 private static void writeToFile(ZipInputStream zipInputStream, File entryFile) throws IOException { 3893 try (FileOutputStream fos = new FileOutputStream(entryFile)) { 3894 byte[] buffer = new byte[BUFFER_SIZE]; 3895 int bytesRead; 3896 while ((bytesRead = zipInputStream.read(buffer)) != -1) { 3897 fos.write(buffer, 0, bytesRead); 3898 } 3899 } 3900 } 3901 getFileNameByPath(String path)3902 private static String getFileNameByPath(String path) { 3903 Path filePath = Paths.get(path); 3904 return filePath.getFileName().toString(); 3905 } 3906 packEncryptJsonFile(Utility utility)3907 private void packEncryptJsonFile(Utility utility) throws BundleException { 3908 if (!utility.getEncryptPath().isEmpty()) { 3909 pathToFile(utility, utility.getEncryptPath(), NULL_DIR_NAME, false); 3910 } else { 3911 LOG.info("Compressor::packEncryptJsonFile has no encrypt.json"); 3912 } 3913 } 3914 packPacJsonFile(Utility utility)3915 private void packPacJsonFile(Utility utility) throws BundleException { 3916 if (!utility.getPacJsonPath().isEmpty()) { 3917 pathToFile(utility, utility.getPacJsonPath(), NULL_DIR_NAME, false); 3918 } else { 3919 LOG.info("Compressor::packPacJsonFile has no pac.json"); 3920 } 3921 } 3922 generalNormalize(Utility utility)3923 private void generalNormalize(Utility utility) { 3924 List<GeneralNormalizeUtil> utils = new ArrayList<>(); 3925 Path tempDir = null; 3926 boolean isSuccess = true; 3927 String[] name = new String[2]; 3928 for (String hapPath : utility.getFormattedHapList()) { 3929 try { 3930 GeneralNormalizeUtil util = new GeneralNormalizeUtil(); 3931 tempDir = Files.createTempDirectory(Paths.get(utility.getOutPath()), "temp"); 3932 unpackHap(hapPath, tempDir.toAbsolutePath().toString()); 3933 File moduleFile = new File( 3934 tempDir.toAbsolutePath() + LINUX_FILE_SEPARATOR + MODULE_JSON); 3935 File configFile = new File( 3936 tempDir.toAbsolutePath() + LINUX_FILE_SEPARATOR + CONFIG_JSON); 3937 File packInfoFile = new File( 3938 tempDir.toAbsolutePath() + LINUX_FILE_SEPARATOR + PACKINFO_NAME); 3939 3940 if (moduleFile.exists() && configFile.exists()) { 3941 LOG.error(PackingToolErrMsg.GENERAL_NORMALIZE_MODE_ARGS_INVALID .toString("Invalid hap structure")); 3942 throw new BundleException("generalNormalize failed, invalid hap structure."); 3943 } 3944 if (moduleFile.exists()) { 3945 String moduleJsonPath = tempDir.resolve(MODULE_JSON).toString(); 3946 util = parseAndModifyGeneralModuleJson(moduleJsonPath, utility, name); 3947 } else if (configFile.exists()) { 3948 String configJsonPath = tempDir.resolve(CONFIG_JSON).toString(); 3949 util = parseAndModifyGeneralConfigJson(configJsonPath, utility, name); 3950 } else { 3951 LOG.error(PackingToolErrMsg.GENERAL_NORMALIZE_MODE_ARGS_INVALID .toString("Invalid hap structure")); 3952 throw new BundleException("generalNormalize failed, invalid hap structure."); 3953 } 3954 if (packInfoFile.exists()) { 3955 String packInfoPath = tempDir.resolve(PACKINFO_NAME).toString(); 3956 parseAndModifyGeneralPackInfo(packInfoPath, utility); 3957 } 3958 utils.add(util); 3959 String modifiedHapPath = Paths.get(utility.getOutPath()) + 3960 LINUX_FILE_SEPARATOR + Paths.get(hapPath).getFileName().toString(); 3961 boolean ret = compressDirToHap(tempDir, modifiedHapPath); 3962 if (!ret) { 3963 isSuccess = false; 3964 String errMsg = "compressDirToHap failed bundleName:" + name[0] + " moduleName:" + name[1]; 3965 LOG.error(PackingToolErrMsg.GENERAL_NORMALIZE_MODE_ARGS_INVALID .toString(errMsg)); 3966 break; 3967 } 3968 } catch (Exception e) { 3969 String errMsg = "general normalize exist Exception bundleName:" + name[0] + " moduleName:" + name[1]; 3970 LOG.error(PackingToolErrMsg.GENERAL_NORMALIZE_MODE_ARGS_INVALID .toString(errMsg + e.getMessage())); 3971 isSuccess = false; 3972 break; 3973 } finally { 3974 if (tempDir != null) { 3975 deleteDirectory(tempDir.toFile()); 3976 } 3977 } 3978 } 3979 if (!isSuccess) { 3980 if (Paths.get(utility.getOutPath()) != null) { 3981 deleteFile(Paths.get(utility.getOutPath()).toFile()); 3982 } 3983 return; 3984 } 3985 writeGeneralRecord(utils, utility.getOutPath()); 3986 } 3987 parseAndModifyGeneralModuleJson(String jsonFilePath, Utility utility, String[] name)3988 private GeneralNormalizeUtil parseAndModifyGeneralModuleJson(String jsonFilePath, Utility utility, String[] name) 3989 throws BundleException { 3990 GeneralNormalizeUtil util = new GeneralNormalizeUtil(); 3991 try (FileInputStream jsonStream = new FileInputStream(jsonFilePath)) { 3992 JSONObject jsonObject = JSON.parseObject(jsonStream, JSONObject.class); 3993 if (!jsonObject.containsKey(APP)) { 3994 LOG.error(PackingToolErrMsg.PARSE_AND_MODIFY_MODULEJSON_FAILED.toString("The module.json file " + 3995 "does not contain 'app'.")); 3996 throw new BundleException("The module.json file does not contain 'app'. "); 3997 } 3998 JSONObject appObject = jsonObject.getJSONObject(APP); 3999 JSONObject moduleObject = jsonObject.getJSONObject(MODULE); 4000 if (!moduleObject.containsKey(NAME)) { 4001 LOG.error(PackingToolErrMsg.PARSE_AND_MODIFY_MODULEJSON_FAILED.toString("The module object of " + 4002 "module.json file does not contain 'name'.")); 4003 throw new BundleException("The module object of module.json file does not contain 'name'. "); 4004 } 4005 if (!appObject.containsKey(BUNDLE_NAME)) { 4006 LOG.error(PackingToolErrMsg.PARSE_AND_MODIFY_MODULEJSON_FAILED.toString("The app object of " + 4007 "app.json file does not contain 'bundleName'.")); 4008 throw new BundleException("The app object of app.json file does not contain 'bundleName'. "); 4009 } 4010 name[0] = appObject.getString(BUNDLE_NAME); 4011 name[1] = moduleObject.getString(NAME); 4012 util.setModuleName(moduleObject.getString(NAME)); 4013 4014 if (utility.getGeneralNormalizeList().contains(DEVICE_TYPES)) { 4015 util.setOriginDeviceTypes(getJsonString(moduleObject, DEVICE_TYPES)); 4016 moduleObject.put(DEVICE_TYPES, utility.getDeviceTypes().split(",")); 4017 } 4018 4019 if (utility.getGeneralNormalizeList().contains(VERSION_CODE)) { 4020 util.setOriginVersionCode(appObject.getIntValue(VERSION_CODE)); 4021 appObject.put(VERSION_CODE, utility.getVersionCode()); 4022 } 4023 4024 if (utility.getGeneralNormalizeList().contains(VERSION_NAME)) { 4025 util.setOriginVersionName(appObject.getString(VERSION_NAME)); 4026 appObject.put(VERSION_NAME, utility.getVersionName()); 4027 } 4028 4029 if (utility.getGeneralNormalizeList().contains(BUNDLE_NAME)) { 4030 util.setOriginBundleName(appObject.getString(BUNDLE_NAME)); 4031 appObject.put(BUNDLE_NAME, utility.getBundleName()); 4032 } 4033 4034 if (utility.getGeneralNormalizeList().contains(MIN_COMPATIBLE_VERSION_CODE)) { 4035 if (appObject.containsKey(MIN_COMPATIBLE_VERSION_CODE)) { 4036 util.setOriginMinCompatibleVersionCode(appObject.getIntValue(MIN_COMPATIBLE_VERSION_CODE)); 4037 } else { 4038 util.setOriginMinCompatibleVersionCode(appObject.getIntValue(VERSION_CODE)); 4039 } 4040 appObject.put(MIN_COMPATIBLE_VERSION_CODE, utility.getMinCompatibleVersionCode()); 4041 } 4042 4043 if (utility.getGeneralNormalizeList().contains(MIN_API_VERSION)) { 4044 util.setOriginMinAPIVersion(appObject.getIntValue(MIN_API_VERSION)); 4045 appObject.put(MIN_API_VERSION, utility.getMinAPIVersion()); 4046 } 4047 4048 if (utility.getGeneralNormalizeList().contains(TARGET_API_VERSION)) { 4049 util.setOriginTargetAPIVersion(appObject.getIntValue(TARGET_API_VERSION)); 4050 appObject.put(TARGET_API_VERSION, utility.getTargetAPIVersion()); 4051 } 4052 4053 if (utility.getGeneralNormalizeList().contains(API_RELEASE_TYPE)) { 4054 util.setOriginApiReleaseType(appObject.getString(API_RELEASE_TYPE)); 4055 appObject.put(API_RELEASE_TYPE, utility.getApiReleaseType()); 4056 } 4057 4058 if (utility.getGeneralNormalizeList().contains(BUNDLE_TYPE)) { 4059 if (!appObject.containsKey(BUNDLE_TYPE)) { 4060 if (moduleObject.getBoolean(INSTALLATION_FREE)) { 4061 String errMsg = 4062 "app.json5 file configuration does not match the 'installationFree' setting of true."; 4063 String solution = "Add the bundleType field to the app.json5 file or set it atomicService."; 4064 LOG.error(PackingToolErrMsg.PARSE_STAGE_BUNDLE_TYPE_FAILED.toString(errMsg, solution)); 4065 throw new BundleException(errMsg); 4066 } 4067 util.setOriginBundleType(APP); 4068 } else { 4069 util.setOriginBundleType(appObject.getString(BUNDLE_TYPE)); 4070 } 4071 appObject.put(BUNDLE_TYPE, utility.getBundleType()); 4072 } 4073 4074 if (utility.getGeneralNormalizeList().contains(INSTALLATION_FREE)) { 4075 util.setOriginInstallationFree(moduleObject.getBoolean(INSTALLATION_FREE)); 4076 util.setIsInstallationFree(true); 4077 moduleObject.put(INSTALLATION_FREE, utility.getDeliveryWithInstall()); 4078 } 4079 4080 if (utility.getGeneralNormalizeList().contains(DELIVERY_WITH_INSTALL)) { 4081 util.setOriginDeliveryWithInstall(moduleObject.getBoolean(DELIVERY_WITH_INSTALL)); 4082 util.setIsDeliveryWithInstall(true); 4083 moduleObject.put(DELIVERY_WITH_INSTALL, utility.getInstallationFree()); 4084 } 4085 writeJson(jsonFilePath, jsonObject); 4086 } catch (IOException e) { 4087 LOG.error(PackingToolErrMsg.IO_EXCEPTION.toString("Parse and modify module.json exist IOException: " + 4088 e.getMessage())); 4089 throw new BundleException("Parse and modify module.json exist IOException: " + e.getMessage()); 4090 } 4091 return util; 4092 } 4093 parseAndModifyGeneralConfigJson(String jsonFilePath, Utility utility, String[] name)4094 private GeneralNormalizeUtil parseAndModifyGeneralConfigJson(String jsonFilePath, Utility utility, String[] name) 4095 throws BundleException { 4096 GeneralNormalizeUtil util = new GeneralNormalizeUtil(); 4097 try (FileInputStream jsonStream = new FileInputStream(jsonFilePath)) { 4098 JSONObject jsonObject = JSON.parseObject(jsonStream, JSONObject.class); 4099 if (!jsonObject.containsKey(APP)) { 4100 LOG.error(PackingToolErrMsg.PARSE_MODIFY_CONFIG_JSON_FAILED.toString("The config.json file " + 4101 "does not contain 'app'.")); 4102 throw new BundleException("The config.json file does not contain 'app'. "); 4103 } 4104 JSONObject appObject = jsonObject.getJSONObject(APP); 4105 4106 if (!appObject.containsKey(VERSION)) { 4107 LOG.error(PackingToolErrMsg.PARSE_MODIFY_CONFIG_JSON_FAILED.toString("The app object of config.json " + 4108 "file does not contain 'version'.")); 4109 throw new BundleException("The app object of config.json file does not contain 'version'. "); 4110 } 4111 JSONObject versionObj = appObject.getJSONObject(VERSION); 4112 4113 if (!appObject.containsKey(API_VERSION)) { 4114 JSONObject apiVersion = new JSONObject(); 4115 appObject.put(API_VERSION, apiVersion); 4116 } 4117 JSONObject apiVersionObj = appObject.getJSONObject(API_VERSION); 4118 4119 if (!jsonObject.containsKey(MODULE)) { 4120 LOG.error(PackingToolErrMsg.PARSE_MODIFY_CONFIG_JSON_FAILED.toString("The app object of config.json " + 4121 "file does not contain 'module'.")); 4122 throw new BundleException("The app object of config.json file does not contain 'module'. "); 4123 } 4124 JSONObject moduleObject = jsonObject.getJSONObject(MODULE); 4125 4126 if (!moduleObject.containsKey(DISTRO)) { 4127 LOG.error(PackingToolErrMsg.PARSE_MODIFY_CONFIG_JSON_FAILED.toString("The app object of config.json " + 4128 "file does not contain 'distro'.")); 4129 throw new BundleException("The app object of config.json file does not contain 'distro'. "); 4130 } 4131 JSONObject distroObj = moduleObject.getJSONObject(DISTRO); 4132 4133 if (!distroObj.containsKey(MODULE_NAME_NEW)) { 4134 LOG.error(PackingToolErrMsg.PARSE_MODIFY_CONFIG_JSON_FAILED.toString("The module object of " + 4135 "config.json file does not contain 'moduleName'.")); 4136 throw new BundleException("The module object of module.json file does not contain 'moduleName'. "); 4137 } 4138 if (!appObject.containsKey(BUNDLE_NAME)) { 4139 LOG.error(PackingToolErrMsg.PARSE_MODIFY_CONFIG_JSON_FAILED.toString("The app object of " + 4140 "config.json file does not contain 'bundleName'.")); 4141 throw new BundleException("The app object of config.json file does not contain 'bundleName'. "); 4142 } 4143 name[0] = appObject.getString(BUNDLE_NAME); 4144 name[1] = distroObj.getString(MODULE_NAME_NEW); 4145 util.setModuleName(distroObj.getString(MODULE_NAME_NEW)); 4146 4147 if (utility.getGeneralNormalizeList().contains(DEVICE_TYPES)) { 4148 util.setOriginDeviceTypes(getJsonString(moduleObject, DEVICE_TYPES)); 4149 moduleObject.put(DEVICE_TYPE, utility.getDeviceTypes().split(",")); 4150 } 4151 if (utility.getGeneralNormalizeList().contains(VERSION_CODE)) { 4152 util.setOriginVersionCode(versionObj.getIntValue(CODE)); 4153 versionObj.put(CODE, utility.getVersionCode()); 4154 } 4155 4156 if (utility.getGeneralNormalizeList().contains(VERSION_NAME)) { 4157 util.setOriginVersionName(versionObj.getString(NAME)); 4158 versionObj.put(NAME, utility.getVersionName()); 4159 } 4160 4161 if (utility.getGeneralNormalizeList().contains(MIN_COMPATIBLE_VERSION_CODE)) { 4162 if (versionObj.containsKey(MIN_COMPATIBLE_VERSION_CODE)) { 4163 util.setOriginMinCompatibleVersionCode(versionObj.getIntValue(MIN_COMPATIBLE_VERSION_CODE)); 4164 } else { 4165 util.setOriginMinCompatibleVersionCode(versionObj.getIntValue(CODE)); 4166 } 4167 versionObj.put(MIN_COMPATIBLE_VERSION_CODE, utility.getMinCompatibleVersionCode()); 4168 } 4169 4170 if (utility.getGeneralNormalizeList().contains(BUNDLE_NAME)) { 4171 util.setOriginBundleName(appObject.getString(BUNDLE_NAME)); 4172 appObject.put(BUNDLE_NAME, utility.getBundleName()); 4173 } 4174 4175 if (utility.getGeneralNormalizeList().contains(MIN_API_VERSION)) { 4176 util.setOriginMinAPIVersion(apiVersionObj.getIntValue(COMPATIBLE)); 4177 apiVersionObj.put(COMPATIBLE, utility.getMinAPIVersion()); 4178 } 4179 4180 if (utility.getGeneralNormalizeList().contains(TARGET_API_VERSION)) { 4181 util.setOriginTargetAPIVersion(apiVersionObj.getIntValue(TARGET)); 4182 apiVersionObj.put(TARGET, utility.getTargetAPIVersion()); 4183 } 4184 4185 if (utility.getGeneralNormalizeList().contains(API_RELEASE_TYPE)) { 4186 util.setOriginApiReleaseType(apiVersionObj.getString(RELEASE_TYPE)); 4187 apiVersionObj.put(RELEASE_TYPE, utility.getApiReleaseType()); 4188 } 4189 4190 if (utility.getGeneralNormalizeList().contains(BUNDLE_TYPE)) { 4191 if (!appObject.containsKey(BUNDLE_TYPE)) { 4192 if (distroObj.getBoolean(INSTALLATION_FREE)) { 4193 util.setOriginBundleType(ATOMIC_SERVICE); 4194 } else { 4195 util.setOriginBundleType(APP); 4196 } 4197 } else { 4198 util.setOriginBundleType(appObject.getString(BUNDLE_TYPE)); 4199 } 4200 appObject.put(BUNDLE_TYPE, utility.getBundleType()); 4201 } 4202 4203 if (utility.getGeneralNormalizeList().contains(INSTALLATION_FREE)) { 4204 util.setOriginInstallationFree(distroObj.getBoolean(INSTALLATION_FREE)); 4205 util.setIsInstallationFree(true); 4206 distroObj.put(INSTALLATION_FREE, utility.getDeliveryWithInstall()); 4207 } 4208 4209 if (utility.getGeneralNormalizeList().contains(DELIVERY_WITH_INSTALL)) { 4210 util.setOriginDeliveryWithInstall(distroObj.getBoolean(DELIVERY_WITH_INSTALL)); 4211 util.setIsDeliveryWithInstall(true); 4212 distroObj.put(DELIVERY_WITH_INSTALL, utility.getInstallationFree()); 4213 } 4214 writeJson(jsonFilePath, jsonObject); 4215 } catch (IOException e) { 4216 LOG.error(PackingToolErrMsg.IO_EXCEPTION.toString("Parse and modify module.json exist IOException: " + 4217 e.getMessage())); 4218 throw new BundleException("Parse and modify config.json exist IOException: " + e.getMessage()); 4219 } 4220 return util; 4221 } 4222 parseAndModifyGeneralPackInfo(String packInfoPath, Utility utility)4223 private void parseAndModifyGeneralPackInfo(String packInfoPath, Utility utility) 4224 throws BundleException { 4225 try (FileInputStream jsonStream = new FileInputStream(packInfoPath)) { 4226 JSONObject jsonObject = JSON.parseObject(jsonStream, JSONObject.class); 4227 if (jsonObject == null) { 4228 LOG.warning("parseAndModifyGeneralPackInfo failed, json format invalid."); 4229 return; 4230 } 4231 JSONObject summaryObject = jsonObject.getJSONObject(SUMMARY); 4232 if (summaryObject == null) { 4233 LOG.warning("parseAndModifyGeneralPackInfo failed, summary invalid."); 4234 return; 4235 } 4236 JSONObject appObject = summaryObject.getJSONObject(APP); 4237 if (appObject == null) { 4238 LOG.warning("parseAndModifyGeneralPackInfo failed, app invalid."); 4239 return; 4240 } 4241 JSONArray moduleJsonList = summaryObject.getJSONArray(MODULES); 4242 if (moduleJsonList.isEmpty()) { 4243 LOG.warning("parseAndModifyGeneralPackInfo failed, modules invalid."); 4244 return; 4245 } 4246 4247 if (utility.getGeneralNormalizeList().contains(DEVICE_TYPES)) { 4248 for (int i = 0; i < moduleJsonList.size(); i++) { 4249 JSONObject moduleJson = moduleJsonList.getJSONObject(i); 4250 if (moduleJson == null) { 4251 LOG.warning("parseAndModifyGeneralPackInfo failed, moduleJson invalid."); 4252 continue; 4253 } 4254 moduleJson.put(DEVICE_TYPE, utility.getDeviceTypes().split(",")); 4255 } 4256 } 4257 4258 JSONObject versionObject = appObject.getJSONObject(VERSION); 4259 if (versionObject == null) { 4260 LOG.warning("parseAndModifyGeneralPackInfo failed, version invalid."); 4261 return; 4262 } 4263 4264 if (utility.getGeneralNormalizeList().contains(VERSION_CODE)) { 4265 versionObject.put(CODE, utility.getVersionCode()); 4266 } 4267 4268 if (utility.getGeneralNormalizeList().contains(VERSION_NAME)) { 4269 versionObject.put(NAME, utility.getVersionName()); 4270 } 4271 4272 if (utility.getGeneralNormalizeList().contains(BUNDLE_NAME)) { 4273 appObject.put(BUNDLE_NAME, utility.getBundleName()); 4274 } 4275 4276 if (utility.getGeneralNormalizeList().contains(MIN_COMPATIBLE_VERSION_CODE)) { 4277 versionObject.put(MIN_COMPATIBLE_VERSION_CODE, utility.getMinCompatibleVersionCode()); 4278 } 4279 4280 if (utility.getGeneralNormalizeList().contains(MIN_API_VERSION)) { 4281 setApiVersion(moduleJsonList, MIN_API_VERSION, utility); 4282 } 4283 4284 if (utility.getGeneralNormalizeList().contains(TARGET_API_VERSION)) { 4285 setApiVersion(moduleJsonList, TARGET_API_VERSION, utility); 4286 } 4287 4288 if (utility.getGeneralNormalizeList().contains(API_RELEASE_TYPE)) { 4289 setApiVersion(moduleJsonList, API_RELEASE_TYPE, utility); 4290 } 4291 4292 if (utility.getGeneralNormalizeList().contains(BUNDLE_TYPE)) { 4293 appObject.put(BUNDLE_TYPE, utility.getBundleType()); 4294 } 4295 4296 if (utility.getGeneralNormalizeList().contains(INSTALLATION_FREE)) { 4297 setDistroObj(moduleJsonList, INSTALLATION_FREE, utility); 4298 } 4299 4300 if (utility.getGeneralNormalizeList().contains(DELIVERY_WITH_INSTALL)) { 4301 setDistroObj(moduleJsonList, DELIVERY_WITH_INSTALL, utility); 4302 } 4303 4304 JSONArray jsonArray = jsonObject.getJSONArray(PACKAGES); 4305 if (jsonArray != null) { 4306 for (int i = 0; i < jsonArray.size(); i++) { 4307 JSONObject object = jsonArray.getJSONObject(i); 4308 if (utility.getGeneralNormalizeList().contains(DEVICE_TYPES)) { 4309 object.put(DEVICE_TYPE, utility.getDeviceTypes().split(",")); 4310 } 4311 if (utility.getGeneralNormalizeList().contains(DELIVERY_WITH_INSTALL)) { 4312 object.put(DELIVERY_WITH_INSTALL, Boolean.parseBoolean(utility.getDeliveryWithInstall())); 4313 } 4314 } 4315 } 4316 4317 writeJson(packInfoPath, jsonObject); 4318 } catch (IOException e) { 4319 LOG.warning("parseAndModifyGeneralPackInfo failed, IOException." + e.getMessage()); 4320 } 4321 } 4322 setApiVersion(JSONArray moduleJsonList, String key, Utility utility)4323 private static void setApiVersion(JSONArray moduleJsonList, String key, Utility utility) { 4324 for (int i = 0; i < moduleJsonList.size(); i++) { 4325 JSONObject moduleJson = moduleJsonList.getJSONObject(i); 4326 if (moduleJson == null) { 4327 LOG.warning("setApiVersion failed, moduleJson invalid."); 4328 break; 4329 } 4330 JSONObject apiVersionObj = moduleJson.getJSONObject(API_VERSION); 4331 if (apiVersionObj == null) { 4332 JSONObject apiVersion = new JSONObject(); 4333 moduleJson.put(API_VERSION, apiVersion); 4334 apiVersionObj = moduleJson.getJSONObject(API_VERSION); 4335 } 4336 if(key == MIN_API_VERSION) { 4337 apiVersionObj.put(COMPATIBLE, utility.getMinAPIVersion()); 4338 } else if (key == TARGET_API_VERSION) { 4339 apiVersionObj.put(TARGET, utility.getTargetAPIVersion()); 4340 } else if (key == API_RELEASE_TYPE) { 4341 apiVersionObj.put(RELEASE_TYPE, utility.getApiReleaseType()); 4342 } 4343 } 4344 } 4345 setDistroObj(JSONArray moduleJsonList, String key, Utility utility)4346 private static void setDistroObj(JSONArray moduleJsonList, String key, Utility utility) { 4347 for (int i = 0; i < moduleJsonList.size(); i++) { 4348 JSONObject moduleJson = moduleJsonList.getJSONObject(i); 4349 if (moduleJson == null) { 4350 LOG.warning("setDistroObj failed, moduleJson invalid."); 4351 break; 4352 } 4353 JSONObject distroObj = moduleJson.getJSONObject(DISTRO); 4354 if (distroObj == null) { 4355 LOG.warning("setDistroObj failed, distro invalid."); 4356 break; 4357 } 4358 if(key == INSTALLATION_FREE) { 4359 distroObj.put(INSTALLATION_FREE, Boolean.parseBoolean(utility.getInstallationFree())); 4360 } else if (key == DELIVERY_WITH_INSTALL) { 4361 distroObj.put(DELIVERY_WITH_INSTALL, Boolean.parseBoolean(utility.getDeliveryWithInstall())); 4362 } 4363 } 4364 } 4365 writeGeneralRecord(List<GeneralNormalizeUtil> utils, String outPath)4366 private static void writeGeneralRecord(List<GeneralNormalizeUtil> utils, String outPath) { 4367 JSONArray jsonArray = new JSONArray(); 4368 try (FileWriter fileWriter = new FileWriter(outPath + LINUX_FILE_SEPARATOR + GENERAL_RECORD)) { 4369 for (GeneralNormalizeUtil util : utils) { 4370 JSONObject jsonObject = new JSONObject(); 4371 if (util.originDeviceTypes != null && !util.originDeviceTypes.isEmpty()) { 4372 jsonObject.put("deviceTypes", util.originDeviceTypes); 4373 if (util.originDeviceTypes instanceof String) { 4374 String arrayStr = (String) util.originDeviceTypes; 4375 JSONArray deviceTypes = JSON.parseArray(arrayStr); 4376 jsonObject.put("deviceTypes", deviceTypes); 4377 } 4378 } 4379 if (util.originVersionCode != INVALID_VERSION) { 4380 jsonObject.put("versionCode", util.originVersionCode); 4381 } 4382 if (util.moduleName != null && !util.moduleName.isEmpty()) { 4383 jsonObject.put("moduleName", util.moduleName); 4384 } 4385 if (util.originVersionName != null && !util.originVersionName.isEmpty()) { 4386 jsonObject.put("versionName", util.originVersionName); 4387 } 4388 if (util.originMinCompatibleVersionCode != INVALID_VERSION) { 4389 jsonObject.put("minCompatibleVersionCode", util.originMinCompatibleVersionCode); 4390 } 4391 if (util.originMinAPIVersion != INVALID_VERSION) { 4392 jsonObject.put("minAPIVersion", util.originMinAPIVersion); 4393 } 4394 if (util.originTargetAPIVersion != INVALID_VERSION) { 4395 jsonObject.put("targetAPIVersion", util.originTargetAPIVersion); 4396 } 4397 if (util.originApiReleaseType!= null && !util.originApiReleaseType.isEmpty()) { 4398 jsonObject.put("apiReleaseType", util.originApiReleaseType); 4399 } 4400 if (util.originBundleType != null && !util.originBundleType.isEmpty()) { 4401 jsonObject.put("bundleType", util.originBundleType); 4402 } 4403 if (util.originBundleName != null && !util.originBundleName.isEmpty()) { 4404 jsonObject.put("bundleName", util.originBundleName); 4405 } 4406 if (util.isInstallationFree == true) { 4407 jsonObject.put("installationFree", util.originInstallationFree); 4408 } 4409 if (util.isDeliveryWithInstall == true) { 4410 jsonObject.put("deliveryWithInstall", util.originDeliveryWithInstall); 4411 } 4412 jsonArray.add(jsonObject); 4413 } 4414 fileWriter.write(jsonArray.toString()); 4415 } catch (IOException e) { 4416 LOG.error(PackingToolErrMsg.IO_EXCEPTION.toString("Write general record exist IOException: " 4417 + e.getMessage())); 4418 } 4419 } 4420 deleteFile(File dir)4421 private static void deleteFile(File dir) { 4422 File[] children = dir.listFiles(); 4423 if (children != null) { 4424 for (File child : children) { 4425 child.delete(); 4426 } 4427 } 4428 } 4429 } 4430