diff --git a/.gitignore b/.gitignore index c51f72aea4f1c609fe75a2f4e84acba5846a877b..1f29cc3a61132a62686557000d74dbc4a083d5c4 100755 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ jar .idea/ +developtools_packing_tool.iml +out/ + diff --git a/adapter/ohos/AppInfo.java b/adapter/ohos/AppInfo.java index b99252a9fa06f5b942d0593690b72f442dc76c5f..90517ba253a70451c25958209b726d9a8c294590 100644 --- a/adapter/ohos/AppInfo.java +++ b/adapter/ohos/AppInfo.java @@ -30,6 +30,16 @@ public class AppInfo { */ public String bundleName = ""; + /** + * Indicates the category of app. + */ + public String appType = "app"; + + /** + * Indicates whether the bundle is split when appType is atomicService. + */ + public boolean split = true; + /** * Indicates the vendor of app AppInfo. */ diff --git a/adapter/ohos/Compressor.java b/adapter/ohos/Compressor.java index fe4bc2d0d14672bcdb99ad3c111abf139fe75493..675cba9d89b94d3d3d0a0e300eb00e75f3650edc 100644 --- a/adapter/ohos/Compressor.java +++ b/adapter/ohos/Compressor.java @@ -31,12 +31,9 @@ import java.io.OutputStream; import java.nio.charset.StandardCharsets; import java.nio.file.attribute.FileTime; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Enumeration; +import java.text.DecimalFormat; +import java.util.*; import java.util.HashMap; -import java.util.List; -import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.zip.CRC32; @@ -119,6 +116,7 @@ public class Compressor { private static final String TEMP_SELECTED_HAP_DIR = "tempSelectedHapDir"; private static final String ABILITIES_DIR_NAME = "abilities"; private static final String EMPTY_STRING = ""; + private static final String APP = "app"; // set timestamp to get fixed MD5 @@ -137,6 +135,7 @@ public class Compressor { private List formNamesList = new ArrayList(); private List fileNameList = new ArrayList(); private List supportDimensionsList = Arrays.asList(PIC_1X2, PIC_2X2, PIC_2X4, PIC_4X4); + private long fileLength_1M = 1024 * 1024; /** * check path if is a module.json file @@ -2014,6 +2013,7 @@ public class Compressor { */ private boolean checkHapIsValid(List fileLists) throws BundleException { List hapVerifyInfos = new ArrayList<>(); + HashMap moduleMap = new HashMap(); for (String hapPath : fileLists) { if (hapPath.isEmpty()) { LOG.error("Compressor::checkHapIsValid input wrong hap file!"); @@ -2031,17 +2031,59 @@ public class Compressor { throw new BundleException("Compressor::checkHapIsValid input wrong hap file!"); } if (isModuleHap(hapPath)) { - hapVerifyInfos.add(parseStageHapVerifyInfo(hapPath)); + HapVerifyInfo hapVerifyInfo = parseStageHapVerifyInfo(hapPath); + hapVerifyInfos.add(hapVerifyInfo); + moduleMap.put(hapVerifyInfo, hapPath); } else { hapVerifyInfos.add(parseFAHapVerifyInfo(hapPath)); } } + if (!HapVerify.checkHapIsValid(hapVerifyInfos)) { return false; } + if (!checkAtomicServiceHapSize(moduleMap)) { + LOG.error("checkAtomicServiceHapSize: hap size is overlarge!"); + return false; + } + return true; + } + + /** + * check hap size is valid in atomicService. + * + * @param moduleMap key is hapVerifyInfo, value is hap path. + * @throws BundleException FileNotFoundException|IOException. + */ + private boolean checkAtomicServiceHapSize(HashMap moduleMap) { + for (HashMap.Entry entry : moduleMap.entrySet()) { + if (!entry.getKey().isStageModule()) { + return true; + } + } + // todo + return true; } + public List getDenpendenciesList(HapVerifyInfo hapVerifyInfo, + HashMap nameToInfo) { + List dependencyList = new ArrayList<>(); + HashSet names; + if (hapVerifyInfo.getDependencyItemList().isEmpty()) { + return dependencyList; + } + for (DependencyItem dependencyItem : hapVerifyInfo.getDependencyItemList()) { + if (!dependencyItem.getBundleName().equals(hapVerifyInfo.getBundleName())) { + continue; + } + String moduleName = dependencyItem.getModuleName(); + HapVerifyInfo verifyInfo = nameToInfo.get(moduleName); + + } + return dependencyList; + } + /** * parse stage file to hap verify info from hap path. * diff --git a/adapter/ohos/HapInfo.java b/adapter/ohos/HapInfo.java index 65a411739867258096a76de3bec72fb34fd7fb3f..4a35aae7c914a503ec989c5ed899c44302895a95 100644 --- a/adapter/ohos/HapInfo.java +++ b/adapter/ohos/HapInfo.java @@ -152,6 +152,15 @@ public class HapInfo { */ public List formInfos = new ArrayList<>(); + /** + * Indicates the type of the current module when the atomicService is split. + */ + public String atomicServiceModuleType = "normal"; + /** + * Indicates the module that is preloaded when the current module is run. + */ + public List preloadModules = new ArrayList(); + /** * get the customize Data value defined in this module. */ diff --git a/adapter/ohos/HapVerify.java b/adapter/ohos/HapVerify.java index f0fbacdbbbf225c3383f0b98e052a2d5a02d758e..b656316bb28669b0f966f31447f810289e465211 100644 --- a/adapter/ohos/HapVerify.java +++ b/adapter/ohos/HapVerify.java @@ -15,6 +15,8 @@ package ohos; +import com.sun.tools.javac.Main; + import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -30,6 +32,9 @@ import java.util.stream.Stream; class HapVerify { private static final String INCLUDE = "include"; private static final String EXCLUDE = "exclude"; + private static final String NORMAL = "normal"; + private static final String APP = "app"; + private static final String ATOMIC_SERVICE = "atomicService"; private static final Log LOG = new Log(HapVerify.class.toString()); private static final int SERVICE_DEPTH = 2; private static final int APPLICATION_DEPTH = 5; @@ -37,6 +42,7 @@ class HapVerify { private static final String ENTRY = "entry"; private static final String FEATURE = "feature"; private static final String SHARED_LIBRARY = "shared"; + private static final String MODULE_MAIN = "main"; private static final String REFERENCE_LINK = "https://developer.harmonyos.com/cn/docs/documentation/doc-guides/verification_rule-0000001406748378"; @@ -57,6 +63,12 @@ class HapVerify { LOG.error("Error: some app variable is different!"); return false; } + // check atomicService config is valid + if (!checkAtomicServiceConfig(hapVerifyInfos)) { + LOG.error("Error: atomic service config is invalid!"); + return false; + } + // check moduleName is valid if (!checkModuleNameIsValid(hapVerifyInfos)) { return false; @@ -95,6 +107,7 @@ class HapVerify { } VerifyCollection verifyCollection = new VerifyCollection(); verifyCollection.bundleName = hapVerifyInfos.get(0).getBundleName(); + verifyCollection.split = hapVerifyInfos.get(0).getSplit(); verifyCollection.vendor = hapVerifyInfos.get(0).getVendor(); verifyCollection.versionCode = hapVerifyInfos.get(0).getVersion().versionCode; verifyCollection.versionName = hapVerifyInfos.get(0).getVersion().versionName; @@ -108,6 +121,10 @@ class HapVerify { LOG.error("Error: input module bundleName is different!"); return false; } + if (hapVerifyInfo.getSplit() != verifyCollection.split) { + LOG.error("Error: input module split is different!"); + return false; + } if (hapVerifyInfo.getVendor().isEmpty() || !verifyCollection.vendor.equals(hapVerifyInfo.getVendor())) { LOG.error("Error: input module vendor is different!"); return false; @@ -137,6 +154,10 @@ class HapVerify { return false; } } + if (!checkappTypeIsSame(hapVerifyInfos)) { + LOG.error("Error: input module appType is different!"); + return false; + } return true; } @@ -180,6 +201,47 @@ class HapVerify { return true; } + /** + * check appType is valid. + * + * @param hapVerifyInfos is the collection of hap infos + * @return true if appType is valid + * @throws BundleException Throws this exception if the json is not standard. + */ + private static boolean checkappTypeIsSame(List hapVerifyInfos){ + if (hapVerifyInfos.isEmpty()) { + LOG.error("HapVerify::checkappTypeIsSame failed, hapVerifyInfos is empty"); + return false; + } + boolean isApp = true; + HapVerifyInfo hapVerifyInfo = hapVerifyInfos.get(0); + if ((hapVerifyInfo.getappType().isEmpty() && hapVerifyInfo.isInstallationFree()) || + hapVerifyInfo.getappType().equals(ATOMIC_SERVICE)) { + isApp = false; + } + if (isApp) { + for (int i = 1; i < hapVerifyInfos.size(); i++) { + HapVerifyInfo info = hapVerifyInfos.get(i); + if ((info.getappType().isEmpty() && info.isInstallationFree()) || + info.getappType().equals(ATOMIC_SERVICE)) { + LOG.error("appType is not same."); + return false; + } + } + } + else { + for (int i = 1; i < hapVerifyInfos.size(); i++) { + HapVerifyInfo info = hapVerifyInfos.get(i); + if ((info.getappType().isEmpty() && !info.isInstallationFree()) || + info.getappType().equals(APP)) { + LOG.error("appType is not same."); + return false; + } + } + } + return true; + } + /** * check packageName is valid. * @@ -847,10 +909,6 @@ class HapVerify { LOG.error("Error: installationFree is different in input hap!"); return false; } - if (isInstallationFree && SHARED_LIBRARY.equals(hapVerifyInfo.getModuleType())) { - LOG.error("Error: app can not contain both atomic service and hsp!"); - return false; - } } int depth = isInstallationFree ? SERVICE_DEPTH : APPLICATION_DEPTH; for (HapVerifyInfo hapVerifyInfo : allHapVerifyInfo) { @@ -996,4 +1054,57 @@ class HapVerify { } return moduleNames; } + + /** + * check atomic service config + * + * @param hapVerifyInfoList is hapVerifyInfo list + * @return true if config is valid + */ + private static boolean checkAtomicServiceConfig(List hapVerifyInfoList) { + if (hapVerifyInfoList.isEmpty()) { + LOG.error("empty hapVerifyInfoList!"); + return false; + } + if (!hapVerifyInfoList.get(0).isStageModule()) { + return true; + } + if (hapVerifyInfoList.get(0).getappType().isEmpty() || hapVerifyInfoList.get(0).getappType().equals(APP)) { + LOG.info("appType is app!"); + return true; + } + if (!checkAtomicServiceHapCount(hapVerifyInfoList)) { + LOG.error("checkAtomicServiceConfig: " + + "The total number of hap and hsp can not be greater than 1 when split is false!"); + return false; + } + boolean hasMain = false; + for (HapVerifyInfo hapVerifyInfo : hapVerifyInfoList) { + if (hapVerifyInfo.getSplit()) { + if (!hapVerifyInfo.getAtomicServiceModuleType().isEmpty() && + hapVerifyInfo.getAtomicServiceModuleType().equals(MODULE_MAIN)) { + if (hasMain) { + LOG.error("checkAtomicServiceConfig: " + + "atomicServiceModuleType can only have one home module when split is true!"); + return false; + } + hasMain = true; + } + } + } + return hasMain; + } + + /** + * check atomic service hap count when split is false + * + * @param hapVerifyInfoList is hapVerifyInfo list + * @return true if config is valid + */ + private static boolean checkAtomicServiceHapCount(List hapVerifyInfoList) { + if (!hapVerifyInfoList.get(0).getSplit()) { + return hapVerifyInfoList.size() == 1 && hapVerifyInfoList.get(0).getModuleType().equals(ENTRY); + } + return true; + } } diff --git a/adapter/ohos/HapVerifyInfo.java b/adapter/ohos/HapVerifyInfo.java index d1e8d74f1b2dfe15140fb13f450bc9168c3e878d..3f2a0fc299dce3d7b1ac9aa11a4dc1d478682e1b 100644 --- a/adapter/ohos/HapVerifyInfo.java +++ b/adapter/ohos/HapVerifyInfo.java @@ -29,6 +29,16 @@ class HapVerifyInfo { */ private String bundleName = ""; + /** + * Indicates the category of bundle. + */ + private String appType = "app"; + + /** + * Indicates whether split the bundle. + */ + private boolean split = false; + /** * Indicates the vendor of module. */ @@ -104,6 +114,16 @@ class HapVerifyInfo { */ private HashMap resourceMap = new HashMap<>(); + /** + * Indicates the category of module in atomicService. + */ + private String atomicServiceModuleType = ""; + + /** + * Indicates the preload config of module. + */ + private List preloadModules = new ArrayList<>(); + /** * get bundle name form HapVerifyInfo. */ @@ -118,6 +138,34 @@ class HapVerifyInfo { this.bundleName = bundleName; } + /** + * get bundle category form HapVerifyInfo. + */ + public String getappType() { + return appType; + } + + /** + * set bundle category for HapVerifyInfo. + */ + public void setAppType(String type) { + this.appType = type; + } + + /** + * get whether split the bundle in atomicService form HapVerifyInfo. + */ + public boolean getSplit() { + return split; + } + + /** + * set whether split the bundle in atomicService form HapVerifyInfo. + */ + public void setSplit(boolean splitBundle) { + this.split = splitBundle; + } + /** * get vendor form HapVerifyInfo. */ @@ -343,4 +391,32 @@ class HapVerifyInfo { } } } + + /** + * set module category in atomic service for HapVerifyInfo. + */ + public void setAtomicServiceModuleType(String moduleType) { + this.atomicServiceModuleType = moduleType; + } + + /** + * get module category in atomic service for HapVerifyInfo. + */ + public String getAtomicServiceModuleType() { + return atomicServiceModuleType; + } + + /** + * set preload list for HapVerifyInfo. + */ + public void setPreloadModules(List preloadModulesList) { + this.preloadModules = preloadModulesList; + } + + /** + * get preload list for HapVerifyInfo. + */ + public List getPreloadModules() { + return preloadModules; + } } diff --git a/adapter/ohos/JsonUtil.java b/adapter/ohos/JsonUtil.java index 08de6d938d157be2f2e7765a12499da6328407af..ae7d004f91d009708ef5d67c93d7ece65c6d1999 100644 --- a/adapter/ohos/JsonUtil.java +++ b/adapter/ohos/JsonUtil.java @@ -64,6 +64,8 @@ public class JsonUtil { private static final String STRING_RESOURCE = "$string:"; private static final String EMPTY = ""; private static final String BUNDLENAME = "bundleName"; + private static final String APP_CATEGORY = "appType"; + private static final String SPLIT = "split"; private static final String VERSIONCODE = "versionCode"; private static final String VERSIONNAME = "versionName"; private static final String PATCH_VERSION_CODE = "patchVersionCode"; @@ -87,6 +89,8 @@ public class JsonUtil { private static final String DISTRIBUTED_NOTIFICATION_ENABLED = "distributedNotificationEnabled"; private static final String ENTITY_TYPE = "entityType"; private static final String UNSPECIFIED = "unspecified"; + private static final String ATOMIC_SERVICE_MODULE_TYPE = "atomicServiceModuleType"; + private static final String PRELOAD_MODULES = "preloadModules"; private static final String SRC_ENTRANCE = "srcEntrance"; private static final String PROCESS = "process"; private static final String PHONE = "phone"; @@ -353,6 +357,8 @@ public class JsonUtil { throw new BundleException("Parse app info failed, appJson is null"); } appInfo.bundleName = getJsonString(appJson, "bundleName"); + appInfo.appType = getJsonString(appJson, "appType", "app"); + appInfo.split = getJsonBooleanValue(appJson, "split", false); appInfo.vendor = getJsonString(appJson, "vendor"); appInfo.relatedBundleName = getJsonString(appJson, "relatedBundleName"); if (appJson.containsKey(VERSION)) { @@ -399,6 +405,8 @@ public class JsonUtil { moduleAppInfo.bundleName = getJsonString(appJson, BUNDLENAME); moduleAppInfo.debug = getJsonBooleanValue(appJson, DEBUG, false); + moduleAppInfo.appType = getJsonString(appJson, APP_CATEGORY); + moduleAppInfo.split = getJsonBooleanValue(appJson, SPLIT, false); moduleAppInfo.icon = parseIconById(appJson, data); moduleAppInfo.label = parseResourceByKey(appJson, data, LABEL, LABEL_ID); moduleAppInfo.labels = parseResourceMapByKey(appJson, data, LABEL_ID); @@ -1005,6 +1013,8 @@ public class JsonUtil { moduleInfo.name = getJsonString(moduleJson, NAME); moduleInfo.type = getJsonString(moduleJson, TYPE); + moduleInfo.atomicServiceModuleType = getJsonString(moduleJson, ATOMIC_SERVICE_MODULE_TYPE); + moduleInfo.preloadModules = parsePreloadItems(moduleJson, data); moduleInfo.srcEntrance = getJsonString(moduleJson, SRC_ENTRANCE); moduleInfo.description = parseResourceByKey(moduleJson, data, DESCRIPTION, DESCRIPTION_ID); moduleInfo.descriptions = parseResourceMapByKey(moduleJson, data, DESCRIPTION_ID); @@ -1821,6 +1831,39 @@ public class JsonUtil { return usedScene; } + /** + * parse preloadItem objects + * + * @param moduleJson is module json object + * @param data is resource byte in hap + * @throws BundleException Throws this exception if the json is not standard. + */ + static List parsePreloadItems(JSONObject moduleJson, byte[] data) throws BundleException { + List preloadItems = new ArrayList<>(); + if (moduleJson.containsKey("preloadModules")) { + JSONArray preloadObjs = moduleJson.getJSONArray("preloadModules"); + for (int i = 0; i < preloadObjs.size(); ++i) { + preloadItems.add(parsePreloadItem(preloadObjs.getJSONObject(i), data)); + } + } + return preloadItems; + } + + /** + * parse preloadItem objects + * + * @param preloadItemObj is preload item json object + * @param data is resource byte in hap + * @throws BundleException Throws this exception if the json is not standard. + */ + static PreloadItem parsePreloadItem(JSONObject preloadItemObj, byte[] data) throws BundleException { + PreloadItem preloadItem = new PreloadItem(); + if (preloadItemObj.containsKey("moduleName")) { + preloadItem.moduleName = getJsonString(preloadItemObj, "moduleName"); + } + return preloadItem; + } + /** * get the String from JSONObject by the key. * diff --git a/adapter/ohos/ModuleAdaption.java b/adapter/ohos/ModuleAdaption.java index dd27e318297b50f2134b6974a1b083ecae4d63d6..67ab237b6014c1f7a8f043d9d191f52586506b4c 100644 --- a/adapter/ohos/ModuleAdaption.java +++ b/adapter/ohos/ModuleAdaption.java @@ -78,6 +78,8 @@ class ModuleAdaption { } appInfo.bundleName = moduleAppInfo.bundleName; appInfo.debug = moduleAppInfo.debug; + appInfo.appType = moduleAppInfo.appType; + appInfo.split = moduleAppInfo.split; appInfo.icon = moduleAppInfo.icon; appInfo.label = moduleAppInfo.label; appInfo.labels = moduleAppInfo.labels; @@ -158,6 +160,8 @@ class ModuleAdaption { hapInfo.formInfos = moduleInfo.abilityFormInfos; hapInfo.commonEvents = moduleInfo.commonEvents; hapInfo.definePermissions = moduleInfo.definePermissions; + hapInfo.atomicServiceModuleType = moduleInfo.atomicServiceModuleType; + hapInfo.preloadModules = moduleInfo.preloadModules; return hapInfo; } diff --git a/adapter/ohos/ModuleAppInfo.java b/adapter/ohos/ModuleAppInfo.java index e167a01dfb3349d671fa8c92a8157d8699301198..7b9fc912c0b596b84b83983b21b9a2bb6ca10b8c 100644 --- a/adapter/ohos/ModuleAppInfo.java +++ b/adapter/ohos/ModuleAppInfo.java @@ -34,6 +34,14 @@ class ModuleAppInfo { * Indicates the debug of app AppJson. */ public boolean debug = false; + /** + * Indicates the category of app. + */ + public String appType = "app"; + /** + * Indicates whether the bundle is split when appType is atomicService. + */ + public boolean split = false; /** * Indicates the icon of app AppJson. */ diff --git a/adapter/ohos/ModuleInfo.java b/adapter/ohos/ModuleInfo.java index 9d6f93c7870caf01ad577ea00843097367b67e82..ae631d22af5a00823a82e2afc655844a308e4147 100644 --- a/adapter/ohos/ModuleInfo.java +++ b/adapter/ohos/ModuleInfo.java @@ -39,6 +39,14 @@ class ModuleInfo { * Indicates the type of ModuleInfo. */ public String type = ""; + /** + * Indicates the type of the current module when the atomicService is split. + */ + public String atomicServiceModuleType = "normal"; + /** + * Indicates the module that is preloaded when the current module is run. + */ + public List preloadModules = new ArrayList(); /** * Indicates the srcEntrance of ModuleInfo. */ diff --git a/adapter/ohos/ModuleJsonUtil.java b/adapter/ohos/ModuleJsonUtil.java index 58f92616a351af981b84c76742e53f5aebdf0c23..b566ddd1daa6d2fec2a7e23044159ee38cc2b37d 100644 --- a/adapter/ohos/ModuleJsonUtil.java +++ b/adapter/ohos/ModuleJsonUtil.java @@ -76,6 +76,12 @@ class ModuleJsonUtil { private static final String ORIGINAL_MODULE_HASH = "originalModuleHash"; private static final String EMPTY_STRING = ""; private static final String COMPRESS_NATIVE_LIBS = "compressNativeLibs"; + private static final String ATOMIC_SERVICE = "atomicService"; + private static final String SPLIT = "split"; + private static final String PRELOADS = "preloads"; + + private static final String MAIN_MODULE = "main"; + private static final String NORMAL_MODULE = "normal"; private static final Log LOG = new Log(ModuleJsonUtil.class.toString()); /** @@ -195,6 +201,13 @@ class ModuleJsonUtil { return moduleApiVersion; } + public static String parseFAappType(boolean isInstallationFree) { + if (isInstallationFree) { + return ATOMIC_SERVICE; + } + return APP; + } + /** * get the apiVersion from json file for fa module. * @@ -357,6 +370,63 @@ class ModuleJsonUtil { return bundleName; } + /** + * get the appType from json file. + * + * @param jsonString uncompress json object + * @throws BundleException Throws this exception if the json is not standard. + * @return the result + */ + public static String parseappType(String jsonString) throws BundleException { + JSONObject jsonObject; + try { + jsonObject = JSON.parseObject(jsonString); + } catch (JSONException exception) { + String errMsg = "parse JSONobject failed"; + LOG.error(errMsg); + throw new BundleException(errMsg); + } + JSONObject appObject = jsonObject.getJSONObject(APP); + if (appObject == null) { + LOG.error("ModuleJsonUtil::parseappType json object do not contain app!"); + throw new BundleException("ModuleJsonUtil::parseappType json object do not contain app!"); + } + if (appObject.containsKey(ATOMIC_SERVICE) || parseStageInstallation(jsonString)) { + return ATOMIC_SERVICE; + } + return APP; + } + + /** + * get the split from json file. + * + * @param jsonString uncompress json object + * @throws BundleException Throws this exception if the json is not standard. + * @return the result + */ + static boolean parseSplit(String jsonString) throws BundleException { + JSONObject jsonObj; + try { + jsonObj = JSON.parseObject(jsonString); + } catch (JSONException exception) { + String errMsg = "parse JSONobject failed"; + LOG.error(errMsg); + throw new BundleException(errMsg); + } + JSONObject appObj = jsonObj.getJSONObject(APP); + if (appObj == null) { + LOG.error("ModuleJsonUtil::parseSplit json do not contain app!"); + throw new BundleException("ModuleJsonUtil::parseSplit json do not contain app!"); + } + if (appObj.containsKey(ATOMIC_SERVICE)) { + JSONObject atomicObj = appObj.getJSONObject(ATOMIC_SERVICE); + if (atomicObj.containsKey(SPLIT)) { + return appObj.getBoolean(SPLIT); + } + } + return true; + } + /** * get the vendor from json file. * @@ -375,8 +445,8 @@ class ModuleJsonUtil { } JSONObject appObject = jsonObject.getJSONObject(APP); if (appObject == null) { - LOG.error("ModuleJsonUtil::parseStageBundleName json object do not contain app!"); - throw new BundleException("ModuleJsonUtil::parseStageBundleName json object do not contain app!"); + LOG.error("ModuleJsonUtil::parseVendor json object do not contain app!"); + throw new BundleException("ModuleJsonUtil::parseVendor json object do not contain app!"); } String vendor = ""; if (appObject.containsKey(VENDOR)) { @@ -850,6 +920,8 @@ class ModuleJsonUtil { } String bundleName = parseBundleName(hapVerifyInfo.getProfileStr()); hapVerifyInfo.setBundleName(bundleName); + hapVerifyInfo.setAppType(parseappType(hapVerifyInfo.getProfileStr())); + hapVerifyInfo.setSplit(parseSplit(hapVerifyInfo.getProfileStr())); hapVerifyInfo.setVendor(parseVendor(hapVerifyInfo.getProfileStr())); hapVerifyInfo.setVersion(parseStageVersion(hapVerifyInfo.getProfileStr())); hapVerifyInfo.setApiVersion(parseStageModuleApiVersion(hapVerifyInfo.getProfileStr())); @@ -864,6 +936,9 @@ class ModuleJsonUtil { hapVerifyInfo.setModuleType(parseStageIsEntry(hapVerifyInfo.getProfileStr())); hapVerifyInfo.setDependencyItemList(parseDependencies(hapVerifyInfo.getProfileStr(), bundleName)); hapVerifyInfo.setInstallationFree(parseStageInstallation(hapVerifyInfo.getProfileStr())); + hapVerifyInfo.setAtomicServiceModuleType( + parseAtomicServiceModuleType(hapVerifyInfo.getProfileStr())); + hapVerifyInfo.setPreloadModules(parsePreloadModules(hapVerifyInfo.getProfileStr())); } /** @@ -890,6 +965,7 @@ class ModuleJsonUtil { hapVerifyInfo.setPackageName(parseFaPackageStr(hapVerifyInfo.getProfileStr())); hapVerifyInfo.setDependencyItemList(parseDependencies(hapVerifyInfo.getProfileStr(), bundleName)); hapVerifyInfo.setInstallationFree(parseFAInstallationFree(hapVerifyInfo.getProfileStr())); + hapVerifyInfo.setAppType(parseFAappType(hapVerifyInfo.isInstallationFree())); } /** @@ -1299,6 +1375,165 @@ class ModuleJsonUtil { return hqfVerifyInfo; } + /** + * get the atomicServiceModuleType from json file. + * + * @param jsonString uncompress json object + * @throws BundleException Throws this exception if the json is not standard. + * @return the result + */ + public static String parseAtomicServiceModuleType(String jsonString) throws BundleException { + JSONObject jsonObject; + try { + jsonObject = JSON.parseObject(jsonString); + } catch (JSONException exception) { + String errMsg = "parse JSONobject failed"; + LOG.error(errMsg); + throw new BundleException(errMsg); + } + JSONObject appObj = jsonObject.getJSONObject(APP); + if (appObj == null) { + LOG.error("Error: parsePatch failed, input patch.json is invalid, patch.json has no app!"); + throw new BundleException("Error: parsePatch failed, input patch.json is invalid!"); + } + JSONObject moduleObj = jsonObject.getJSONObject(MODULE); + if (moduleObj == null) { + LOG.error("ModuleJsonUtil::parseAtomicServiceModuleType json object do not contain app!"); + throw new BundleException("ModuleJsonUtil::parseAtomicServiceModuleType json object do not contain app!"); + } + if (parseappType(jsonString).equals(APP)) { + return NORMAL_MODULE; + } + if (appObj.containsKey(ATOMIC_SERVICE)) { + return CheckAtomicServiceModuleType(jsonString); + } + if (parseStageInstallation(jsonString)) { + if (parseStageEntry(jsonString).equals(ENTRY)) { + return MAIN_MODULE; + } + else { + return NORMAL_MODULE; + } + } + return NORMAL_MODULE; + } + + public static String CheckAtomicServiceModuleType(String jsonString) throws BundleException { + JSONObject jsonObject; + try { + jsonObject = JSON.parseObject(jsonString); + } catch (JSONException exception) { + String errMsg = "parse JSONobject failed"; + LOG.error(errMsg); + throw new BundleException(errMsg); + } + JSONObject appObj = jsonObject.getJSONObject(APP); + JSONObject moduleObj = jsonObject.getJSONObject(MODULE); + JSONObject atomicObj = appObj.getJSONObject(ATOMIC_SERVICE); + if (!atomicObj.containsKey(SPLIT)) { + LOG.error("app atomicService json object do not contain split!"); + throw new BundleException("app atomicService json object do not contain split!"); + } + if (atomicObj.getBoolean(SPLIT)) { + if (!atomicObj.containsKey(MAIN_MODULE)) { + LOG.error("app atomicService json object must contain main when split is true!"); + throw new BundleException("app atomicService json object must contain main when split is true!"); + } + if (getJsonString(atomicObj, MAIN_MODULE).equals(parseStageModuleName(jsonString))) { + if (!parseStageIsEntry(jsonString).equals(ENTRY)) { + LOG.error("module type must be entry when the module is main in atomic service!"); + throw new BundleException("module type must be entry " + + "when the module is main in atomic service!"); + } + return MAIN_MODULE; + } + else { + if (parseStageIsEntry(jsonString).equals(ENTRY)) { + LOG.error("module type can not be entry when the module is normal in atomic service!"); + throw new BundleException("module type can not be entry " + + "when the module is normal in atomic service!"); + } + return NORMAL_MODULE; + } + } + else { + if (atomicObj.containsKey(MAIN_MODULE)) { + LOG.error("need not to specify main when split is false!"); + throw new BundleException("need not to specify main when split is false!"); + } + if (moduleObj.containsKey(ATOMIC_SERVICE)) { + JSONObject moduleAtomicObj = moduleObj.getJSONObject(ATOMIC_SERVICE); + if (moduleAtomicObj.containsKey(PRELOADS)) { + LOG.error("can not have preloads when split is false!"); + throw new BundleException("can not have preloads when split is false!"); + } + } + } + return NORMAL_MODULE; + } + + /** + * parse preload config in module. + * + * @param jsonString is the string of module.json + * @return preloadModules is the result of parsed preload config + */ + public static List parsePreloadModules(String jsonString) throws BundleException { + JSONObject jsonObject; + try { + jsonObject = JSON.parseObject(jsonString); + } catch (JSONException exception) { + String errMsg = "parse JSONobject failed"; + LOG.error(errMsg); + throw new BundleException(errMsg); + } + JSONObject moduleObj = jsonObject.getJSONObject(MODULE); + if (moduleObj == null) { + LOG.error("ModuleJsonUtil::parsePreloadModules failed, module is null!"); + throw new BundleException("ModuleJsonUtil::parsePreloadModules failed, module is null!"); + } + JSONObject appObj = jsonObject.getJSONObject(APP); + if (appObj == null) { + LOG.error("ModuleJsonUtil::parsePreloadModules failed, module is null!"); + throw new BundleException("ModuleJsonUtil::parsePreloadModules failed, module is null!"); + } + if (moduleObj.containsKey(ATOMIC_SERVICE) && !appObj.containsKey(ATOMIC_SERVICE)) { + LOG.error("app must have atomicService when module have atomicService!"); + throw new BundleException("app must have atomicService when module have atomicService!"); + } + List preloadItems = new ArrayList<>(); + if (!moduleObj.containsKey(ATOMIC_SERVICE)) { + return preloadItems; + } + JSONObject atomicObj = moduleObj.getJSONObject(ATOMIC_SERVICE); + if (atomicObj.containsKey(PRELOADS)) { + JSONArray preloadInfos = atomicObj.getJSONArray(PRELOADS); + for (int i = 0; i < preloadInfos.size(); i++) { + preloadItems.add(parsePreloadItem(preloadInfos.getJSONObject(i))); + } + } + + return preloadItems; + } + + /** + * parse preload info + * + * @param jsonObject Json hap json Object + * @return the preloadItem result + * @throws BundleException Throws this exception if the json is not standard. + */ + public static PreloadItem parsePreloadItem(JSONObject jsonObject) throws BundleException { + if (jsonObject == null) { + throw new BundleException("ModuleJsonUtil::parsePreloadItem failed, jsonObject is null"); + } + PreloadItem preloadInfo = new PreloadItem(); + if (jsonObject.containsKey(MODULE_NAME)) { + preloadInfo.moduleName = getJsonString(jsonObject, MODULE_NAME); + } + return preloadInfo; + } + public static boolean stageIsCompressNativeLibs(String jsonString) throws BundleException { JSONObject jsonObject; try { diff --git a/adapter/ohos/PackInfo.java b/adapter/ohos/PackInfo.java index f72feb9266401447c39fe6c7d3627c578f3e7065..5fd7333df5cb93a44369a81453f96cd7d81b8502 100644 --- a/adapter/ohos/PackInfo.java +++ b/adapter/ohos/PackInfo.java @@ -28,6 +28,11 @@ public class PackInfo { */ public String name = ""; + /** + * Indicates the name of PackInfo. + */ + public String appType = ""; + /** * Indicates the moduleName of PackInfo. */ diff --git a/adapter/ohos/PreloadItem.java b/adapter/ohos/PreloadItem.java new file mode 100644 index 0000000000000000000000000000000000000000..bc6500430030635c49cd4ad2f17c6dddec2da39e --- /dev/null +++ b/adapter/ohos/PreloadItem.java @@ -0,0 +1,8 @@ +package ohos; + +public class PreloadItem { + /** + * Indicates the name of module that is preloaded. + */ + public String moduleName = ""; +} diff --git a/adapter/ohos/VerifyCollection.java b/adapter/ohos/VerifyCollection.java index 03046c53002390d2d4315d8e70bf2facfa3c607b..8375f49b8c83b20818e1f4cb009afbd3b5a3f871 100644 --- a/adapter/ohos/VerifyCollection.java +++ b/adapter/ohos/VerifyCollection.java @@ -27,6 +27,14 @@ class VerifyCollection { * Indicates the bundleName of app. */ public String bundleName = ""; + /** + * Indicates the category of app. + */ + public String appType = "app"; + /** + * Indicates whether split the bundle in atomicService. + */ + public boolean split = false; /** * Indicates the vendor of app. */ @@ -55,6 +63,10 @@ class VerifyCollection { * Indicates the apiReleaseType of app. */ public String releaseType = ""; + /** + * Indicates the category of module in atomicService. + */ + public String atomicServiceModuleType = "normal"; /** * Indicates the moduleNames of app. */ @@ -63,4 +75,8 @@ class VerifyCollection { * Indicates the packageNames of app. */ List packageNames = new ArrayList<>(); + /** + * Indicates the preload modules of module in atomicService. + */ + List preloadModules = new ArrayList<>(); } diff --git a/modulecheck/app.json b/modulecheck/app.json index fe9ed1e28c03102490701013b39bcd944ebf950b..8f0cb5aeedbf9993db314be7fec17cf186da5560 100644 --- a/modulecheck/app.json +++ b/modulecheck/app.json @@ -26,6 +26,7 @@ "enum": [ "bundleName", "debug", + "atomicService", "icon", "label", "description", @@ -44,6 +45,7 @@ "userDataClearable", "accessible", "multiProjects", + "asanEnabled", "default", "tablet", "tv", @@ -59,6 +61,70 @@ "minLength": 7, "pattern": "^[a-zA-Z][0-9a-zA-Z_.]+$" }, + "atomicService": { + "description": "Indicates the config for atomic service.", + "type": "object", + "propertyNames": { + "enum": [ + "split", + "main" + ] + }, + "required": [ + "split" + ], + "properties": { + "split": { + "description": "Indicates whether to split bundle in atomicService.", + "type": "boolean", + "default": true + }, + "main": { + "description": "Indicates the name of main module when split is true.", + "type": "string", + "maxLength": 31 + } + }, + "allOf": [ + { + "if": { + "properties": { + "split": { + "const": true + } + } + }, + "then": { + "propertyNames": { + "enum": [ + "split", + "main" + ], + "required": [ + "split", + "main" + ] + } + } + }, + { + "if": { + "properties": { + "split": { + "const": false + } + } + }, + "then": { + "propertyNames": { + "enum": [ + "split" + ] + } + } + } + ] + }, "debug": { "description": "Identify whether the application can be debugged.", "type": "boolean", diff --git a/modulecheck/module.json b/modulecheck/module.json index 20c1851739901c236aca11e451eaf5c16db01018..b8c511f9f53891ee5234938050e4e2bc4d9b4d85 100644 --- a/modulecheck/module.json +++ b/modulecheck/module.json @@ -37,7 +37,9 @@ "requestPermissions", "dependencies", "libIsolation", - "compressNativeLibs" + "compressNativeLibs", + "installationFree", + "atomicService" ] }, "required": [ @@ -116,7 +118,8 @@ "testRunner", "dependencies", "libIsolation", - "compressNativeLibs" + "compressNativeLibs", + "atomicService" ] }, "required": [ @@ -159,7 +162,8 @@ "testRunner", "dependencies", "libIsolation", - "compressNativeLibs" + "compressNativeLibs", + "atomicService" ] }, "required": [ @@ -290,6 +294,7 @@ "abilities": { "description": "Indicates all abilities in the current module. The value is an array of objects, each of which represents an ability.This label can be left blank by default,and indicates no capability exists in the current module.", "type": "array", + "uniqueItems": true, "items": { "type": "object", "required": [ @@ -1070,6 +1075,37 @@ "description": "Specifies whether the libs libraries of the .hap file are compressed for storage. If this attribute is set to false, the libs libraries are stored without being compressed and will be directly loaded during the installation of the .hap file.", "type": "boolean", "default": true + }, + "atomicService": { + "description": "Indicates the module config in atomic service.", + "type": "object", + "propertyNames": { + "enum": [ + "preloads" + ] + }, + "properties": { + "preloads": { + "description": "Indicates modules are preloaded when the current module is run.", + "type": "array", + "uniqueItems": true, + "items": { + "type": "object", + "propertyNames": { + "enum": [ + "moduleName" + ] + }, + "properties": { + "moduleName": { + "description": "Indicates module is preloaded when the current module is run.", + "type": "string", + "maxLength": 31 + } + } + } + } + } } } } diff --git a/packingTool.sh b/packingTool.sh index a582626be882d51c275e54a328d180de467a9924..58f379641e29ea449469280eaedfc3e5f9c48c4c 100755 --- a/packingTool.sh +++ b/packingTool.sh @@ -63,6 +63,7 @@ declare -a compile_class=( "HQFVerify" "HQFInfo" "DependencyItem" + "PreloadItem" ) compile_class_length=${#compile_class[@]} for ((i=0; i<${compile_class_length};++i)) diff --git a/unpackingTool.sh b/unpackingTool.sh index 99b671321b67299d2775f72d6e82da9f999e6887..a804ebc36ae5ebca17496ee10c5bed6cae969937 100755 --- a/unpackingTool.sh +++ b/unpackingTool.sh @@ -95,6 +95,7 @@ declare -a unpack_class=( "FileUtils.java" "HQFInfo.java" "APPQFResult.java" + "PreloadItem.java" ) unpack_class_length=${#unpack_class[@]} for ((i=0; i<${unpack_class_length};++i))