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