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