From 444027b3547ce32977120d6a2b972f03cddc6a0c Mon Sep 17 00:00:00 2001 From: longwei Date: Thu, 11 Aug 2022 12:40:00 +0800 Subject: [PATCH 1/3] add process for app in stage Signed-off-by: longwei Change-Id: I10b8fdf45ada02a62ff596d55e7e84c7068e73b6 --- modulecheck/app.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/modulecheck/app.json b/modulecheck/app.json index d0fdc0a3..274c6c9e 100644 --- a/modulecheck/app.json +++ b/modulecheck/app.json @@ -44,6 +44,7 @@ "userDataClearable", "accessible", "targetBundleList", + "process", "default", "tablet", "tv", @@ -178,6 +179,11 @@ "type": "string" } }, + "process": { + "description": "Indicates the process name of thi application. If config thie word, every ability in this application will be under this process.", + "type": "string", + "maxLength": 127 + }, "default": { "description": "The configuration in the default tag is applicable to all devices. If the configuration is different for other device types, you need to configure the configuration under the configuration tag of the device type.", "type": "object", -- Gitee From 8338afccf4397af2fad088ae378134c16713173d Mon Sep 17 00:00:00 2001 From: longwei Date: Tue, 16 Aug 2022 21:11:56 +0800 Subject: [PATCH 2/3] compile haptobin in packingtool Signed-off-by: longwei Change-Id: Ifd6ac029c66ee60729aa4e583056bb3c7e902e30 --- BUILD.gn | 118 +---------------------- adapter/bundles/packing_tool/bundle.json | 23 ----- build.py | 22 +++++ build.pydeps | 1 + bundle.json | 29 ++++++ haptobin.sh | 39 ++++++++ modulecheck/app.json | 6 -- packingtool.gni | 19 ++++ 8 files changed, 114 insertions(+), 143 deletions(-) delete mode 100644 adapter/bundles/packing_tool/bundle.json create mode 100755 build.py create mode 100644 build.pydeps create mode 100755 bundle.json create mode 100755 haptobin.sh create mode 100755 packingtool.gni diff --git a/BUILD.gn b/BUILD.gn index 7c1c8f19..0d9c3a47 100755 --- a/BUILD.gn +++ b/BUILD.gn @@ -11,119 +11,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -import("//build/config/ohos/rules.gni") -import("//build/ohos.gni") -import("//developtools/developtools.gni") +import("//developtools/packing_tool/packingtool.gni") -java_library("app_packing_tool_java") { - java_files = [ - "adapter/ohos/BundleException.java", - "adapter/ohos/CommandParser.java", - "adapter/ohos/CompressEntrance.java", - "adapter/ohos/Compressor.java", - "adapter/ohos/CompressVerify.java", - "adapter/ohos/Log.java", - "adapter/ohos/ShowHelp.java", - "adapter/ohos/Utility.java", - "adapter/ohos/ModuleJsonUtil.java", - "adapter/ohos/Version.java", - ] - - main_class = "ohos.CompressEntrance" - - final_jar_path = "$root_build_dir/developtools/app_packing_tool.jar" -} - -java_library("app_unpacking_tool_java") { - java_files = [ - "adapter/ohos/BundleException.java", - "adapter/ohos/CommandParser.java", - "adapter/ohos/Log.java", - "adapter/ohos/ShowHelp.java", - "adapter/ohos/UncompressEntrance.java", - "adapter/ohos/Uncompress.java", - "adapter/ohos/UncompressVerify.java", - "adapter/ohos/Utility.java", - "adapter/ohos/HapInfo.java", - "adapter/ohos/ReqPermission.java", - "adapter/ohos/Distro.java", - "adapter/ohos/AbilityInfo.java", - "adapter/ohos/MetaData.java", - "adapter/ohos/MetaDataInfo.java", - "adapter/ohos/SkillInfo.java", - "adapter/ohos/UsedScene.java", - "adapter/ohos/PackInfo.java", - "adapter/ohos/FormInfo.java", - "adapter/ohos/ProfileInfo.java", - "adapter/ohos/AppInfo.java", - "adapter/ohos/DefPermission.java", - "adapter/ohos/DefPermissionGroup.java", - "adapter/ohos/CustomizeData.java", - "adapter/ohos/UncomperssResult.java", - "adapter/ohos/JsonUtil.java", - "adapter/ohos/JsInfo.java", - "adapter/ohos/DeviceConfig.java", - "adapter/ohos/CommonEvent.java", - "adapter/ohos/Shortcut.java", - "adapter/ohos/IntentInfo.java", - "adapter/ohos/ResourcesParser.java", - "adapter/ohos/DistroFilter.java", - "adapter/ohos/ApiVersion.java", - "adapter/ohos/ScreenShape.java", - "adapter/ohos/ScreenDensity.java", - "adapter/ohos/ScreenWindow.java", - "adapter/ohos/CountryCode.java", - "adapter/ohos/HapZipInfo.java", - "adapter/ohos/AbilityFormInfo.java", - ] - - deps = [ "//third_party/fastjson/repackaged:fastjson_utils_java" ] - - java_manifest_file = "META-INF/unpacking_tool/MANIFEST.MF" - - main_class = "ohos.UncompressEntrance" - - final_jar_path = "$root_build_dir/developtools/app_unpacking_tool.jar" -} - -java_library("haptobin_tool_java") { - java_files = [ - "adapter/ohos/Log.java", - "adapter/ohos/BinaryTool.java", - "adapter/ohos/FileUtils.java", - "adapter/ohos/ConvertHapToBin.java", - ] - - deps = [ "//third_party/fastjson/repackaged:fastjson_utils_java" ] - - java_manifest_file = "META-INF/packingbin_tool/MANIFEST.MF" - - main_class = "ohos.ConvertHapToBin" - - final_jar_path = "$root_build_dir/developtools/haptobin_tool.jar" -} - -java_library("bininfo_collecting_tool_java") { - java_files = [ - "adapter/ohos/Log.java", - "adapter/ohos/FileUtils.java", - "adapter/ohos/CollectBinInfo.java", - ] - - deps = [ "//third_party/fastjson/repackaged:fastjson_utils_java" ] - - java_manifest_file = "META-INF/collectingbininfo_tool/MANIFEST.MF" - - main_class = "ohos.CollectBinInfo" - - final_jar_path = "$root_build_dir/developtools/bininfo_collecting_tool.jar" -} - -group("packing_tool_target") { - deps = [ - ":app_packing_tool_java", - ":app_unpacking_tool_java", - ":bininfo_collecting_tool_java", - ":haptobin_tool_java", - ] +packing_tool("packing_tool") { + sources = ["//developtools/packing_tool/haptobin.sh"] + outputs = ["${target_out_dir}/haptobin.jar"] } diff --git a/adapter/bundles/packing_tool/bundle.json b/adapter/bundles/packing_tool/bundle.json deleted file mode 100644 index 131fbf25..00000000 --- a/adapter/bundles/packing_tool/bundle.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "packing_tool", - "version": "1.0.0", - "publishAs": "code-segment", - "description": "packing_tool for dev", - "keywords": [ - "packing", - "unpacking", - "linux" - ], - "component": { - "name": "packing_tool", - "subsystem": "developtools", - "adapted_system_type": [ "mini", "small", "standard" ], - "deps": { - "components": [], - "third_party": [ "fastjson" ] - }, - "build": { - "sub_component": [] - } - } -} diff --git a/build.py b/build.py new file mode 100755 index 00000000..4a0b845d --- /dev/null +++ b/build.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +import os +import sys +import argparse + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--input', required=True) + parser.add_argument('--output', required=True) + args = parser.parse_args() + rootDir = os.path.dirname(os.path.realpath(__file__)) + + print("rootDir is " + rootDir) + print(args.input) + print(args.output) + # compile haptobin + command = "sh " + args.input + ' ' + rootDir + ' ' + args.output + os.system(command) + +if __name__ == '__main__': + sys.exit(main()) \ No newline at end of file diff --git a/build.pydeps b/build.pydeps new file mode 100644 index 00000000..3fb299e8 --- /dev/null +++ b/build.pydeps @@ -0,0 +1 @@ +build.py diff --git a/bundle.json b/bundle.json new file mode 100755 index 00000000..2cbf5aef --- /dev/null +++ b/bundle.json @@ -0,0 +1,29 @@ +{ + "name": "packing_tool", + "version": "3.2", + "license": "Apache License 2.0", + "publishAs": "code-segment", + "description": "packing_tool for openharmony", + "segment": { + "destPath": "developtools/packing_tool" + }, + "keywords": [ + "packing", + "unpacking", + "linux" + ], + "component": { + "name": "packing_tool", + "subsystem": "developtools", + "adapted_system_type": [ "mini", "small", "standard" ], + "deps": { + "components": [] + }, + "build": { + "sub_component": [ + "//developtools/packing_tool:packing_tool" + ] + } + } +} + \ No newline at end of file diff --git a/haptobin.sh b/haptobin.sh new file mode 100755 index 00000000..07d216b6 --- /dev/null +++ b/haptobin.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +rootPath=$1 +outPath=$2 +echo ${rootPath} +tempPath="." +jar_dir="jar" +haptobin_jar_file="haptobin_tool.jar" +haptobin_jar_path="$rootPath/$jar_dir/$haptobin_jar_file" +manifest_path=$rootPath/META-INF/packingbin_tool/MANIFEST.MF +echo ${manifest_path} +# compile java class +out_dir="$rootPath/out/production/packing_tool" +java_suffix=".java" +class_suffix=".class" +out_class="$tempPath/$out_dir" +java_collection="" +class_collextion="" +declare -a compile_class=( + "Log" + "BinaryTool" + "FileUtils" + "ConvertHapToBin" + "BundleException" + "Utility" +) +compile_class_length=${#compile_class[@]} +for ((i=0; i<${compile_class_length};++i)) +do + java_collection="${java_collection} ${rootPath}/adapter/ohos/${compile_class[$i]}${java_suffix}" + class_collextion="${class_collextion} ohos/${compile_class[$i]}${class_suffix}" +done +compile_command="javac -d ${out_dir} ${java_collection}" +eval ${compile_command} + +cd ${out_dir} +pack_command="jar -cvfm ${haptobin_jar_path} ${manifest_path} ${class_collextion}" +eval ${pack_command} +cp_command="cp ${haptobin_jar_path} ${outPath}" +eval ${cp_command} \ No newline at end of file diff --git a/modulecheck/app.json b/modulecheck/app.json index 274c6c9e..d0fdc0a3 100644 --- a/modulecheck/app.json +++ b/modulecheck/app.json @@ -44,7 +44,6 @@ "userDataClearable", "accessible", "targetBundleList", - "process", "default", "tablet", "tv", @@ -179,11 +178,6 @@ "type": "string" } }, - "process": { - "description": "Indicates the process name of thi application. If config thie word, every ability in this application will be under this process.", - "type": "string", - "maxLength": 127 - }, "default": { "description": "The configuration in the default tag is applicable to all devices. If the configuration is different for other device types, you need to configure the configuration under the configuration tag of the device type.", "type": "object", diff --git a/packingtool.gni b/packingtool.gni new file mode 100755 index 00000000..aebc3889 --- /dev/null +++ b/packingtool.gni @@ -0,0 +1,19 @@ +import("//build/config/python.gni") + +template("packing_tool") { + action_with_pydeps(target_name) { + forward_variables_from( + invoker, + [ + "sources", + "outputs" + ]) + script = "//developtools/packing_tool/build.py" + args = [ + "--input", + rebase_path(sources[0], root_out_dir), + "--output", + rebase_path(outputs[0], root_out_dir), + ] + } +} \ No newline at end of file -- Gitee From 153d74f4facc7a95f20aeab7a200ad1a6a27f15b Mon Sep 17 00:00:00 2001 From: longwei Date: Tue, 16 Aug 2022 21:11:56 +0800 Subject: [PATCH 3/3] fix fileUtil Signed-off-by: longwei Change-Id: I216ea55062d6781534ded56a9e83c14531b99d0b --- adapter/ohos/BinaryTool.java | 3 +- adapter/ohos/Compressor.java | 51 ++++++++++++++- adapter/ohos/FileUtils.java | 123 +++++++++++------------------------ jar/haptobin_tool.jar | Bin 11432 -> 0 bytes 4 files changed, 88 insertions(+), 89 deletions(-) delete mode 100644 jar/haptobin_tool.jar diff --git a/adapter/ohos/BinaryTool.java b/adapter/ohos/BinaryTool.java index c3012787..5fd13edb 100644 --- a/adapter/ohos/BinaryTool.java +++ b/adapter/ohos/BinaryTool.java @@ -87,8 +87,7 @@ public class BinaryTool { * @return true: success, false: fail */ private static boolean writePackageInfo(final String filePath, RandomAccessFile appStream) { - Optional packageName = FileUtils.getValueFromJsonFileContent(PROFILE_KEY, PACKAGE_KEY, - JSON_FILE_NAME, filePath); + Optional packageName = FileUtils.getBundleNameFromFileContent(JSON_FILE_NAME, filePath); if (!packageName.isPresent()) { LOG.error("have no config.json or have no key of package!"); return false; diff --git a/adapter/ohos/Compressor.java b/adapter/ohos/Compressor.java index 36bb937a..672a5e0a 100644 --- a/adapter/ohos/Compressor.java +++ b/adapter/ohos/Compressor.java @@ -1993,7 +1993,7 @@ public class Compressor { * @return hapVerifyInfo */ public static HapVerifyInfo parseStageHapVerifyInfo(String filePath) throws BundleException { - HapVerifyInfo hapVerifyInfo = FileUtils.readStageHapVerifyInfo(filePath); + HapVerifyInfo hapVerifyInfo = readStageHapVerifyInfos.(filePath); hapVerifyInfo.setStageModule(true); ModuleJsonUtil.parseStageHapVerifyInfo(hapVerifyInfo); return hapVerifyInfo; @@ -2006,7 +2006,7 @@ public class Compressor { * @return hapVerifyInfo */ public static HapVerifyInfo parseFAHapVerifyInfo(String filePath) throws BundleException { - HapVerifyInfo hapVerifyInfo = FileUtils.readFAHapVerifyInfo(filePath); + HapVerifyInfo hapVerifyInfo = readFAHapVerifyInfo(filePath); hapVerifyInfo.setStageModule(false); ModuleJsonUtil.parseFAHapVerifyInfo(hapVerifyInfo); return hapVerifyInfo; @@ -2062,4 +2062,51 @@ public class Compressor { } return true; } + + /** + * read stage hap verify info from hap file. + * + * @param srcPath source file to zip + * @return HapVerifyInfo of parse result + * @throws BundleException FileNotFoundException|IOException. + */ + public static HapVerifyInfo readStageHapVerifyInfo(String srcPath) throws BundleException { + HapVerifyInfo hapVerifyInfo = new HapVerifyInfo(); + ZipFile zipFile = null; + try { + File srcFile = new File(srcPath); + zipFile = new ZipFile(srcFile); + hapVerifyInfo.setResourceMap(FileUtils.getProfileJson(zipFile)); + hapVerifyInfo.setProfileStr(FileUtils.getFileStringFromZip(MODULE_JSON, zipFile)); + } catch (IOException e) { + LOG.error("FileUtil::parseStageHapVerifyInfo file not available!"); + throw new BundleException("FileUtil::parseStageHapVerifyInfo file not available!"); + } finally { + Utility.closeStream(zipFile); + } + return hapVerifyInfo; + } + + /** + * read fa hap verify info from hap file. + * + * @param srcPath source file to zip + * @return HapVerifyInfo of parse result + * @throws BundleException FileNotFoundException|IOException. + */ + public static HapVerifyInfo readFAHapVerifyInfo(String srcPath) throws BundleException { + HapVerifyInfo hapVerifyInfo = new HapVerifyInfo(); + ZipFile zipFile = null; + try { + File srcFile = new File(srcPath); + zipFile = new ZipFile(srcFile); + hapVerifyInfo.setProfileStr(FileUtils.getFileStringFromZip(CONFIG_JSON, zipFile)); + } catch (IOException e) { + LOG.error("FileUtil::parseStageHapVerifyInfo file not available."); + throw new BundleException("FileUtil::parseStageHapVerifyInfo file not available."); + } finally { + Utility.closeStream(zipFile); + } + return hapVerifyInfo; + } } diff --git a/adapter/ohos/FileUtils.java b/adapter/ohos/FileUtils.java index e4284093..764154b0 100644 --- a/adapter/ohos/FileUtils.java +++ b/adapter/ohos/FileUtils.java @@ -15,8 +15,6 @@ package ohos; -import ohos.utils.fastjson.JSONObject; - import java.io.*; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; @@ -40,6 +38,8 @@ class FileUtils { private static final String CONFIG_JSON = "config.json"; private static final String SHA256 = "SHA-256"; private static final int SHA256_BUFFER_SIZE = 10240; + public static String bundleName = "\"bundleName\":"; + public static char quotation = '\"'; /** * generate fileData byte stream @@ -156,41 +156,6 @@ class FileUtils { return Optional.ofNullable(content.toString()); } - /** - * get special value from JSON String - * - * @param key json main key - * @param subKey json sub key - * @param jsonFileName json file name - * @param filePath path which will be searched - * @return value - */ - public static Optional getValueFromJsonFileContent(final String key, final String subKey, - final String jsonFileName, final String filePath) { - Optional jsonFilePath = searchFile(jsonFileName, filePath); - if (!jsonFilePath.isPresent()) { - return Optional.empty(); - } - - Optional jsonStr = getFileContent(jsonFilePath.get()); - if (!jsonStr.isPresent()) { - return Optional.empty(); - } - - JSONObject jsonObject = JSONObject.parseObject(jsonStr.get()); - if (jsonObject == null) { - return Optional.empty(); - } - - if (!jsonObject.containsKey(key)) { - return Optional.empty(); - } - - JSONObject subObject = jsonObject.getJSONObject(key); - String value = subObject.getString(subKey); - return Optional.of(value); - } - /** * close file stream * @@ -448,53 +413,6 @@ class FileUtils { return jsonStr.toString(); } - /** - * read stage hap verify info from hap file. - * - * @param srcPath source file to zip - * @return HapVerifyInfo of parse result - * @throws BundleException FileNotFoundException|IOException. - */ - public static HapVerifyInfo readStageHapVerifyInfo(String srcPath) throws BundleException { - HapVerifyInfo hapVerifyInfo = new HapVerifyInfo(); - ZipFile zipFile = null; - try { - File srcFile = new File(srcPath); - zipFile = new ZipFile(srcFile); - hapVerifyInfo.setResourceMap(getProfileJson(zipFile)); - hapVerifyInfo.setProfileStr(getFileStringFromZip(MODULE_JSON, zipFile)); - } catch (IOException e) { - LOG.error("FileUtil::parseStageHapVerifyInfo file not available!"); - throw new BundleException("FileUtil::parseStageHapVerifyInfo file not available!"); - } finally { - Utility.closeStream(zipFile); - } - return hapVerifyInfo; - } - - /** - * read fa hap verify info from hap file. - * - * @param srcPath source file to zip - * @return HapVerifyInfo of parse result - * @throws BundleException FileNotFoundException|IOException. - */ - public static HapVerifyInfo readFAHapVerifyInfo(String srcPath) throws BundleException { - HapVerifyInfo hapVerifyInfo = new HapVerifyInfo(); - ZipFile zipFile = null; - try { - File srcFile = new File(srcPath); - zipFile = new ZipFile(srcFile); - hapVerifyInfo.setProfileStr(getFileStringFromZip(CONFIG_JSON, zipFile)); - } catch (IOException e) { - LOG.error("FileUtil::parseStageHapVerifyInfo file not available."); - throw new BundleException("FileUtil::parseStageHapVerifyInfo file not available."); - } finally { - Utility.closeStream(zipFile); - } - return hapVerifyInfo; - } - /** * get all resource file in profile. * @@ -551,7 +469,7 @@ class FileUtils { } } - /** + /** * get sha-256 for file * * @param hapPath is the input path of file @@ -588,4 +506,39 @@ class FileUtils { } return hexString.toString(); } + + public static Optional getBundleNameFromFileContent(final String jsonFileName, final String filePath) { + Optional jsonFilePath = searchFile(jsonFileName, filePath); + if (!jsonFilePath.isPresent()) { + return Optional.empty(); + } + + Optional jsonOptional= getFileContent(jsonFilePath.get()); + if (!jsonOptional.isPresent()) { + return Optional.empty(); + } + String jsonStr = jsonOptional.get().replaceAll("\r\n|\r|\n", ""); + return Optional.of(getBundleName(jsonStr)); + } + + private static String getBundleName(String jsonStr) { + String realStr = jsonStr.replaceAll(" ", ""); + if (!realStr.contains(bundleName)) { + return ""; + } + int index = realStr.indexOf(bundleName); + String res = ""; + index += bundleName.length(); + int left = index; + while (realStr.charAt(left) != quotation) { + ++left; + } + ++left; + int right = left; + while (realStr.charAt(right) != quotation) { + ++right; + } + res = realStr.substring(left, right); + return res; + } } \ No newline at end of file diff --git a/jar/haptobin_tool.jar b/jar/haptobin_tool.jar deleted file mode 100644 index 4fb57fe39514b491a5548394fbb6c0ed16fe8242..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11432 zcmaKy1yCK$vVeno2<{r(Ik*Q1esFg=*uf>Z1b2eF1_%zp-QC^Y-6c4@%9y`<{8L$0SWZe@Oj(6VR-9umP^?NMs^aMh>l^3gF`jQzF?j>E&iLrQ&t@4W5LbQ=suF|2=2#`*X8*K{ia z|Mgwp|GsN$ZtKVlv^8S_Ss6My2F5)pqbp+ex8tZ`&!wTF>*G;rY(gD=|JA{+$P(s@ z_c_g5XCvsiw6wZ;;l|8_?O+D@_0w0C>Bi_NOndCHH4ozT@k~dTuWt{RNFC&Y=D43# zy4i_gS$rfQ_{D)XW-22V7i9PygnJwS`$pYpDl&}BfevMG=HRI#RybWEZcDx@2zUJS zSi(JL6W`R2kRw-5X6JzEgu>spw~*kBPLyU&j?D?twwcp}(##nz9;Jj1_t8;YcZUGZ z#4zcmN-EP}toUHB+=js6ZM>+#Bd9xjw^U#_22%u@F8_?%?Im0F3rg37GS)7vK;c~n zSqbj#I5tn9wKk`ewKhsKIUp$hE^f~TxYIXGPHxVay#a%85IWg67eI8vo`6UI-?5+JhR9EaH5{xYVlJwEHuq_} zqRUjf@j0Z7zU5N`ao(Pu7#6&lsN-Hw&h}oGIjK)nimmHpuFVGI&Y;W_pDZWMM|VlK zvqfNmvt$di%OW$@utNZ4Mm}2T3rYInmr}u(3x$~y!YMzz?-E37e6(`vfvNoe86TR*8@nAYH9<=f(y^!JB`

Y3Ufgc(39Z#`XeqW8A&HZ&YLj86hV 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 NLA-l6LigwDzW~JaQAz*+ -- Gitee