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