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