1 /* 2 * Copyright (c) 2022 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.math.BigDecimal; 19 import java.util.ArrayList; 20 import java.util.Collection; 21 import java.util.Collections; 22 import java.util.HashMap; 23 import java.util.HashSet; 24 import java.util.List; 25 import java.util.Map; 26 import java.util.Optional; 27 import java.util.Set; 28 import java.util.Objects; 29 import java.util.stream.Collectors; 30 import java.util.stream.Stream; 31 32 /** 33 * check hap is verify. 34 */ 35 class HapVerify { 36 private static final String INCLUDE = "include"; 37 private static final String EXCLUDE = "exclude"; 38 private static final Log LOG = new Log(HapVerify.class.toString()); 39 private static final String EMPTY_STRING = ""; 40 private static final String ENTRY = "entry"; 41 private static final String FEATURE = "feature"; 42 private static final String SHARED_LIBRARY = "shared"; 43 private static final String HAR = "har"; 44 private static final String REFERENCE_LINK = "FAQ"; 45 private static final String ATOMIC_SERVICE = "atomicService"; 46 private static final String TYPE_SHARED = "shared"; 47 private static final long FILE_LENGTH_1M = 1024 * 1024L; 48 private static final long FILE_LENGTH_1KB = 1024L; 49 private static final double FILE_SIZE_OFFSET_DOUBLE = 0.01d; 50 private static final int FILE_SIZE_DECIMAL_PRECISION = 2; 51 private static final String HAP_SUFFIX = ".hap"; 52 private static final String HSP_SUFFIX = ".hsp"; 53 private static final String APP_PLUGIN = "appPlugin"; 54 55 /** 56 * check hap is verify. 57 * 58 * @param hapVerifyInfos is the collection of hap infos 59 * @return the result 60 * @throws BundleException Throws this exception if the json is not standard 61 */ checkHapIsValid(List<HapVerifyInfo> hapVerifyInfos)62 public static boolean checkHapIsValid(List<HapVerifyInfo> hapVerifyInfos) throws BundleException { 63 if (hapVerifyInfos == null || hapVerifyInfos.isEmpty()) { 64 String errMsg = "Hap verify infos is null or empty."; 65 LOG.error(PackingToolErrMsg.CHECK_HAP_VERIFY_INFO_LIST_EMPTY.toString(errMsg)); 66 return false; 67 } 68 // check app is plugin app 69 if (!checkIsPluginApp(hapVerifyInfos)) { 70 LOG.error("checkIsPluginApp failed"); 71 return false; 72 } 73 // check app variable is same 74 if (!checkAppFieldsIsSame(hapVerifyInfos)) { 75 String errMsg = "Some app variable is different."; 76 LOG.error(PackingToolErrMsg.CHECK_HAP_INVALID.toString(errMsg)); 77 return false; 78 } 79 // check moduleName is valid 80 if (!checkModuleNameIsValid(hapVerifyInfos)) { 81 return false; 82 } 83 // check package is valid 84 if (!checkPackageNameIsValid(hapVerifyInfos)) { 85 String errMsg = "Check packageName is duplicated."; 86 LOG.error(PackingToolErrMsg.CHECK_HAP_INVALID.toString(errMsg)); 87 return false; 88 } 89 // check entry is valid 90 if (!checkEntryIsValid(hapVerifyInfos)) { 91 return false; 92 } 93 // check dependency is valid 94 if (!checkDependencyIsValid(hapVerifyInfos)) { 95 String errMsg = "Check module dependency is invalid."; 96 LOG.error(PackingToolErrMsg.CHECK_HAP_INVALID.toString(errMsg)); 97 return false; 98 } 99 // check atomic service is valid 100 if (!checkAtomicServiceIsValid(hapVerifyInfos)) { 101 String errMsg = "Check atomicService is invalid."; 102 LOG.error(PackingToolErrMsg.CHECK_HAP_INVALID.toString(errMsg)); 103 return false; 104 } 105 // check ability is valid 106 if (!checkAbilityNameIsValid(hapVerifyInfos)) { 107 LOG.info("Ability name is duplicated."); 108 } 109 // check targetModuleName 110 if (!checkTargetModuleNameIsExisted(hapVerifyInfos)) { 111 String errMsg = "Target module cannot found."; 112 LOG.error(PackingToolErrMsg.CHECK_HAP_INVALID.toString(errMsg)); 113 return false; 114 } 115 if (!checkCompileSdkIsValid(hapVerifyInfos)) { 116 String errMsg = "The compileSdkType of each module is different."; 117 LOG.error(PackingToolErrMsg.CHECK_HAP_INVALID.toString(errMsg)); 118 return false; 119 } 120 if (!checkProxyDataUriIsUnique(hapVerifyInfos)) { 121 String errMsg = "The values of uri in proxyData of module.json are not unique."; 122 LOG.error(PackingToolErrMsg.CHECK_HAP_INVALID.toString(errMsg)); 123 return false; 124 } 125 if (!checkContinueTypeIsValid(hapVerifyInfos)) { 126 return false; 127 } 128 return true; 129 } 130 checkIsPluginApp(List<HapVerifyInfo> hapVerifyInfos)131 private static boolean checkIsPluginApp(List<HapVerifyInfo> hapVerifyInfos) { 132 boolean hasPluginBundle = hapVerifyInfos.stream() 133 .anyMatch(hapVerifyInfo -> hapVerifyInfo.getBundleType().equals(APP_PLUGIN)); 134 if (!hasPluginBundle) { 135 return true; 136 } 137 if (hapVerifyInfos.size() != 1) { 138 LOG.error("plugin App must contain only one element"); 139 return false; 140 } 141 if (hapVerifyInfos.get(0).getFileType() != HSP_SUFFIX) { 142 LOG.error("plugin App must be of type hsp"); 143 return false; 144 } 145 return true; 146 } 147 checkContinueTypeIsValid(List<HapVerifyInfo> hapVerifyInfos)148 private static boolean checkContinueTypeIsValid(List<HapVerifyInfo> hapVerifyInfos) { 149 for (HapVerifyInfo hapVerifyInfo : hapVerifyInfos) { 150 if (!checkContinueTypeIsValid(hapVerifyInfo)) { 151 return false; 152 } 153 } 154 for (int i = 0; i < hapVerifyInfos.size(); i++) { 155 for (int j = i + 1; j < hapVerifyInfos.size(); j++) { 156 if (!checkContinueTypeIsValid(hapVerifyInfos.get(i), hapVerifyInfos.get(j))) { 157 return false; 158 } 159 } 160 } 161 return true; 162 } 163 checkContinueTypeIsValid(HapVerifyInfo hapVerifyInfo)164 private static boolean checkContinueTypeIsValid(HapVerifyInfo hapVerifyInfo) { 165 List<String> abilityNames = hapVerifyInfo.getAbilityNames(); 166 if (abilityNames.size() < 2) { 167 return true; 168 } 169 for (int i = 0; i < abilityNames.size(); i++) { 170 List<String> typeList = hapVerifyInfo.getContinueTypeMap().get(abilityNames.get(i)); 171 if (typeList == null) { 172 continue; 173 } 174 for (int j = i + 1; j < abilityNames.size(); j++) { 175 List<String> typeList2 = hapVerifyInfo.getContinueTypeMap().get(abilityNames.get(j)); 176 if (typeList2 == null) { 177 continue; 178 } 179 if (!Collections.disjoint(typeList, typeList2)) { 180 String cause = "Module(" + hapVerifyInfo.getModuleName() + "), Ability(" + 181 abilityNames.get(i) + ") and Ability(" + 182 abilityNames.get(j) + ") have same continueType.\n"; 183 cause += "Ability(" + abilityNames.get(i) + ") have continueType: " + typeList + ", "; 184 cause += "Another Ability(" + abilityNames.get(j) + ") have continueType: " + typeList2 + "."; 185 String solution = "Please ensure that the continueType for different abilities does not overlap."; 186 LOG.error(PackingToolErrMsg.CONTINUE_TYPE_INVALID.toString(cause, solution)); 187 return false; 188 } 189 } 190 } 191 return true; 192 } 193 checkContinueTypeIsValid(HapVerifyInfo hapVerifyInfo, HapVerifyInfo hapVerifyInfo2)194 private static boolean checkContinueTypeIsValid(HapVerifyInfo hapVerifyInfo, HapVerifyInfo hapVerifyInfo2) { 195 if (Collections.disjoint(hapVerifyInfo.getDeviceType(), hapVerifyInfo2.getDeviceType())) { 196 return true; 197 } 198 List<String> typeList = hapVerifyInfo.getContinueTypeMap().values().stream() 199 .flatMap(Collection::stream).collect(Collectors.toList()); 200 List<String> typeList2 = hapVerifyInfo2.getContinueTypeMap().values().stream() 201 .flatMap(Collection::stream).collect(Collectors.toList()); 202 if (!Collections.disjoint(typeList, typeList2)) { 203 String cause = "Conflict detected between modules due to overlapping deviceType and continueType:\n" + 204 "- Module(" + hapVerifyInfo.getModuleName() + ") with deviceType: " + 205 hapVerifyInfo.getDeviceType() + " and continueType: " + typeList + "\n" + 206 "- Module(" + hapVerifyInfo2.getModuleName() + ") with deviceType: " + 207 hapVerifyInfo2.getDeviceType() + " and continueType: " + typeList2; 208 209 String solution = "Ensure that the continueType fields in these modules are different. " + 210 "Update either (" + hapVerifyInfo.getModuleName() + ") or (" + hapVerifyInfo2.getModuleName() + 211 ") to avoid continueType or deviceType overlap."; 212 213 LOG.error(PackingToolErrMsg.CONTINUE_TYPE_INVALID.toString(cause, solution)); 214 return false; 215 } 216 return true; 217 } 218 219 /** 220 * check inter-app hsp is valid. 221 * 222 * @param hapVerifyInfos is the collection of hap infos 223 * @return the result 224 * @throws BundleException Throws this exception if the json is not standard 225 */ checkSharedApppIsValid(List<HapVerifyInfo> hapVerifyInfos)226 public static boolean checkSharedApppIsValid(List<HapVerifyInfo> hapVerifyInfos) throws BundleException { 227 if (hapVerifyInfos == null || hapVerifyInfos.isEmpty()) { 228 String cause = "Hap verify infos is null or empty"; 229 LOG.error(PackingToolErrMsg.CHECK_HAP_VERIFY_INFO_LIST_EMPTY.toString(cause)); 230 return false; 231 } 232 String moduleName = hapVerifyInfos.get(0).getModuleName(); 233 for (HapVerifyInfo hapVerifyInfo : hapVerifyInfos) { 234 if (!moduleName.equals(hapVerifyInfo.getModuleName())) { 235 String cause = "The module name is different."; 236 String solution = "When the bundleType is shared, ensure that all modules have the same module name."; 237 LOG.error(PackingToolErrMsg.CHECK_SHARED_APP_INVALID.toString(cause, solution)); 238 return false; 239 } 240 if (!hapVerifyInfo.getDependencyItemList().isEmpty()) { 241 String cause = "The shared App cannot depend on other modules."; 242 String solution = "Remove dependencies settings in 'module.json5' and ensure module does " + 243 "not contain dependencies."; 244 LOG.error(PackingToolErrMsg.CHECK_SHARED_APP_INVALID.toString(cause, solution)); 245 return false; 246 } 247 if (!TYPE_SHARED.equals(hapVerifyInfo.getModuleType())) { 248 String cause = "The module type is not shared."; 249 String solution = "Ensure module type is shared for all modules."; 250 LOG.error(PackingToolErrMsg.CHECK_SHARED_APP_INVALID.toString(cause, solution)); 251 return false; 252 } 253 } 254 for (int i = 0; i < hapVerifyInfos.size(); i++) { 255 for (int j = i + 1; j < hapVerifyInfos.size(); j++) { 256 if (!checkDuplicatedIsValid(hapVerifyInfos.get(i), hapVerifyInfos.get(j))) { 257 String cause = "There are duplicated modules in the packing file."; 258 String solution = "Ensure that there are no duplicated modules."; 259 LOG.error(PackingToolErrMsg.CHECK_SHARED_APP_INVALID.toString(cause, solution)); 260 return false; 261 } 262 } 263 } 264 return true; 265 } 266 267 268 /** 269 * check whether the app fields in the hap are the same. 270 * 271 * @param hapVerifyInfos is the collection of hap infos 272 * @return true if app fields is same 273 */ checkAppFieldsIsSame(List<HapVerifyInfo> hapVerifyInfos)274 private static boolean checkAppFieldsIsSame(List<HapVerifyInfo> hapVerifyInfos) { 275 if (hapVerifyInfos.isEmpty()) { 276 String cause = "Hap verify infos is empty."; 277 LOG.error(PackingToolErrMsg.CHECK_HAP_VERIFY_INFO_LIST_EMPTY.toString(cause)); 278 return false; 279 } 280 HapVerifyInfo verifyInfo = hapVerifyInfos.get(0); 281 Optional<HapVerifyInfo> optional = hapVerifyInfos.stream() 282 .filter(hapVerifyInfo -> !hapVerifyInfo.getModuleType().equals(TYPE_SHARED)) 283 .findFirst(); 284 if (optional.isPresent()) { 285 verifyInfo = optional.get(); 286 } 287 List<HapVerifyInfo> hapList = new ArrayList<>(); 288 List<HapVerifyInfo> hspList = new ArrayList<>(); 289 int hspMinCompatibleVersionCodeMax = -1; 290 int hspTargetApiVersionMax = -1; 291 int hspMinApiVersionMax = -1; 292 VerifyCollection verifyCollection = new VerifyCollection(); 293 verifyCollection.bundleName = verifyInfo.getBundleName(); 294 verifyCollection.setBundleType(verifyInfo.getBundleType()); 295 verifyCollection.vendor = verifyInfo.getVendor(); 296 verifyCollection.versionCode = verifyInfo.getVersion().versionCode; 297 verifyCollection.versionName = verifyInfo.getVersion().versionName; 298 verifyCollection.compatibleApiVersion = verifyInfo.getApiVersion().getCompatibleApiVersion(); 299 verifyCollection.releaseType = verifyInfo.getApiVersion().getReleaseType(); 300 verifyCollection.targetBundleName = verifyInfo.getTargetBundleName(); 301 verifyCollection.targetPriority = verifyInfo.getTargetPriority(); 302 verifyCollection.debug = verifyInfo.isDebug(); 303 verifyCollection.setModuleName(verifyInfo.getModuleName()); 304 verifyCollection.setModuleType(verifyInfo.getModuleType()); 305 verifyCollection.setMultiAppMode(verifyInfo.getMultiAppMode()); 306 307 List<String> assetAccessGroups = verifyInfo.getAssetAccessGroups(); 308 String moduleName = verifyInfo.getModuleName(); 309 Optional<HapVerifyInfo> entryOptional = hapVerifyInfos.stream() 310 .filter(hapVerifyInfo -> ENTRY.equals(hapVerifyInfo.getModuleType())) 311 .findFirst(); 312 if (entryOptional.isPresent()) { 313 moduleName = entryOptional.get().getModuleName(); 314 assetAccessGroups = entryOptional.get().getAssetAccessGroups(); 315 } 316 for (HapVerifyInfo hapVerifyInfo : hapVerifyInfos) { 317 if (!appFieldsIsSame(verifyCollection, hapVerifyInfo)) { 318 LOG.warning("Module: (" + verifyCollection.getModuleName() + ") and Module: (" + 319 hapVerifyInfo.getModuleName() + ") has different values."); 320 return false; 321 } 322 if (!appAssetAccessGroupsIsSame(assetAccessGroups, hapVerifyInfo)) { 323 LOG.warning("Module: (" + moduleName + ") and Module: (" + 324 hapVerifyInfo.getModuleName() + ") has different values."); 325 } 326 if (Objects.equals(hapVerifyInfo.getFileType(), HAP_SUFFIX)) { 327 hapList.add(hapVerifyInfo); 328 } else if (Objects.equals(hapVerifyInfo.getFileType(), HSP_SUFFIX)) { 329 hspList.add(hapVerifyInfo); 330 if (hapVerifyInfo.getVersion().minCompatibleVersionCode > hspMinCompatibleVersionCodeMax) { 331 hspMinCompatibleVersionCodeMax = hapVerifyInfo.getVersion().minCompatibleVersionCode; 332 } 333 if (hapVerifyInfo.getApiVersion().getTargetApiVersion() > hspTargetApiVersionMax) { 334 hspTargetApiVersionMax = hapVerifyInfo.getApiVersion().getTargetApiVersion(); 335 } 336 if (hapVerifyInfo.getApiVersion().getCompatibleApiVersion() > hspMinApiVersionMax) { 337 hspMinApiVersionMax = hapVerifyInfo.getApiVersion().getCompatibleApiVersion(); 338 } 339 } 340 } 341 if (!appFieldsIsValid(hapList, hspMinCompatibleVersionCodeMax, hspTargetApiVersionMax, hspMinApiVersionMax)) { 342 return false; 343 } 344 if (!moduleDebugValidation(hapList, hspList)) { 345 return false; 346 } 347 return true; 348 } 349 appFieldsIsValid(List<HapVerifyInfo> hapVerifyInfos, int minCompatibleVersionCode, int targetApiVersion, int minApiVersion)350 private static boolean appFieldsIsValid(List<HapVerifyInfo> hapVerifyInfos, int minCompatibleVersionCode, 351 int targetApiVersion, int minApiVersion) { 352 if (hapVerifyInfos.isEmpty()) { 353 LOG.warning("Hap verify infos is empty"); 354 return true; 355 } 356 HapVerifyInfo hap = hapVerifyInfos.get(0); 357 for (HapVerifyInfo hapInfo : hapVerifyInfos) { 358 if (hap.getVersion().minCompatibleVersionCode != hapInfo.getVersion().minCompatibleVersionCode || 359 hap.getApiVersion().getTargetApiVersion() != hapInfo.getApiVersion().getTargetApiVersion() || 360 hap.getApiVersion().getCompatibleApiVersion() != hapInfo.getApiVersion().getCompatibleApiVersion()) { 361 String errMsg = "Hap minCompatibleVersionCode or targetApiVersion or minApiVersion different."; 362 String solution = "Ensure that the values of 'minCompatibleVersionCode' and 'targetApiVersion' " + 363 "and 'minApiVersion' in the module.json file of each HAP module are the same."; 364 LOG.error(PackingToolErrMsg.CHECK_APP_FIELDS_INVALID.toString(errMsg, solution)); 365 return false; 366 } 367 } 368 if (hap.getVersion().minCompatibleVersionCode < minCompatibleVersionCode || 369 hap.getApiVersion().getTargetApiVersion() < targetApiVersion || 370 hap.getApiVersion().getCompatibleApiVersion() < minApiVersion) { 371 String cause = "The values of minCompatibleVersionCode or targetApiVersion or minApiVersion in the" + 372 " module.json file of the HAP module are smaller than those of the HSP module."; 373 String solution = "Ensure that the values of aminCompatibleVersionCode and targetApiVersion" + 374 " and minApiVersion in the module.json file of the HAP module" + 375 " are greater than or equal to those of the HSP module."; 376 LOG.error(PackingToolErrMsg.CHECK_APP_FIELDS_INVALID.toString(cause, solution)); 377 return false; 378 } 379 return true; 380 } 381 moduleDebugValidation(List<HapVerifyInfo> hapVerifyInfos, List<HapVerifyInfo> hspVerifyInfos)382 private static boolean moduleDebugValidation(List<HapVerifyInfo> hapVerifyInfos, 383 List<HapVerifyInfo> hspVerifyInfos) { 384 if (hapVerifyInfos.isEmpty()) { 385 LOG.warning("Hap verify infos is empty"); 386 return true; 387 } 388 HapVerifyInfo hap = hapVerifyInfos.get(0); 389 for (HapVerifyInfo hapInfo : hapVerifyInfos) { 390 if (hap.isDebug() != hapInfo.isDebug()) { 391 String errMsg = "The debug fields of multiple Hap are different."; 392 String solution = "Ensure that the values of 'debug' in the module.json file of each HAP module" + 393 " are the same."; 394 LOG.error(PackingToolErrMsg.CHECK_APP_FIELDS_INVALID.toString(errMsg, solution)); 395 return false; 396 } 397 } 398 if (hap.isDebug() || hspVerifyInfos.isEmpty()) { 399 LOG.warning("Hap debug is true or Hsp verify infos is empty"); 400 return true; 401 } 402 if (hspVerifyInfos.stream().anyMatch(HapVerifyInfo::isDebug)) { 403 String errMsg = "Detected HAP(s) with debug=false, but some HSP(s) are debug=true."; 404 String solution = "When the debug value of Hap is false,the debug value of Hsp should also be false."; 405 LOG.error(PackingToolErrMsg.CHECK_APP_FIELDS_INVALID.toString(errMsg, solution)); 406 return false; 407 } 408 return true; 409 } 410 appFieldsIsSame(VerifyCollection verifyCollection, HapVerifyInfo hapVerifyInfo)411 private static boolean appFieldsIsSame(VerifyCollection verifyCollection, HapVerifyInfo hapVerifyInfo) { 412 if (hapVerifyInfo.getBundleName().isEmpty() || 413 !verifyCollection.bundleName.equals(hapVerifyInfo.getBundleName())) { 414 String errMsg = "The bundleName parameter values are different."; 415 String solution = "Check if the bundleName is the same in different modules."; 416 LOG.error(PackingToolErrMsg.APP_FIELDS_DIFFERENT_ERROR.toString(errMsg, solution)); 417 return false; 418 } 419 if (!verifyCollection.getBundleType().equals(hapVerifyInfo.getBundleType())) { 420 String errMsg = "The bundleType parameter values are different."; 421 String solution = "Check if the bundleType is the same in different modules."; 422 LOG.error(PackingToolErrMsg.APP_FIELDS_DIFFERENT_ERROR.toString(errMsg, solution)); 423 return false; 424 } 425 if (verifyCollection.versionCode != hapVerifyInfo.getVersion().versionCode) { 426 String errMsg = "The versionCode parameter values are different."; 427 String solution = "Check if the versionCode is the same in different modules."; 428 LOG.error(PackingToolErrMsg.APP_FIELDS_DIFFERENT_ERROR.toString(errMsg, solution)); 429 return false; 430 } 431 if (!verifyCollection.releaseType.equals(hapVerifyInfo.getApiVersion().getReleaseType())) { 432 if (verifyCollection.getModuleType().equals(TYPE_SHARED) || 433 hapVerifyInfo.getModuleType().equals(TYPE_SHARED)) { 434 LOG.warning("Module: (" + verifyCollection.getModuleName() + ") and Module: (" + 435 hapVerifyInfo.getModuleName() + ") has different releaseType."); 436 } else { 437 String errMsg = "The module releaseType parameter values are different."; 438 String solution = "Check if the releaseType is the same in different modules."; 439 LOG.error(PackingToolErrMsg.APP_FIELDS_DIFFERENT_ERROR.toString(errMsg, solution)); 440 return false; 441 } 442 } 443 if (!verifyCollection.targetBundleName.equals(hapVerifyInfo.getTargetBundleName())) { 444 String errMsg = "The targetBundleName parameter values are different."; 445 String solution = "Check if the targetBundleName is the same in different modules."; 446 LOG.error(PackingToolErrMsg.APP_FIELDS_DIFFERENT_ERROR.toString(errMsg, solution)); 447 return false; 448 } 449 if (verifyCollection.targetPriority != hapVerifyInfo.getTargetPriority()) { 450 String errMsg = "The targetPriority parameter values are different."; 451 String solution = "Check if the targetPriority is the same in different modules."; 452 LOG.error(PackingToolErrMsg.APP_FIELDS_DIFFERENT_ERROR.toString(errMsg, solution)); 453 return false; 454 } 455 if (isEntryOrFeature(verifyCollection.getModuleType()) && isEntryOrFeature(hapVerifyInfo.getModuleType())) { 456 if (!verifyCollection.getMultiAppMode().equals(hapVerifyInfo.getMultiAppMode())) { 457 String errMsg = "The multiAppMode parameter values are different."; 458 String solution = "Check if the multiAppMode is the same in different modules."; 459 LOG.error(PackingToolErrMsg.APP_FIELDS_DIFFERENT_ERROR.toString(errMsg, solution)); 460 return false; 461 } 462 } 463 return true; 464 } 465 appAssetAccessGroupsIsSame(List<String> assetAccessGroups, HapVerifyInfo hapVerifyInfo)466 private static boolean appAssetAccessGroupsIsSame(List<String> assetAccessGroups, HapVerifyInfo hapVerifyInfo) { 467 if (!new HashSet<>(assetAccessGroups). 468 equals(new HashSet<>(hapVerifyInfo.getAssetAccessGroups()))){ 469 LOG.warning("input module assetAccessGroups is different."); 470 return false; 471 } 472 return true; 473 } 474 isEntryOrFeature(String moduleType)475 private static boolean isEntryOrFeature(String moduleType) { 476 return ENTRY.equals(moduleType) || FEATURE.equals(moduleType); 477 } 478 479 /** 480 * check moduleName is valid. 481 * 482 * @param hapVerifyInfos is the collection of hap infos 483 * @return true if moduleName is valid 484 * @throws BundleException Throws this exception if the json is not standard. 485 */ checkModuleNameIsValid(List<HapVerifyInfo> hapVerifyInfos)486 private static boolean checkModuleNameIsValid(List<HapVerifyInfo> hapVerifyInfos) throws BundleException { 487 for (int i = 0; i < hapVerifyInfos.size() - 1; ++i) { 488 if (hapVerifyInfos.get(i).getModuleName().isEmpty()) { 489 String cause = "The module name in the HAP infos is empty."; 490 String solution = "Ensure that each HAP file contains a valid module name field before verification."; 491 LOG.error(PackingToolErrMsg.CHECK_MODULE_NAME_INVALID.toString(cause, solution)); 492 throw new BundleException("Check moduleName is valid should not be empty."); 493 } 494 for (int j = i + 1; j < hapVerifyInfos.size(); ++j) { 495 if (hapVerifyInfos.get(i).getModuleName().equals(hapVerifyInfos.get(j).getModuleName()) && 496 !checkDuplicatedIsValid(hapVerifyInfos.get(i), hapVerifyInfos.get(j))) { 497 String cause = "Module: (" + hapVerifyInfos.get(i).getModuleName() + ") and Module: (" + 498 hapVerifyInfos.get(j).getModuleName() + ") have the same moduleName, " + 499 "please check deviceType or distroFilter/distributionFilter of the module.\n" + "Module: " + 500 hapVerifyInfos.get(i).getModuleName() + " has deviceType " + 501 hapVerifyInfos.get(i).getDeviceType() + ".\n" + "Another Module: " + 502 hapVerifyInfos.get(j).getModuleName() + " has deviceType " + 503 hapVerifyInfos.get(j).getDeviceType() + "."; 504 if (!EMPTY_STRING.equals(hapVerifyInfos.get(i).getDistroFilter().dump())) { 505 cause += "\n" + "Module: " + hapVerifyInfos.get(i).getModuleName() + " DistroFilter/DistributionFilter is " + 506 hapVerifyInfos.get(i).getDistroFilter().dump() + "."; 507 } 508 if (!EMPTY_STRING.equals(hapVerifyInfos.get(j).getDistroFilter().dump())) { 509 cause += "\n" + "Another Module: " + hapVerifyInfos.get(j).getModuleName() + 510 " DistroFilter/DistributionFilter is " + hapVerifyInfos.get(j).getDistroFilter().dump() + "."; 511 } 512 String solution = "Make sure the module name is valid and unique.\n" + 513 "Reference: " + REFERENCE_LINK + "."; 514 LOG.error(PackingToolErrMsg.CHECK_MODULE_NAME_INVALID.toString(cause, solution)); 515 return false; 516 } 517 } 518 } 519 return true; 520 } 521 522 /** 523 * check packageName is valid. 524 * 525 * @param hapVerifyInfos is the collection of hap infos 526 * @return true if moduleName is valid 527 * @throws BundleException Throws this exception if the json is not standard 528 */ checkPackageNameIsValid(List<HapVerifyInfo> hapVerifyInfos)529 private static boolean checkPackageNameIsValid(List<HapVerifyInfo> hapVerifyInfos) throws BundleException { 530 for (int i = 0; i < hapVerifyInfos.size() - 1; ++i) { 531 if (hapVerifyInfos.get(i).getPackageName().isEmpty()) { 532 continue; 533 } 534 for (int j = i + 1; j < hapVerifyInfos.size(); ++j) { 535 if (hapVerifyInfos.get(i).getPackageName().equals(hapVerifyInfos.get(j).getPackageName()) && 536 !checkDuplicatedIsValid(hapVerifyInfos.get(i), hapVerifyInfos.get(j))) { 537 String cause = "Module: (" + hapVerifyInfos.get(i).getModuleName() + ") and Module: (" + 538 hapVerifyInfos.get(j).getModuleName() + ") have the same packageName, " + 539 "please check deviceType or distroFilter of the module.\n" + "Module: " + 540 hapVerifyInfos.get(i).getModuleName() + " has deviceType " + 541 hapVerifyInfos.get(i).getDeviceType() + ".\n" + "Another Module: " + 542 hapVerifyInfos.get(j).getModuleName() + " has deviceType " + 543 hapVerifyInfos.get(j).getDeviceType() + "."; 544 if (!EMPTY_STRING.equals(hapVerifyInfos.get(i).getDistroFilter().dump())) { 545 cause += "\n" + "Module: " + hapVerifyInfos.get(i).getModuleName() + " DistroFilter is " + 546 hapVerifyInfos.get(i).getDistroFilter().dump() + "."; 547 } 548 if (!EMPTY_STRING.equals(hapVerifyInfos.get(j).getDistroFilter().dump())) { 549 cause += "\n" + "Another Module: " + hapVerifyInfos.get(j).getModuleName() + 550 " DistroFilter is " + hapVerifyInfos.get(j).getDistroFilter().dump() + "."; 551 } 552 String solution = "Make sure package name is valid and unique.\n" + 553 "Reference: " + REFERENCE_LINK + "."; 554 LOG.error(PackingToolErrMsg.CHECK_PACKAGE_NAME_INVALID.toString(cause, solution)); 555 return false; 556 } 557 } 558 } 559 return true; 560 } 561 562 /** 563 * check abilityName is valid. 564 * 565 * @param hapVerifyInfos is the collection of hap infos 566 * @return true if abilityName is valid 567 * @throws BundleException Throws this exception if the json is not standard. 568 */ checkAbilityNameIsValid(List<HapVerifyInfo> hapVerifyInfos)569 private static boolean checkAbilityNameIsValid(List<HapVerifyInfo> hapVerifyInfos) throws BundleException { 570 for (HapVerifyInfo hapVerifyInfo : hapVerifyInfos) { 571 long noDuplicatedCount = hapVerifyInfo.getAbilityNames().stream().distinct().count(); 572 if (noDuplicatedCount != hapVerifyInfo.getAbilityNames().size()) { 573 LOG.warning( 574 hapVerifyInfo.getModuleName() + " ability duplicated, please rename ability name."); 575 return false; 576 } 577 } 578 for (int i = 0; i < hapVerifyInfos.size(); ++i) { 579 if (hapVerifyInfos.get(i).getAbilityNames().isEmpty()) { 580 continue; 581 } 582 for (int j = i + 1; j < hapVerifyInfos.size(); ++j) { 583 if (!Collections.disjoint(hapVerifyInfos.get(i).getAbilityNames(), 584 hapVerifyInfos.get(j).getAbilityNames()) && 585 !checkDuplicatedIsValid(hapVerifyInfos.get(i), hapVerifyInfos.get(j))) { 586 LOG.warning("Module: (" + hapVerifyInfos.get(i).getModuleName() + ") and Module: (" + 587 hapVerifyInfos.get(j).getModuleName() + ") have the same ability name."); 588 LOG.warning("Module: " + hapVerifyInfos.get(i).getModuleName() + " has ability " 589 + hapVerifyInfos.get(i).getAbilityNames() + "."); 590 LOG.warning("Module: " + hapVerifyInfos.get(j).getModuleName() + " has ability " 591 + hapVerifyInfos.get(j).getAbilityNames() + "."); 592 LOG.warning("Solution: Make sure ability name is valid and unique."); 593 LOG.warning("Reference: " + REFERENCE_LINK + "."); 594 return false; 595 } 596 } 597 } 598 return true; 599 } 600 601 /** 602 * check targetModuleName is existed. 603 * 604 * @param hapVerifyInfos is the collection of hap infos 605 * @return true if targetModuleName is erxisted 606 * @throws BundleException Throws this exception if the json is not standard. 607 */ checkTargetModuleNameIsExisted(List<HapVerifyInfo> hapVerifyInfos)608 private static boolean checkTargetModuleNameIsExisted(List<HapVerifyInfo> hapVerifyInfos) throws BundleException { 609 List<HapVerifyInfo> internalOverlayHap = new ArrayList<>(); 610 List<HapVerifyInfo> nonOverlayHap = new ArrayList<>(); 611 List<String> targetModuleList = new ArrayList<>(); 612 List<String> moduleList = new ArrayList<>(); 613 for (HapVerifyInfo hapInfo : hapVerifyInfos) { 614 if (!hapInfo.getTargetBundleName().isEmpty()) { 615 return true; 616 } 617 if (!hapInfo.getTargetModuleName().isEmpty()) { 618 internalOverlayHap.add(hapInfo); 619 targetModuleList.add(hapInfo.getTargetModuleName()); 620 continue; 621 } 622 nonOverlayHap.add(hapInfo); 623 if (!SHARED_LIBRARY.equals(hapInfo.getModuleType())) { 624 moduleList.add(hapInfo.getModuleName()); 625 } 626 } 627 if (internalOverlayHap.isEmpty()) { 628 return true; 629 } 630 if (nonOverlayHap.isEmpty()) { 631 LOG.error(PackingToolErrMsg.TARGET_MODULE_NAME_NOT_EXIST.toString( 632 "The target modules are needed to pack with the overlay module.")); 633 return false; 634 } 635 if (!moduleList.containsAll(targetModuleList)) { 636 List<String> missingModules = new ArrayList<>(targetModuleList); 637 missingModules.removeAll(moduleList); 638 LOG.error(PackingToolErrMsg.TARGET_MODULE_NAME_NOT_EXIST.toString( 639 "The following target overlay modules are missing: " + missingModules)); 640 return false; 641 } 642 643 644 return true; 645 } 646 checkCompileSdkIsValid(List<HapVerifyInfo> hapVerifyInfos)647 private static boolean checkCompileSdkIsValid(List<HapVerifyInfo> hapVerifyInfos) throws BundleException { 648 if (hapVerifyInfos.isEmpty()) { 649 String cause = "Hap verify infos is empty"; 650 LOG.error(PackingToolErrMsg.CHECK_HAP_VERIFY_INFO_LIST_EMPTY.toString(cause)); 651 return false; 652 } 653 String compileSdkType = hapVerifyInfos.get(0).getCompileSdkType(); 654 for (HapVerifyInfo info : hapVerifyInfos) { 655 if (!compileSdkType.equals(info.getCompileSdkType())) { 656 String cause = "CompileSdkType is not the same for all modules."; 657 String solution = "Ensure that all modules has same compileSdkType."; 658 LOG.error(PackingToolErrMsg.COMPILE_SDK_TYPE_DIFFERENT.toString(cause, solution)); 659 return false; 660 } 661 } 662 return true; 663 } 664 checkProxyDataUriIsUnique(List<HapVerifyInfo> hapVerifyInfos)665 private static boolean checkProxyDataUriIsUnique(List<HapVerifyInfo> hapVerifyInfos) throws BundleException { 666 if (hapVerifyInfos.isEmpty()) { 667 String cause = "Hap verify infos is empty"; 668 LOG.error(PackingToolErrMsg.CHECK_HAP_VERIFY_INFO_LIST_EMPTY.toString(cause)); 669 return false; 670 } 671 Set<String> uriSet = new HashSet<>(); 672 for (HapVerifyInfo info : hapVerifyInfos) { 673 for (String uri : info.getProxyDataUris()) { 674 if (uriSet.contains(uri)) { 675 String moduleName = info.getModuleName(); 676 String cause = "The uri(" + uri + ") in proxyData settings of Module(" + moduleName + 677 ") is duplicated."; 678 String solution = "Ensure that the uri in proxyData is unique across different modules."; 679 LOG.error(PackingToolErrMsg.PROXY_DATA_URI_NOT_UNIQUE.toString(cause, solution)); 680 return false; 681 } else { 682 uriSet.add(uri); 683 } 684 } 685 } 686 return true; 687 } 688 689 /** 690 * check entry is valid. 691 * 692 * @param hapVerifyInfos is the collection of hap infos 693 * @return true if entry is valid 694 * @throws BundleException Throws this exception if the json is not standard. 695 */ checkEntryIsValid(List<HapVerifyInfo> hapVerifyInfos)696 private static boolean checkEntryIsValid(List<HapVerifyInfo> hapVerifyInfos) throws BundleException { 697 List<HapVerifyInfo> entryHapVerifyInfos = new ArrayList<>(); 698 List<HapVerifyInfo> featureHapVerifyInfos = new ArrayList<>(); 699 for (HapVerifyInfo hapVerifyInfo : hapVerifyInfos) { 700 if (ENTRY.equals(hapVerifyInfo.getModuleType())) { 701 entryHapVerifyInfos.add(hapVerifyInfo); 702 } else if (FEATURE.equals(hapVerifyInfo.getModuleType())) { 703 featureHapVerifyInfos.add(hapVerifyInfo); 704 } else if (!SHARED_LIBRARY.equals(hapVerifyInfo.getModuleType())) { 705 LOG.warning("Input wrong type module."); 706 } 707 } 708 if (hapVerifyInfos.isEmpty() 709 || (entryHapVerifyInfos.isEmpty() && (!SHARED_LIBRARY.equals(hapVerifyInfos.get(0).getBundleType())))) { 710 LOG.warning("Warning: has no entry module."); 711 } 712 713 for (int i = 0; i < entryHapVerifyInfos.size() - 1; ++i) { 714 for (int j = i + 1; j < entryHapVerifyInfos.size(); ++j) { 715 if (!checkDuplicatedIsValid(entryHapVerifyInfos.get(i), entryHapVerifyInfos.get(j))) { 716 String cause = "Module(" + entryHapVerifyInfos.get(i).getModuleName() + ") and Module(" + 717 entryHapVerifyInfos.get(j).getModuleName() + ") are entry, " + 718 "please check deviceType or distroFilter of the module.\n" + "Module: " + 719 entryHapVerifyInfos.get(i).getModuleName() + " has deviceType " + 720 entryHapVerifyInfos.get(i).getDeviceType() + ".\n" + "Another Module: " + 721 entryHapVerifyInfos.get(j).getModuleName() + " has deviceType " + 722 entryHapVerifyInfos.get(j).getDeviceType() + "."; 723 724 if (!EMPTY_STRING.equals(entryHapVerifyInfos.get(i).getDistroFilter().dump())) { 725 cause += "\n" + "Module: " + entryHapVerifyInfos.get(i).getModuleName() + " DistroFilter is " + 726 entryHapVerifyInfos.get(i).getDistroFilter().dump() + "."; 727 } 728 if (!EMPTY_STRING.equals(entryHapVerifyInfos.get(j).getDistroFilter().dump())) { 729 cause += "\n" + "Another Module: " + entryHapVerifyInfos.get(j).getModuleName() + 730 " DistroFilter is " + entryHapVerifyInfos.get(j).getDistroFilter().dump() + "."; 731 } 732 733 String solution = "Make sure the entry module is valid and unique, and the HAP uniqueness " + 734 "check logic passes.\nReference: " + REFERENCE_LINK + "."; 735 LOG.error(PackingToolErrMsg.CHECK_ENTRY_INVALID.toString(cause, solution)); 736 return false; 737 } 738 } 739 } 740 741 Map<String, List<HapVerifyInfo>> deviceHap = classifyEntry(entryHapVerifyInfos); 742 for (HapVerifyInfo hapVerifyInfo : featureHapVerifyInfos) { 743 if (!checkFeature(hapVerifyInfo, deviceHap)) { 744 LOG.warning(hapVerifyInfo.getModuleName() + " can not be covered by entry."); 745 } 746 } 747 748 return true; 749 } 750 751 /** 752 * check if name duplicated, name is valid. 753 * 754 * @param hapVerifyInfoLeft is one hapVerifyInfo 755 * @param hapVerifyInfoRight is another hapVerifyInfo that name is duplicated with hapVerifyInfoLeft 756 * @return true if moduleName is valid 757 * @throws BundleException Throws this exception if the json is not standard. 758 */ checkDuplicatedIsValid(HapVerifyInfo hapVerifyInfoLeft, HapVerifyInfo hapVerifyInfoRight)759 private static boolean checkDuplicatedIsValid(HapVerifyInfo hapVerifyInfoLeft, HapVerifyInfo hapVerifyInfoRight) 760 throws BundleException { 761 // check deviceType 762 if (Collections.disjoint(hapVerifyInfoLeft.getDeviceType(), hapVerifyInfoRight.getDeviceType())) { 763 return true; 764 } 765 // check distroFilter 766 if (checkDistroFilterDisjoint(hapVerifyInfoLeft.getDistroFilter(), hapVerifyInfoRight.getDistroFilter(), 767 hapVerifyInfoLeft.getModuleName(), hapVerifyInfoRight.getModuleName())) { 768 return true; 769 } 770 771 return false; 772 } 773 774 /** 775 * check two distroFilter is disjoint. 776 * 777 * @param distroFilterLeft is one distroFilter 778 * @param distroFilterRight is another distroFilter will be checked 779 * @param moduleNameLeft is the moduleName associated with distroFilterLeft 780 * @param moduleNameRight is the moduleName associated with distroFilterRight 781 * @return true if two distroFilter is disjoint 782 * @throws BundleException Throws this exception if the json is not standard. 783 */ checkDistroFilterDisjoint(DistroFilter distroFilterLeft, DistroFilter distroFilterRight, String moduleNameLeft, String moduleNameRight)784 private static boolean checkDistroFilterDisjoint(DistroFilter distroFilterLeft, DistroFilter distroFilterRight, 785 String moduleNameLeft, String moduleNameRight) throws BundleException { 786 if (distroFilterLeft == null || distroFilterRight == null) { 787 return false; 788 } 789 if (distroFilterLeft.apiVersion != null && distroFilterRight.apiVersion != null) { 790 if (checkPolicyValueDisjoint(distroFilterLeft.apiVersion.policy, distroFilterLeft.apiVersion.value, 791 distroFilterRight.apiVersion.policy, distroFilterRight.apiVersion.value, 792 moduleNameLeft, moduleNameRight)) { 793 return true; 794 } 795 } 796 if (distroFilterLeft.screenShape != null && distroFilterRight.screenShape != null) { 797 if (checkPolicyValueDisjoint(distroFilterLeft.screenShape.policy, distroFilterLeft.screenShape.value, 798 distroFilterRight.screenShape.policy, distroFilterRight.screenShape.value, 799 moduleNameLeft, moduleNameRight)) { 800 return true; 801 } 802 } 803 if (distroFilterLeft.screenDensity != null && distroFilterRight.screenDensity != null) { 804 if (checkPolicyValueDisjoint(distroFilterLeft.screenDensity.policy, distroFilterLeft.screenDensity.value, 805 distroFilterRight.screenDensity.policy, distroFilterRight.screenDensity.value, 806 moduleNameLeft, moduleNameRight)) { 807 return true; 808 } 809 } 810 if (distroFilterLeft.screenWindow != null && distroFilterRight.screenWindow != null) { 811 if (checkPolicyValueDisjoint(distroFilterLeft.screenWindow.policy, distroFilterLeft.screenWindow.value, 812 distroFilterRight.screenWindow.policy, distroFilterRight.screenWindow.value, 813 moduleNameLeft, moduleNameRight)) { 814 return true; 815 } 816 } 817 if (distroFilterLeft.countryCode != null && distroFilterRight.countryCode != null) { 818 if (checkPolicyValueDisjoint(distroFilterLeft.countryCode.policy, distroFilterLeft.countryCode.value, 819 distroFilterRight.countryCode.policy, distroFilterRight.countryCode.value, 820 moduleNameLeft, moduleNameRight)) { 821 return true; 822 } 823 } 824 return false; 825 } 826 827 /** 828 * check two distroFilter variable is disjoint. 829 * 830 * @param policyLeft is one distroFilter variable policy 831 * @param valueLeft is one distroFilter variable value 832 * @param policyRight is another distroFilter variable policy 833 * @param valueRight is another distroFilter variable value 834 * @return true if two variable is disjoint 835 * @throws BundleException Throws this exception if the json is not standard. 836 */ checkPolicyValueDisjoint(String policyLeft, List<String> valueLeft, String policyRight, List<String> valueRight, String moduleNameLeft, String moduleNameRight)837 private static boolean checkPolicyValueDisjoint(String policyLeft, List<String> valueLeft, String policyRight, 838 List<String> valueRight, String moduleNameLeft, String moduleNameRight) throws BundleException { 839 if (valueLeft == null || valueRight == null) { 840 String errMsg = "The variable 'value' in the distributionFilter setting is empty."; 841 String solution = "Ensure that all distributionFilter file and filter settings has 'value' setting."; 842 solution += "Module " + moduleNameLeft + " and " + moduleNameRight + " can be checked in priority."; 843 LOG.error(PackingToolErrMsg.CHECK_POLICY_DISJOINT_ERROR.toString(errMsg, solution)); 844 throw new BundleException("Check policy value disjoint value should not empty."); 845 } 846 if (EXCLUDE.equals(policyLeft) && INCLUDE.equals(policyRight)) { 847 if (valueRight.isEmpty() || valueLeft.containsAll(valueRight)) { 848 return true; 849 } 850 } else if (INCLUDE.equals(policyLeft) && INCLUDE.equals(policyRight)) { 851 if (Collections.disjoint(valueLeft, valueRight)) { 852 return true; 853 } 854 } else if (INCLUDE.equals(policyLeft) && EXCLUDE.equals(policyRight)) { 855 if (valueLeft.isEmpty() || valueRight.containsAll(valueLeft)) { 856 return true; 857 } 858 } else if (EXCLUDE.equals(policyLeft) && EXCLUDE.equals(policyRight)) { 859 return false; 860 } else { 861 String errMsg = "Check distributionFilter 'policy' setting is invalid."; 862 String solution = "Ensure all distributionFilter file and filter settings 'policy' value must " + 863 "'include' or 'exclude'.\n"; 864 solution += "Module " + moduleNameLeft + " and " + moduleNameRight + " can be checked in priority."; 865 LOG.error(PackingToolErrMsg.CHECK_POLICY_DISJOINT_ERROR.toString(errMsg, solution)); 866 throw new BundleException("Check policy value disjoint input policy is invalid."); 867 } 868 return false; 869 } 870 871 /** 872 * classify entry haps by deviceType. 873 * 874 * @param entryHapVerifyInfos is the list od entry hapVerifyInfos 875 * @return deviceHap that is classfied 876 */ classifyEntry(List<HapVerifyInfo> entryHapVerifyInfos)877 private static Map<String, List<HapVerifyInfo>> classifyEntry(List<HapVerifyInfo> entryHapVerifyInfos) { 878 Map<String, List<HapVerifyInfo>> deviceHaps = new HashMap<>(); 879 for (HapVerifyInfo hapVerifyInfo : entryHapVerifyInfos) { 880 for (String device : hapVerifyInfo.getDeviceType()) { 881 if (deviceHaps.containsKey(device)) { 882 deviceHaps.get(device).add(hapVerifyInfo); 883 } else { 884 deviceHaps.put(device, new ArrayList<HapVerifyInfo>()); 885 deviceHaps.get(device).add(hapVerifyInfo); 886 } 887 } 888 } 889 return deviceHaps; 890 } 891 892 /** 893 * check feature is valid, deviceType is subset of entry, distroFilter is subset of entry 894 * 895 * @param featureHap the feature hap will be checked 896 * @param deviceHap is the haps that feature matched 897 * @return feature is valid 898 * @throws BundleException when input distroFilter is invalid 899 */ checkFeature(HapVerifyInfo featureHap, Map<String, List<HapVerifyInfo>> deviceHap)900 private static boolean checkFeature(HapVerifyInfo featureHap, Map<String, List<HapVerifyInfo>> deviceHap) 901 throws BundleException { 902 // check deviceType and distroFilter 903 for (String device : featureHap.getDeviceType()) { 904 if (!deviceHap.containsKey(device)) { 905 LOG.warning("Warning: device " + device + " has feature but has no entry."); 906 return false; 907 } 908 List<HapVerifyInfo> entryHaps = deviceHap.get(device); 909 if (!checkFeatureDistroFilter(featureHap, entryHaps)) { 910 LOG.warning(featureHap.getModuleName() + 911 "'s distroFilter has not covered by entry."); 912 if (!EMPTY_STRING.equals(featureHap.getDistroFilter().dump())) { 913 LOG.warning(featureHap.getModuleName() + " has " + 914 featureHap.getDistroFilter().dump() + "."); 915 } 916 return false; 917 } 918 } 919 return true; 920 } 921 922 /** 923 * check feature is valid, deviceType is subset of entry, distroFilter is subset of entry 924 * 925 * @param featureHap the feature hap will be checked 926 * @param entryHaps is the haps that feature matched 927 * @return feature is valid 928 * @throws BundleException when input policy in invalid 929 */ checkFeatureDistroFilter(HapVerifyInfo featureHap, List<HapVerifyInfo> entryHaps)930 private static boolean checkFeatureDistroFilter(HapVerifyInfo featureHap, List<HapVerifyInfo> entryHaps) 931 throws BundleException { 932 if (featureHap.getDistroFilter() == null) { 933 if (checkApiVersionCovered(null, entryHaps) 934 && checkScreenShapeCovered(null, entryHaps) 935 && checkScreenWindowCovered(null, entryHaps) 936 && checkScreenDensityCovered(null, entryHaps) 937 && checkCountryCodeCovered(null, entryHaps)) { 938 return true; 939 } else { 940 return false; 941 } 942 } 943 if (!checkApiVersionCovered(featureHap.getDistroFilter().apiVersion, entryHaps)) { 944 LOG.warning("HapVerify::checkFeatureDistroFilter failed, apiVersion is not covered."); 945 return false; 946 } 947 if (!checkScreenShapeCovered(featureHap.getDistroFilter().screenShape, entryHaps)) { 948 LOG.warning("HapVerify::checkFeatureDistroFilter failed, screenShape is not covered."); 949 return false; 950 } 951 if (!checkScreenWindowCovered(featureHap.getDistroFilter().screenWindow, entryHaps)) { 952 LOG.warning("HapVerify::checkFeatureDistroFilter failed, screenWindow is not covered."); 953 return false; 954 } 955 if (!checkScreenDensityCovered(featureHap.getDistroFilter().screenDensity, entryHaps)) { 956 LOG.warning("HapVerify::checkFeatureDistroFilter failed, screenDensity is not covered."); 957 return false; 958 } 959 if (!checkCountryCodeCovered(featureHap.getDistroFilter().countryCode, entryHaps)) { 960 LOG.warning("HapVerify::checkFeatureDistroFilter failed, countryCode is not covered."); 961 return false; 962 } 963 return true; 964 } 965 966 /** 967 * check feature apiVersion is subset of entry apiVersion 968 * 969 * @param apiVersion is the apiVersion of feature hap 970 * @param entryHaps is the haps that feature matched 971 * @return apiVersion is valid 972 * @throws BundleException when input policy is invalid 973 */ checkApiVersionCovered(ApiVersion apiVersion, List<HapVerifyInfo> entryHaps)974 private static boolean checkApiVersionCovered(ApiVersion apiVersion, List<HapVerifyInfo> entryHaps) 975 throws BundleException { 976 List<String> include = null; 977 List<String> exclude = null; 978 for (HapVerifyInfo hapVerifyInfo : entryHaps) { 979 if (hapVerifyInfo.getDistroFilter() == null || hapVerifyInfo.getDistroFilter().apiVersion == null) { 980 return true; 981 } 982 if (hapVerifyInfo.getDistroFilter().apiVersion.policy == null) { 983 LOG.error(PackingToolErrMsg.CHECK_FEATURE_DISTRO_FILTER_INVALID.toString( 984 "Entry module(" + hapVerifyInfo.getModuleName() + ") apiVersion policy is null.")); 985 return false; 986 } 987 if (INCLUDE.equals(hapVerifyInfo.getDistroFilter().apiVersion.policy)) { 988 if (include == null) { 989 include = new ArrayList<>(); 990 } 991 // take collection of two include value 992 include.addAll(hapVerifyInfo.getDistroFilter().apiVersion.value); 993 } else if (EXCLUDE.equals(hapVerifyInfo.getDistroFilter().apiVersion.policy)) { 994 if (exclude == null) { 995 exclude = new ArrayList<>(); 996 } 997 // take intersection of two exclude value 998 exclude = Stream.of(exclude, hapVerifyInfo.getDistroFilter().apiVersion.value). 999 flatMap(Collection::stream).distinct().collect(Collectors.toList()); 1000 } else { 1001 LOG.error(PackingToolErrMsg.CHECK_FEATURE_DISTRO_FILTER_INVALID.toString( 1002 "Entry module(" + hapVerifyInfo.getModuleName() + ") apiVersion policy '" + 1003 hapVerifyInfo.getDistroFilter().apiVersion.policy + "' is invalid.")); 1004 throw new BundleException("Check apiVersion covered input policy is invalid."); 1005 } 1006 } 1007 if (include != null) { 1008 include = include.stream().distinct().collect(Collectors.toList()); 1009 } 1010 if (exclude != null) { 1011 exclude = exclude.stream().distinct().collect(Collectors.toList()); 1012 } 1013 if (apiVersion == null) { 1014 return checkEntryPolicyValueCoverAll(include, exclude); 1015 } 1016 return checkPolicyValueCovered(apiVersion.policy, apiVersion.value, include, exclude); 1017 } 1018 1019 /** 1020 * check feature screenShape is subset of entry screenShape 1021 * 1022 * @param screenShape is the screenShape of feature hap 1023 * @param entryHaps is the haps that feature matched 1024 * @return screenShape is valid 1025 * @throws BundleException when input policy is invalid 1026 */ checkScreenShapeCovered(ScreenShape screenShape, List<HapVerifyInfo> entryHaps)1027 private static boolean checkScreenShapeCovered(ScreenShape screenShape, List<HapVerifyInfo> entryHaps) 1028 throws BundleException { 1029 List<String> include = null; 1030 List<String> exclude = null; 1031 for (HapVerifyInfo hapVerifyInfo : entryHaps) { 1032 if (hapVerifyInfo.getDistroFilter() == null || hapVerifyInfo.getDistroFilter().screenShape == null) { 1033 return true; 1034 } 1035 if (hapVerifyInfo.getDistroFilter().screenShape.policy == null) { 1036 LOG.error(PackingToolErrMsg.CHECK_FEATURE_DISTRO_FILTER_INVALID.toString( 1037 "Entry module(" + hapVerifyInfo.getModuleName() + ") screenShape policy is null.")); 1038 return false; 1039 } 1040 if (INCLUDE.equals(hapVerifyInfo.getDistroFilter().screenShape.policy)) { 1041 if (include == null) { 1042 include = new ArrayList<>(); 1043 } 1044 include.addAll(hapVerifyInfo.getDistroFilter().screenShape.value); 1045 } else if (EXCLUDE.equals(hapVerifyInfo.getDistroFilter().screenShape.policy)) { 1046 if (exclude == null) { 1047 exclude = new ArrayList<>(); 1048 } 1049 exclude = Stream.of(exclude, hapVerifyInfo.getDistroFilter().screenShape.value). 1050 flatMap(Collection::stream).distinct().collect(Collectors.toList()); 1051 } else { 1052 LOG.error(PackingToolErrMsg.CHECK_FEATURE_DISTRO_FILTER_INVALID.toString( 1053 "Entry module(" + hapVerifyInfo.getModuleName() + ") screenShape policy '" + 1054 hapVerifyInfo.getDistroFilter().screenShape.policy + "' is invalid.")); 1055 throw new BundleException("Check screenShape covered input policy is invalid."); 1056 } 1057 } 1058 if (include != null) { 1059 include = include.stream().distinct().collect(Collectors.toList()); 1060 } 1061 if (exclude != null) { 1062 exclude = exclude.stream().distinct().collect(Collectors.toList()); 1063 } 1064 if (screenShape == null) { 1065 return checkEntryPolicyValueCoverAll(include, exclude); 1066 } 1067 return checkPolicyValueCovered(screenShape.policy, screenShape.value, include, exclude); 1068 } 1069 1070 /** 1071 * check feature screenWindow is subset of entry screenWindow 1072 * 1073 * @param screenWindow is the screenWindow of feature hap 1074 * @param entryHaps is the haps that feature matched 1075 * @return screenWindow is valid 1076 * @throws BundleException when input policy is invalid 1077 */ checkScreenWindowCovered(ScreenWindow screenWindow, List<HapVerifyInfo> entryHaps)1078 private static boolean checkScreenWindowCovered(ScreenWindow screenWindow, List<HapVerifyInfo> entryHaps) 1079 throws BundleException { 1080 List<String> include = null; 1081 List<String> exclude = null; 1082 for (HapVerifyInfo hapVerifyInfo : entryHaps) { 1083 if (hapVerifyInfo.getDistroFilter() == null || hapVerifyInfo.getDistroFilter().screenWindow == null) { 1084 return true; 1085 } 1086 if (hapVerifyInfo.getDistroFilter().screenWindow.policy == null) { 1087 LOG.error(PackingToolErrMsg.CHECK_FEATURE_DISTRO_FILTER_INVALID.toString( 1088 "Entry module(" + hapVerifyInfo.getModuleName() + ") screenWindow policy is null.")); 1089 return false; 1090 } 1091 if (INCLUDE.equals(hapVerifyInfo.getDistroFilter().screenWindow.policy)) { 1092 if (include == null) { 1093 include = new ArrayList<>(); 1094 } 1095 include.addAll(hapVerifyInfo.getDistroFilter().screenWindow.value); 1096 } else if (EXCLUDE.equals(hapVerifyInfo.getDistroFilter().screenWindow.policy)) { 1097 if (exclude == null) { 1098 exclude = new ArrayList<>(); 1099 } 1100 exclude = Stream.of(exclude, hapVerifyInfo.getDistroFilter().screenWindow.value). 1101 flatMap(Collection::stream).distinct().collect(Collectors.toList()); 1102 } else { 1103 LOG.error(PackingToolErrMsg.CHECK_FEATURE_DISTRO_FILTER_INVALID.toString( 1104 "Entry module(" + hapVerifyInfo.getModuleName() + ") screenWindow policy '" + 1105 hapVerifyInfo.getDistroFilter().screenWindow.policy + "' is invalid.")); 1106 throw new BundleException("Check screenWindow covered input policy is invalid."); 1107 } 1108 } 1109 if (include != null) { 1110 include = include.stream().distinct().collect(Collectors.toList()); 1111 } 1112 if (exclude != null) { 1113 exclude = exclude.stream().distinct().collect(Collectors.toList()); 1114 } 1115 if (screenWindow == null) { 1116 return checkEntryPolicyValueCoverAll(include, exclude); 1117 } 1118 return checkPolicyValueCovered(screenWindow.policy, screenWindow.value, include, exclude); 1119 } 1120 1121 /** 1122 * check feature screenDensity is subset of entry screenDensity 1123 * 1124 * @param screenDensity is the screenDensity of feature hap 1125 * @param entryHaps is the haps that feature matched 1126 * @return screenDensity is valid 1127 * @throws BundleException when input policy is invalid 1128 */ checkScreenDensityCovered(ScreenDensity screenDensity, List<HapVerifyInfo> entryHaps)1129 private static boolean checkScreenDensityCovered(ScreenDensity screenDensity, List<HapVerifyInfo> entryHaps) 1130 throws BundleException { 1131 List<String> include = null; 1132 List<String> exclude = null; 1133 for (HapVerifyInfo hapVerifyInfo : entryHaps) { 1134 if (hapVerifyInfo.getDistroFilter() == null || hapVerifyInfo.getDistroFilter().screenDensity == null) { 1135 return true; 1136 } 1137 if (hapVerifyInfo.getDistroFilter().screenDensity.policy == null) { 1138 LOG.error(PackingToolErrMsg.CHECK_FEATURE_DISTRO_FILTER_INVALID.toString( 1139 "Entry module(" + hapVerifyInfo.getModuleName() + ") screenDensity policy is null.")); 1140 return false; 1141 } 1142 if (INCLUDE.equals(hapVerifyInfo.getDistroFilter().screenDensity.policy)) { 1143 if (include == null) { 1144 include = new ArrayList<>(); 1145 } 1146 include.addAll(hapVerifyInfo.getDistroFilter().screenDensity.value); 1147 } else if (EXCLUDE.equals(hapVerifyInfo.getDistroFilter().screenDensity.policy)) { 1148 if (exclude == null) { 1149 exclude = new ArrayList<>(); 1150 } 1151 exclude = Stream.of(exclude, hapVerifyInfo.getDistroFilter().screenDensity.value). 1152 flatMap(Collection::stream).distinct().collect(Collectors.toList()); 1153 } else { 1154 LOG.error(PackingToolErrMsg.CHECK_FEATURE_DISTRO_FILTER_INVALID.toString( 1155 "Entry module(" + hapVerifyInfo.getModuleName() + ") screenDensity policy '" + 1156 hapVerifyInfo.getDistroFilter().screenDensity.policy + "' is invalid.")); 1157 throw new BundleException("Check screenDensity covered input policy is invalid."); 1158 } 1159 } 1160 if (include != null) { 1161 include = include.stream().distinct().collect(Collectors.toList()); 1162 } 1163 if (exclude != null) { 1164 exclude = exclude.stream().distinct().collect(Collectors.toList()); 1165 } 1166 if (screenDensity == null) { 1167 return checkEntryPolicyValueCoverAll(include, exclude); 1168 } 1169 return checkPolicyValueCovered(screenDensity.policy, screenDensity.value, include, exclude); 1170 } 1171 1172 /** 1173 * check feature countryCode is subset of entry countryCode 1174 * 1175 * @param countryCode is the countryCode of feature hap 1176 * @param entryHaps is the haps that feature matched 1177 * @return countryCode is valid 1178 * @throws BundleException when input policy is invalid 1179 */ checkCountryCodeCovered(CountryCode countryCode, List<HapVerifyInfo> entryHaps)1180 private static boolean checkCountryCodeCovered(CountryCode countryCode, List<HapVerifyInfo> entryHaps) 1181 throws BundleException { 1182 List<String> include = null; 1183 List<String> exclude = null; 1184 for (HapVerifyInfo hapVerifyInfo : entryHaps) { 1185 if (hapVerifyInfo.getDistroFilter() == null || hapVerifyInfo.getDistroFilter().countryCode == null) { 1186 return true; 1187 } 1188 if (hapVerifyInfo.getDistroFilter().countryCode.policy == null) { 1189 LOG.error(PackingToolErrMsg.CHECK_FEATURE_DISTRO_FILTER_INVALID.toString( 1190 "Entry module(" + hapVerifyInfo.getModuleName() + ") countryCode policy is null.")); 1191 return false; 1192 } 1193 if (INCLUDE.equals(hapVerifyInfo.getDistroFilter().countryCode.policy)) { 1194 if (include == null) { 1195 include = new ArrayList<>(); 1196 } 1197 include.addAll(hapVerifyInfo.getDistroFilter().countryCode.value); 1198 } else if (EXCLUDE.equals(hapVerifyInfo.getDistroFilter().countryCode.policy)) { 1199 if (exclude == null) { 1200 exclude = new ArrayList<>(); 1201 } 1202 exclude = Stream.of(exclude, hapVerifyInfo.getDistroFilter().countryCode.value). 1203 flatMap(Collection::stream).distinct().collect(Collectors.toList()); 1204 } else { 1205 LOG.error(PackingToolErrMsg.CHECK_FEATURE_DISTRO_FILTER_INVALID.toString( 1206 "Entry module(" + hapVerifyInfo.getModuleName() + ") countryCode policy '" + 1207 hapVerifyInfo.getDistroFilter().countryCode.policy + "' is invalid.")); 1208 throw new BundleException("Check countryCode covered input policy is invalid."); 1209 } 1210 } 1211 if (include != null) { 1212 include = include.stream().distinct().collect(Collectors.toList()); 1213 } 1214 if (exclude != null) { 1215 exclude = exclude.stream().distinct().collect(Collectors.toList()); 1216 } 1217 if (countryCode == null) { 1218 return checkEntryPolicyValueCoverAll(include, exclude); 1219 } 1220 return checkPolicyValueCovered(countryCode.policy, countryCode.value, include, exclude); 1221 } 1222 1223 /** 1224 * check entry policy value covered all value 1225 * 1226 * @param include is the collection of included value 1227 * @param exclude is the collection of excluded value 1228 * @return entry policy value covered all value 1229 */ checkEntryPolicyValueCoverAll(List<String> include, List<String> exclude)1230 private static boolean checkEntryPolicyValueCoverAll(List<String> include, List<String> exclude) { 1231 if (include == null) { 1232 return exclude == null || exclude.isEmpty(); 1233 } 1234 return exclude != null && include.containsAll(exclude); 1235 } 1236 1237 /** 1238 * check entry policy value covered all value 1239 * 1240 * @param include is the collection of included value 1241 * @param exclude is the collection of excluded value 1242 * @return entry policy value covered all value 1243 */ checkPolicyValueCovered( String policy, List<String> value, List<String> include, List<String> exclude)1244 private static boolean checkPolicyValueCovered( 1245 String policy, List<String> value, List<String> include, List<String> exclude) { 1246 if (value == null || policy == null) { 1247 LOG.warning("checkPolicyValueCovered::failed covered value or policy is null."); 1248 return false; 1249 } 1250 if (EXCLUDE.equals(policy)) { 1251 return checkCoveredExcludePolicyValue(value, include, exclude); 1252 } else if (INCLUDE.equals(policy)) { 1253 return checkCoveredIncludePolicyValue(value, include, exclude); 1254 } else { 1255 return false; 1256 } 1257 } 1258 1259 /** 1260 * check entry covered feature value when feature policy is exclude 1261 * 1262 * @param value is the feature value 1263 * @param include is the included value of entry 1264 * @param exclude is the excluded value of entry 1265 * @return entry policy value covered feature value 1266 */ checkCoveredExcludePolicyValue( List<String> value, List<String> include, List<String> exclude)1267 private static boolean checkCoveredExcludePolicyValue( 1268 List<String> value, List<String> include, List<String> exclude) { 1269 if (include == null) { 1270 return exclude == null || value.containsAll(exclude); 1271 } 1272 if (exclude == null) { 1273 return false; 1274 } 1275 exclude.removeAll(include); 1276 return value.containsAll(exclude); 1277 } 1278 1279 /** 1280 * check entry covered feature value when feature policy is include 1281 * 1282 * @param value is the feature value 1283 * @param include is the included value of entry 1284 * @param exclude is the excluded value of entry 1285 * @return entry policy value covered feature value 1286 */ checkCoveredIncludePolicyValue( List<String> value, List<String> include, List<String> exclude)1287 private static boolean checkCoveredIncludePolicyValue( 1288 List<String> value, List<String> include, List<String> exclude) { 1289 if (include == null) { 1290 return exclude == null || Collections.disjoint(exclude, value); 1291 } 1292 if (exclude == null) { 1293 return include.containsAll(value); 1294 } 1295 exclude.removeAll(include); 1296 return Collections.disjoint(exclude, value); 1297 } 1298 1299 /** 1300 * check dependency is valid 1301 * 1302 * @param allHapVerifyInfo is all input hap module 1303 * @return true if dependency is valid 1304 * @throws BundleException when input hapVerify is invalid 1305 */ checkDependencyIsValid(List<HapVerifyInfo> allHapVerifyInfo)1306 private static boolean checkDependencyIsValid(List<HapVerifyInfo> allHapVerifyInfo) throws BundleException { 1307 if (allHapVerifyInfo.isEmpty()) { 1308 String cause = "Hap verify infos is empty"; 1309 LOG.error(PackingToolErrMsg.CHECK_HAP_VERIFY_INFO_LIST_EMPTY.toString(cause)); 1310 throw new BundleException("HapVerify::checkDependencyIsValid failed, input none hap."); 1311 } 1312 boolean isInstallationFree = allHapVerifyInfo.get(0).isInstallationFree(); 1313 for (HapVerifyInfo hapVerifyInfo : allHapVerifyInfo) { 1314 if (isInstallationFree != hapVerifyInfo.isInstallationFree()) { 1315 String cause = "The installationFree value is different in input hap."; 1316 String solution = "Ensure that the installationFree field is same for all hap."; 1317 LOG.error(PackingToolErrMsg.CHECK_DEPENDENCY_INVALID.toString(cause, solution)); 1318 return false; 1319 } 1320 } 1321 for (HapVerifyInfo hapVerifyInfo : allHapVerifyInfo) { 1322 List<HapVerifyInfo> dependencyList = new ArrayList<>(); 1323 dependencyList.add(hapVerifyInfo); 1324 if (!dfsTraverseDependency(hapVerifyInfo, allHapVerifyInfo, dependencyList)) { 1325 return false; 1326 } 1327 dependencyList.remove(dependencyList.size() - 1); 1328 } 1329 return true; 1330 } 1331 1332 /** 1333 * DFS traverse dependency, and check dependency list is valid 1334 * 1335 * @param hapVerifyInfo the first node of dependency list 1336 * @param allHapVerifyInfo is all input hap module 1337 * @param dependencyList is the current dependency list 1338 * @return true if dependency list is valid 1339 * @throws BundleException when input hapVerifyInfo is invalid 1340 */ dfsTraverseDependency( HapVerifyInfo hapVerifyInfo, List<HapVerifyInfo> allHapVerifyInfo, List<HapVerifyInfo> dependencyList)1341 private static boolean dfsTraverseDependency( 1342 HapVerifyInfo hapVerifyInfo, List<HapVerifyInfo> allHapVerifyInfo, 1343 List<HapVerifyInfo> dependencyList) throws BundleException { 1344 // check dependencyList is valid 1345 if (checkDependencyListCirculate(dependencyList)) { 1346 return false; 1347 } 1348 for (DependencyItem dependency : hapVerifyInfo.getDependencyItemList()) { 1349 if (!dependency.getBundleName().equals(hapVerifyInfo.getBundleName())) { 1350 continue; 1351 } 1352 if (!checkDependencyInFileList(dependency, allHapVerifyInfo)) { 1353 LOG.warning("Dependent module " + dependency.getModuleName() + " missing, check the HSP-Path."); 1354 continue; 1355 } 1356 List<HapVerifyInfo> layerDependencyList = getLayerDependency( 1357 dependency.getModuleName(), hapVerifyInfo, allHapVerifyInfo); 1358 for (HapVerifyInfo item : layerDependencyList) { 1359 if (FEATURE.equals(item.getModuleType()) || ENTRY.equals(item.getModuleType())) { 1360 String cause = 1361 "HAP or HSP cannot depend on the feature or entry module. The dependeny module(" + 1362 item.getModuleName() + ") type is feature or entry."; 1363 String solution = "Remove module dependencies on module (" + item.getModuleName() + 1364 ") to ensure the dependency list is valid."; 1365 LOG.error(PackingToolErrMsg.DEPENDENCY_LIST_INVALID.toString(cause, solution)); 1366 return false; 1367 } 1368 dependencyList.add(item); 1369 if (!dfsTraverseDependency(item, allHapVerifyInfo, dependencyList)) { 1370 return false; 1371 } 1372 dependencyList.remove(dependencyList.size() - 1); 1373 } 1374 } 1375 return true; 1376 } 1377 checkDependencyInFileList( DependencyItem dependencyItem, List<HapVerifyInfo> allHapVerifyInfo)1378 private static boolean checkDependencyInFileList( 1379 DependencyItem dependencyItem, List<HapVerifyInfo> allHapVerifyInfo) { 1380 String moduleName = dependencyItem.getModuleName(); 1381 String bundleName = dependencyItem.getBundleName(); 1382 for (HapVerifyInfo hapVerifyInfo : allHapVerifyInfo) { 1383 if (moduleName.equals(hapVerifyInfo.getModuleName()) && bundleName.equals(hapVerifyInfo.getBundleName())) { 1384 return true; 1385 } 1386 } 1387 return false; 1388 } 1389 1390 /** 1391 * get one layer dependency module by moduleName 1392 * 1393 * @param moduleName is the dependency moduleName of module 1394 * @param hapVerifyInfo the first node of dependency list 1395 * @param allHapVerifyInfo is all input hap module 1396 * @return a layer dependency list 1397 */ getLayerDependency( String moduleName, HapVerifyInfo hapVerifyInfo, List<HapVerifyInfo> allHapVerifyInfo)1398 private static List<HapVerifyInfo> getLayerDependency( 1399 String moduleName, HapVerifyInfo hapVerifyInfo, List<HapVerifyInfo> allHapVerifyInfo) throws BundleException { 1400 List<HapVerifyInfo> layerHapVerifyInfoList = new ArrayList<>(); 1401 for (HapVerifyInfo item : allHapVerifyInfo) { 1402 if (item.getModuleName().equals(moduleName) && checkModuleJoint(hapVerifyInfo, item)) { 1403 layerHapVerifyInfoList.add(item); 1404 } 1405 } 1406 return layerHapVerifyInfoList; 1407 } 1408 1409 /** 1410 * check two module is joint 1411 * 1412 * @param infoLeft is one hapVerifyInfo 1413 * @param infoRight is another hapVerifyInfo 1414 * @return true if dependency list is valid 1415 */ checkModuleJoint(HapVerifyInfo infoLeft, HapVerifyInfo infoRight)1416 private static boolean checkModuleJoint(HapVerifyInfo infoLeft, HapVerifyInfo infoRight) throws BundleException { 1417 return !checkDuplicatedIsValid(infoLeft, infoRight); 1418 } 1419 1420 /** 1421 * check dependency list is circulate 1422 * 1423 * @param dependencyList is current dependency list 1424 * @return true if dependency list is circulate 1425 */ checkDependencyListCirculate(List<HapVerifyInfo> dependencyList)1426 private static boolean checkDependencyListCirculate(List<HapVerifyInfo> dependencyList) throws BundleException { 1427 for (int i = 0; i < dependencyList.size() - 1; ++i) { 1428 for (int j = i + 1; j < dependencyList.size(); ++j) { 1429 if (isSameHapVerifyInfo(dependencyList.get(i), dependencyList.get(j))) { 1430 String cause = "Circular dependency, dependencyList is " + 1431 getHapVerifyInfoListNames(dependencyList) + "."; 1432 String solution = "Please check the dependecy against the module name in the list.\n"; 1433 solution += "Remove circulate dependency module to ensure the dependency list is valid."; 1434 LOG.error(PackingToolErrMsg.DEPENDENCY_LIST_INVALID.toString(cause, solution)); 1435 return true; 1436 } 1437 } 1438 } 1439 return false; 1440 } 1441 1442 /** 1443 * check two hapVerifyInfo is same.If two module has same moduleName and joint, they are the same hapVerifyInfo 1444 * 1445 * @param infoLeft is one hapVerifyInfo 1446 * @param infoRight is another hapVerifyInfo 1447 * @return true two hapVerifyInfo is same 1448 */ isSameHapVerifyInfo(HapVerifyInfo infoLeft, HapVerifyInfo infoRight)1449 private static boolean isSameHapVerifyInfo(HapVerifyInfo infoLeft, HapVerifyInfo infoRight) throws BundleException { 1450 if (!infoLeft.getModuleName().equals(infoRight.getModuleName())) { 1451 return false; 1452 } 1453 return checkModuleJoint(infoLeft, infoRight); 1454 } 1455 1456 /** 1457 * get moduleNames from List<HapVerifyInfo> 1458 * 1459 * @param hapVerifyInfoList is hapVerifyInfo list 1460 * @return true two hapVerifyInfo is same 1461 */ getHapVerifyInfoListNames(List<HapVerifyInfo> hapVerifyInfoList)1462 private static List<String> getHapVerifyInfoListNames(List<HapVerifyInfo> hapVerifyInfoList) { 1463 List<String> moduleNames = new ArrayList<>(); 1464 for (HapVerifyInfo hapVerifyInfo : hapVerifyInfoList) { 1465 moduleNames.add((hapVerifyInfo.getModuleName())); 1466 } 1467 return moduleNames; 1468 } 1469 checkAtomicServiceModuleAndDependenciesSize(List<HapVerifyInfo> hapVerifyInfoList)1470 private static boolean checkAtomicServiceModuleAndDependenciesSize(List<HapVerifyInfo> hapVerifyInfoList) 1471 throws BundleException { 1472 if (hapVerifyInfoList.isEmpty()) { 1473 String cause = "Hap verify infos is empty"; 1474 LOG.error(PackingToolErrMsg.CHECK_HAP_VERIFY_INFO_LIST_EMPTY.toString(cause)); 1475 return false; 1476 } 1477 int entryLimit = hapVerifyInfoList.get(0).getEntrySizeLimit(); 1478 int notEntryLimit = hapVerifyInfoList.get(0).getNotEntrySizeLimit(); 1479 for (HapVerifyInfo hapVerifyInfo : hapVerifyInfoList) { 1480 List<String> dependencies = getModuleDependency(hapVerifyInfo, hapVerifyInfoList); 1481 List<HapVerifyInfo> dependenciesInfos = new ArrayList<>(); 1482 for (String module : dependencies) { 1483 HapVerifyInfo info = findAtomicServiceHapVerifyInfo(module, hapVerifyInfoList); 1484 dependenciesInfos.add(info); 1485 } 1486 long fileSize = hapVerifyInfo.getFileLength(); 1487 for (HapVerifyInfo dependency : dependenciesInfos) { 1488 if (dependency == null) { 1489 continue; 1490 } 1491 fileSize += dependency.getFileLength(); 1492 } 1493 if (hapVerifyInfo.getModuleType().equals(ENTRY) && 1494 entryLimit != 0 && 1495 (fileSize >= entryLimit * FILE_LENGTH_1KB)) { 1496 String errMsg = "Module " + hapVerifyInfo.getModuleName() + " and it's dependencies size sum is " + 1497 getCeilFileSize(fileSize, entryLimit) + "KB, which is overlarge than " + entryLimit + "KB."; 1498 LOG.error(PackingToolErrMsg.CHECK_ATOMIC_SERVICE_MODULE_SIZE.toString(errMsg)); 1499 return false; 1500 } 1501 if (!hapVerifyInfo.getModuleType().equals(ENTRY) && 1502 notEntryLimit != 0 && 1503 (fileSize >= notEntryLimit * FILE_LENGTH_1KB)) { 1504 String errMsg = "Module " + hapVerifyInfo.getModuleName() + " and it's dependencies size sum is " + 1505 getCeilFileSize(fileSize, notEntryLimit) + "KB, which is overlarge than " + notEntryLimit + 1506 "KB."; 1507 LOG.error(PackingToolErrMsg.CHECK_ATOMIC_SERVICE_MODULE_SIZE.toString(errMsg)); 1508 return false; 1509 } 1510 } 1511 return true; 1512 } 1513 getCeilFileSize(long fileSize, int sizeLimit)1514 private static double getCeilFileSize(long fileSize, int sizeLimit) { 1515 double threshold = Double.valueOf(sizeLimit) + FILE_SIZE_OFFSET_DOUBLE; 1516 double size = new BigDecimal((float) fileSize 1517 / FILE_LENGTH_1KB).setScale(FILE_SIZE_DECIMAL_PRECISION, BigDecimal.ROUND_HALF_UP).doubleValue(); 1518 if (size < threshold && size >= sizeLimit) { 1519 size = threshold; 1520 } 1521 return size; 1522 } 1523 getDeviceHapVerifyInfoMap(List<HapVerifyInfo> hapVerifyInfoList)1524 private static Map<String, List<HapVerifyInfo>> getDeviceHapVerifyInfoMap(List<HapVerifyInfo> hapVerifyInfoList) 1525 throws BundleException { 1526 if (hapVerifyInfoList.isEmpty()) { 1527 String cause = "Hap verify infos is empty"; 1528 LOG.error(PackingToolErrMsg.CHECK_HAP_VERIFY_INFO_LIST_EMPTY.toString(cause)); 1529 throw new BundleException("getDeviceHapVerifyInfoMap failed, hapVerifyInfoList is empty."); 1530 } 1531 Map<String, List<HapVerifyInfo>> deviceInfoMap = new HashMap<String, List<HapVerifyInfo>>(); 1532 for (HapVerifyInfo hapVerifyInfo : hapVerifyInfoList) { 1533 List<String> deviceTypes = hapVerifyInfo.getDeviceType(); 1534 for (String device : deviceTypes) { 1535 if (!deviceInfoMap.containsKey(device)) { 1536 List<HapVerifyInfo> infos = new ArrayList<>(); 1537 infos.add(hapVerifyInfo); 1538 deviceInfoMap.put(device, infos); 1539 } else { 1540 deviceInfoMap.get(device).add(hapVerifyInfo); 1541 } 1542 } 1543 } 1544 return deviceInfoMap; 1545 } 1546 checkAtomicServiceIsValid(List<HapVerifyInfo> hapVerifyInfoList)1547 private static boolean checkAtomicServiceIsValid(List<HapVerifyInfo> hapVerifyInfoList) throws BundleException { 1548 if (hapVerifyInfoList.isEmpty()) { 1549 String cause = "Hap verify infos is empty"; 1550 LOG.error(PackingToolErrMsg.CHECK_HAP_VERIFY_INFO_LIST_EMPTY.toString(cause)); 1551 return false; 1552 } 1553 String bundleType = hapVerifyInfoList.get(0).getBundleType(); 1554 if (!bundleType.equals(ATOMIC_SERVICE)) { 1555 return true; 1556 } 1557 boolean isStage = hapVerifyInfoList.get(0).isStageModule(); 1558 if (!isStage) { 1559 return true; 1560 } 1561 // check preloads is valid 1562 Map<String, List<HapVerifyInfo>> deviceInfoMap = getDeviceHapVerifyInfoMap(hapVerifyInfoList); 1563 for (String device : deviceInfoMap.keySet()) { 1564 List<HapVerifyInfo> hapVerifyInfos = deviceInfoMap.get(device); 1565 if (!checkAtomicServicePreloadsIsValid(hapVerifyInfos)) { 1566 LOG.error(PackingToolErrMsg.CHECK_ATOMICSERVICE_INVALID.toString( 1567 "Check whether atomicService preloads are valid failed on device " + device + ".")); 1568 return false; 1569 } 1570 } 1571 1572 return true; 1573 } 1574 checkAtomicServiceSumLimit(List<HapVerifyInfo>hapVerifyInfos)1575 private static boolean checkAtomicServiceSumLimit(List<HapVerifyInfo>hapVerifyInfos) { 1576 int sumLimit = hapVerifyInfos.get(0).getSumSizeLimit(); 1577 if (!hapVerifyInfos.get(0).isStageModule()) { 1578 return true; 1579 } 1580 long fileSize = 0L; 1581 for (HapVerifyInfo hapVerifyInfo : hapVerifyInfos) { 1582 fileSize += hapVerifyInfo.getFileLength(); 1583 if (fileSize >= sumLimit * FILE_LENGTH_1M) { 1584 LOG.error("The total file size is " + getCeilFileSize(fileSize, sumLimit) + 1585 "MB, greater than " + sumLimit + "MB."); 1586 return false; 1587 } 1588 } 1589 return true; 1590 } 1591 checkAtomicServicePreloadsIsValid(List<HapVerifyInfo> hapVerifyInfoList)1592 private static boolean checkAtomicServicePreloadsIsValid(List<HapVerifyInfo> hapVerifyInfoList) 1593 throws BundleException { 1594 if (hapVerifyInfoList.isEmpty()) { 1595 String cause = "Hap verify infos is empty."; 1596 LOG.error(PackingToolErrMsg.CHECK_HAP_VERIFY_INFO_LIST_EMPTY.toString(cause)); 1597 throw new BundleException("checkAtomicServicePreloadsIsValid failed, hapVerifyInfoList is empty."); 1598 } 1599 List<String> moduleNames = new ArrayList<>(); 1600 for (HapVerifyInfo hapVerifyInfo : hapVerifyInfoList) { 1601 moduleNames.add(hapVerifyInfo.getModuleName()); 1602 } 1603 // check preload module is existed and not self 1604 for (HapVerifyInfo hapVerifyInfo : hapVerifyInfoList) { 1605 List<String> preloadModuleName = new ArrayList<>(); 1606 List<PreloadItem> preloadItems = hapVerifyInfo.getPreloadItems(); 1607 for (PreloadItem preloadItem : preloadItems) { 1608 String moduleName = preloadItem.getModuleName(); 1609 if (preloadModuleName.contains(moduleName)) { 1610 LOG.error(PackingToolErrMsg.ATOMICSERVICE_PRELOADS_INVALID.toString( 1611 "Preloads a duplicate module, module(" + hapVerifyInfo.getModuleName() + 1612 ") cannot preloads module (" + moduleName + ").")); 1613 return false; 1614 } 1615 preloadModuleName.add(moduleName); 1616 if (!moduleNames.contains(moduleName)) { 1617 LOG.error(PackingToolErrMsg.ATOMICSERVICE_PRELOADS_INVALID.toString( 1618 "Preloads a not exist module, module(" + hapVerifyInfo.getModuleName() + 1619 ") cannot preloads module(" + moduleName + ").")); 1620 return false; 1621 } 1622 if (moduleName.equals(hapVerifyInfo.getModuleName())) { 1623 LOG.error(PackingToolErrMsg.ATOMICSERVICE_PRELOADS_INVALID.toString("Cannot preload self, module " + 1624 hapVerifyInfo.getModuleName() + " cannot preloads self.")); 1625 return false; 1626 } 1627 } 1628 } 1629 // check feature preload is valid 1630 Map<String, String> moduleNameWithType = new HashMap<>(); 1631 for (HapVerifyInfo hapVerifyInfo : hapVerifyInfoList) { 1632 moduleNameWithType.put(hapVerifyInfo.getModuleName(), hapVerifyInfo.getModuleType()); 1633 } 1634 for (HapVerifyInfo hapVerifyInfo : hapVerifyInfoList) { 1635 List<PreloadItem> preloadItems = hapVerifyInfo.getPreloadItems(); 1636 for (PreloadItem preloadItem : preloadItems) { 1637 String moduleName = preloadItem.getModuleName(); 1638 if (moduleNameWithType.get(moduleName).equals(ENTRY) 1639 || moduleNameWithType.get(moduleName).equals(HAR)) { 1640 LOG.error(PackingToolErrMsg.ATOMICSERVICE_PRELOADS_INVALID.toString( 1641 "feature or shared cannot preload entry or har, module(" + hapVerifyInfo.getModuleName() + 1642 ") cannot preloads module(" + moduleName + ").")); 1643 return false; 1644 } 1645 } 1646 } 1647 1648 return true; 1649 } 1650 1651 /** 1652 * check file size is valid from List<HapVerifyInfo> 1653 * 1654 * @param hapVerifyInfoList is hapVerifyInfo list 1655 * @return true file size is under limit 1656 */ checkFileSizeIsValid(List<HapVerifyInfo> hapVerifyInfoList)1657 public static boolean checkFileSizeIsValid(List<HapVerifyInfo> hapVerifyInfoList) throws BundleException { 1658 if (hapVerifyInfoList.isEmpty()) { 1659 LOG.error(PackingToolErrMsg.CHECK_HAP_VERIFY_INFO_LIST_EMPTY.toString("Hap verify infos is empty.")); 1660 throw new BundleException("Check file size is valid failed, hap verify infos is empty."); 1661 } 1662 if (!checkFileSize(hapVerifyInfoList)) { 1663 return false; 1664 } 1665 return true; 1666 } 1667 checkFileSize(List<HapVerifyInfo> hapVerifyInfoList)1668 private static boolean checkFileSize(List<HapVerifyInfo> hapVerifyInfoList) throws BundleException { 1669 if (hapVerifyInfoList.isEmpty()) { 1670 LOG.error(PackingToolErrMsg.CHECK_HAP_VERIFY_INFO_LIST_EMPTY.toString("Hap verify infos is empty.")); 1671 throw new BundleException("checkFileSizeWhenSplit failed, hapVerifyInfoList is empty."); 1672 } 1673 // check single file length 1674 int entryLimit = hapVerifyInfoList.get(0).getEntrySizeLimit(); 1675 int notEntryLimit = hapVerifyInfoList.get(0).getNotEntrySizeLimit(); 1676 for (HapVerifyInfo hapVerifyInfo : hapVerifyInfoList) { 1677 if (hapVerifyInfo.getModuleType().equals(ENTRY) && 1678 entryLimit != 0 && 1679 (hapVerifyInfo.getFileLength() >= entryLimit * FILE_LENGTH_1KB)) { 1680 String errMsg = "Module " + hapVerifyInfo.getModuleName() + "'s size is " + 1681 getCeilFileSize(hapVerifyInfo.getFileLength(), entryLimit) + 1682 "KB, which is overlarge than " + entryLimit + "KB."; 1683 LOG.error(PackingToolErrMsg.CHECK_FILE_SIZE_INVALID.toString(errMsg)); 1684 return false; 1685 } 1686 if (!hapVerifyInfo.getModuleType().equals(ENTRY) && 1687 notEntryLimit != 0 && 1688 (hapVerifyInfo.getFileLength() >= notEntryLimit * FILE_LENGTH_1KB)) { 1689 String errMsg = "Module " + hapVerifyInfo.getModuleName() + "'s size is " + 1690 getCeilFileSize(hapVerifyInfo.getFileLength(), notEntryLimit) + 1691 "KB, which is overlarge than " + notEntryLimit + "KB."; 1692 LOG.error(PackingToolErrMsg.CHECK_FILE_SIZE_INVALID.toString(errMsg)); 1693 return false; 1694 } 1695 } 1696 1697 Map<String, List<HapVerifyInfo>> deviceInfoMap = getDeviceHapVerifyInfoMap(hapVerifyInfoList); 1698 for (String device : deviceInfoMap.keySet()) { 1699 List<HapVerifyInfo>hapVerifyInfoList1 = deviceInfoMap.get(device); 1700 if (!checkAtomicServiceModuleAndDependenciesSize(hapVerifyInfoList1)) { 1701 String errMsg = "Check the atomicService module size failed on device " + device + "."; 1702 LOG.error(PackingToolErrMsg.CHECK_FILE_SIZE_INVALID.toString(errMsg)); 1703 return false; 1704 } 1705 } 1706 return true; 1707 } 1708 getModuleDependency(HapVerifyInfo hapVerifyInfo, List<HapVerifyInfo> hapVerifyInfoList)1709 private static List<String> getModuleDependency(HapVerifyInfo hapVerifyInfo, 1710 List<HapVerifyInfo> hapVerifyInfoList) throws BundleException { 1711 List<String> dependencyModules = new ArrayList<>(); 1712 dependencyModules.addAll(hapVerifyInfo.getDependencies()); 1713 List<String> dependencyItems = hapVerifyInfo.getDependencies(); 1714 for (String dependency : dependencyItems) { 1715 HapVerifyInfo dependencyHapVerifyInfo = findAtomicServiceHapVerifyInfo(dependency, hapVerifyInfoList); 1716 if (dependencyHapVerifyInfo == null) { 1717 continue; 1718 } 1719 List<String> childDependencies = getModuleDependency(dependencyHapVerifyInfo, hapVerifyInfoList); 1720 for (String childDependency : childDependencies) { 1721 if (!dependencyModules.contains(childDependency)) { 1722 dependencyModules.add(childDependency); 1723 } 1724 } 1725 } 1726 return dependencyModules; 1727 } 1728 findAtomicServiceHapVerifyInfo(String moduleName, List<HapVerifyInfo> hapVerifyInfoList)1729 private static HapVerifyInfo findAtomicServiceHapVerifyInfo(String moduleName, 1730 List<HapVerifyInfo> hapVerifyInfoList) { 1731 for (HapVerifyInfo hapVerifyInfo : hapVerifyInfoList) { 1732 if (hapVerifyInfo.getModuleName().equals(moduleName)) { 1733 return hapVerifyInfo; 1734 } 1735 } 1736 return null; 1737 } 1738 } 1739