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