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