• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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