• 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 #include "quick_fix/patch_profile.h"
17 
18 #include <mutex>
19 #include <sstream>
20 
21 #include "app_log_wrapper.h"
22 #include "bundle_constants.h"
23 #include "bundle_util.h"
24 #include "json_util.h"
25 #include "parameter.h"
26 #include "string_ex.h"
27 
28 namespace OHOS {
29 namespace AppExecFwk {
30 namespace PatchProfileReader {
31 constexpr const char* BUNDLE_PATCH_PROFILE_APP_KEY_BUNDLE_NAME = "bundleName";
32 constexpr const char* BUNDLE_PATCH_PROFILE_APP_KEY_VERSION_CODE = "versionCode";
33 constexpr const char* BUNDLE_PATCH_PROFILE_APP_KEY_VERSION_NAME = "versionName";
34 constexpr const char* BUNDLE_PATCH_PROFILE_APP_KEY_PATCH_VERSION_CODE = "patchVersionCode";
35 constexpr const char* BUNDLE_PATCH_PROFILE_APP_KEY_PATCH_VERSION_NAME = "patchVersionName";
36 constexpr const char* BUNDLE_PATCH_PROFILE_MODULE_KEY_NAME = "name";
37 constexpr const char* BUNDLE_PATCH_PROFILE_MODULE_KEY_TYPE = "type";
38 constexpr const char* BUNDLE_PATCH_PROFILE_MODULE_KEY_DEVICE_TYPES = "deviceTypes";
39 constexpr const char* BUNDLE_PATCH_PROFILE_MODULE_KEY_ORIGINAL_MODULE_HASH = "originalModuleHash";
40 constexpr const char* BUNDLE_PATCH_PROFILE_KEY_APP = "app";
41 constexpr const char* BUNDLE_PATCH_PROFILE_KEY_MODULE = "module";
42 constexpr const char* BUNDLE_PATCH_TYPE_PATCH = "patch";
43 constexpr const char* BUNDLE_PATCH_TYPE_HOT_RELOAD = "hotreload";
44 
45 int32_t g_parseResult = ERR_OK;
46 std::mutex g_mutex;
47 struct App {
48     std::string bundleName;
49     uint32_t versionCode = 0;
50     std::string versionName;
51     uint32_t patchVersionCode = 0;
52     std::string patchVersionName;
53 };
54 
55 struct Module {
56     std::string name;
57     std::string type;
58     std::vector<std::string> deviceTypes;
59     std::string originalModuleHash;
60 };
61 
62 struct PatchJson {
63     App app;
64     Module module;
65 };
66 
from_json(const nlohmann::json & jsonObject,App & app)67 void from_json(const nlohmann::json &jsonObject, App &app)
68 {
69     const auto &jsonObjectEnd = jsonObject.end();
70     GetValueIfFindKey<std::string>(jsonObject,
71         jsonObjectEnd,
72         BUNDLE_PATCH_PROFILE_APP_KEY_BUNDLE_NAME,
73         app.bundleName,
74         JsonType::STRING,
75         true,
76         g_parseResult,
77         ArrayType::NOT_ARRAY);
78     GetValueIfFindKey<uint32_t>(jsonObject,
79         jsonObjectEnd,
80         BUNDLE_PATCH_PROFILE_APP_KEY_VERSION_CODE,
81         app.versionCode,
82         JsonType::NUMBER,
83         true,
84         g_parseResult,
85         ArrayType::NOT_ARRAY);
86     GetValueIfFindKey<std::string>(jsonObject,
87         jsonObjectEnd,
88         BUNDLE_PATCH_PROFILE_APP_KEY_VERSION_NAME,
89         app.versionName,
90         JsonType::STRING,
91         false,
92         g_parseResult,
93         ArrayType::NOT_ARRAY);
94     GetValueIfFindKey<uint32_t>(jsonObject,
95         jsonObjectEnd,
96         BUNDLE_PATCH_PROFILE_APP_KEY_PATCH_VERSION_CODE,
97         app.patchVersionCode,
98         JsonType::NUMBER,
99         true,
100         g_parseResult,
101         ArrayType::NOT_ARRAY);
102     GetValueIfFindKey<std::string>(jsonObject,
103         jsonObjectEnd,
104         BUNDLE_PATCH_PROFILE_APP_KEY_PATCH_VERSION_NAME,
105         app.patchVersionName,
106         JsonType::STRING,
107         false,
108         g_parseResult,
109         ArrayType::NOT_ARRAY);
110 }
111 
from_json(const nlohmann::json & jsonObject,Module & module)112 void from_json(const nlohmann::json &jsonObject, Module &module)
113 {
114     const auto &jsonObjectEnd = jsonObject.end();
115     GetValueIfFindKey<std::string>(jsonObject,
116         jsonObjectEnd,
117         BUNDLE_PATCH_PROFILE_MODULE_KEY_NAME,
118         module.name,
119         JsonType::STRING,
120         true,
121         g_parseResult,
122         ArrayType::NOT_ARRAY);
123     GetValueIfFindKey<std::string>(jsonObject,
124         jsonObjectEnd,
125         BUNDLE_PATCH_PROFILE_MODULE_KEY_TYPE,
126         module.type,
127         JsonType::STRING,
128         true,
129         g_parseResult,
130         ArrayType::NOT_ARRAY);
131     GetValueIfFindKey<std::vector<std::string>>(jsonObject,
132         jsonObjectEnd,
133         BUNDLE_PATCH_PROFILE_MODULE_KEY_DEVICE_TYPES,
134         module.deviceTypes,
135         JsonType::ARRAY,
136         false,
137         g_parseResult,
138         ArrayType::STRING);
139     GetValueIfFindKey<std::string>(jsonObject,
140         jsonObjectEnd,
141         BUNDLE_PATCH_PROFILE_MODULE_KEY_ORIGINAL_MODULE_HASH,
142         module.originalModuleHash,
143         JsonType::STRING,
144         false,
145         g_parseResult,
146         ArrayType::NOT_ARRAY);
147 }
148 
from_json(const nlohmann::json & jsonObject,PatchJson & patchJson)149 void from_json(const nlohmann::json &jsonObject, PatchJson &patchJson)
150 {
151     const auto &jsonObjectEnd = jsonObject.end();
152     GetValueIfFindKey<App>(jsonObject,
153         jsonObjectEnd,
154         BUNDLE_PATCH_PROFILE_KEY_APP,
155         patchJson.app,
156         JsonType::OBJECT,
157         true,
158         g_parseResult,
159         ArrayType::NOT_ARRAY);
160     GetValueIfFindKey<Module>(jsonObject,
161         jsonObjectEnd,
162         BUNDLE_PATCH_PROFILE_KEY_MODULE,
163         patchJson.module,
164         JsonType::OBJECT,
165         true,
166         g_parseResult,
167         ArrayType::NOT_ARRAY);
168 }
169 
GetQuickFixType(const std::string & type)170 QuickFixType GetQuickFixType(const std::string &type)
171 {
172     if (type == BUNDLE_PATCH_TYPE_PATCH) {
173         return QuickFixType::PATCH;
174     }
175     if (type == BUNDLE_PATCH_TYPE_HOT_RELOAD) {
176         return QuickFixType::HOT_RELOAD;
177     }
178     APP_LOGW("GetQuickFixType: unknow quick fix type");
179     return QuickFixType::UNKNOWN;
180 }
181 
CheckNameIsValid(const std::string & name)182 bool CheckNameIsValid(const std::string &name)
183 {
184     if (name.empty()) {
185         return false;
186     }
187     if (name.find(Constants::RELATIVE_PATH) != std::string::npos) {
188         return false;
189     }
190     return true;
191 }
192 
ToPatchInfo(const PatchJson & patchJson,AppQuickFix & appQuickFix)193 bool ToPatchInfo(const PatchJson &patchJson, AppQuickFix &appQuickFix)
194 {
195     if (!CheckNameIsValid(patchJson.app.bundleName)) {
196         APP_LOGE("bundle name is invalid");
197         return false;
198     }
199     if (!CheckNameIsValid(patchJson.module.name)) {
200         APP_LOGE("module name is invalid");
201         return false;
202     }
203     appQuickFix.bundleName = patchJson.app.bundleName;
204     appQuickFix.versionCode = patchJson.app.versionCode;
205     appQuickFix.versionName = patchJson.app.versionName;
206     appQuickFix.deployingAppqfInfo.versionCode = patchJson.app.patchVersionCode;
207     appQuickFix.deployingAppqfInfo.versionName = patchJson.app.patchVersionName;
208     appQuickFix.deployingAppqfInfo.type = GetQuickFixType(patchJson.module.type);
209     HqfInfo hqfInfo;
210     hqfInfo.moduleName = patchJson.module.name;
211     hqfInfo.hapSha256 = patchJson.module.originalModuleHash;
212     hqfInfo.type = GetQuickFixType(patchJson.module.type);
213     appQuickFix.deployingAppqfInfo.hqfInfos.emplace_back(hqfInfo);
214     return true;
215 }
216 }
217 
DefaultNativeSo(const PatchExtractor & patchExtractor,bool isSystemLib64Exist,AppqfInfo & appqfInfo)218 bool PatchProfile::DefaultNativeSo(
219     const PatchExtractor &patchExtractor, bool isSystemLib64Exist, AppqfInfo &appqfInfo)
220 {
221     if (isSystemLib64Exist) {
222         if (patchExtractor.IsDirExist(Constants::LIBS + Constants::ARM64_V8A)) {
223             appqfInfo.cpuAbi = Constants::ARM64_V8A;
224             auto iter = Constants::ABI_MAP.find(Constants::ARM64_V8A);
225             if (iter != Constants::ABI_MAP.end()) {
226                 appqfInfo.nativeLibraryPath = Constants::LIBS + iter->second;
227                 return true;
228             }
229             APP_LOGE("Can't find ARM64_V8A in ABI_MAP");
230             return false;
231         }
232         APP_LOGE(" ARM64_V8A's directory doesn't exist");
233         return false;
234     }
235 
236     if (patchExtractor.IsDirExist(Constants::LIBS + Constants::ARM_EABI_V7A)) {
237         appqfInfo.cpuAbi = Constants::ARM_EABI_V7A;
238         auto iter = Constants::ABI_MAP.find(Constants::ARM_EABI_V7A);
239         if (iter != Constants::ABI_MAP.end()) {
240             appqfInfo.nativeLibraryPath = Constants::LIBS + iter->second;
241             return true;
242         }
243         APP_LOGE("Can't find ARM_EABI_V7A in ABI_MAP");
244         return false;
245     }
246 
247     if (patchExtractor.IsDirExist(Constants::LIBS + Constants::ARM_EABI)) {
248         appqfInfo.cpuAbi = Constants::ARM_EABI;
249         auto iter = Constants::ABI_MAP.find(Constants::ARM_EABI);
250         if (iter != Constants::ABI_MAP.end()) {
251             appqfInfo.nativeLibraryPath = Constants::LIBS + iter->second;
252             return true;
253         }
254         APP_LOGE("Can't find ARM_EABI in ABI_MAP");
255         return false;
256     }
257     APP_LOGE("ARM_EABI_V7A and ARM_EABI directories do not exist");
258     return false;
259 }
260 
ParseNativeSo(const PatchExtractor & patchExtractor,AppqfInfo & appqfInfo)261 bool PatchProfile::ParseNativeSo(const PatchExtractor &patchExtractor, AppqfInfo &appqfInfo)
262 {
263     std::string abis = GetAbiList();
264     std::vector<std::string> abiList;
265     SplitStr(abis, Constants::ABI_SEPARATOR, abiList, false, false);
266     if (abiList.empty()) {
267         APP_LOGE("Abi is empty");
268         return false;
269     }
270     bool isDefault = std::find(abiList.begin(), abiList.end(), Constants::ABI_DEFAULT) != abiList.end();
271     bool isSystemLib64Exist = BundleUtil::IsExistDir(Constants::SYSTEM_LIB64);
272     APP_LOGD("abi list : %{public}s, isDefault : %{public}d, isSystemLib64Exist : %{public}d",
273         abis.c_str(), isDefault, isSystemLib64Exist);
274     bool soExist = patchExtractor.IsDirExist(Constants::LIBS);
275     if (!soExist) {
276         APP_LOGD("so not exist");
277         if (isDefault) {
278             appqfInfo.cpuAbi = isSystemLib64Exist ? Constants::ARM64_V8A : Constants::ARM_EABI_V7A;
279             return true;
280         }
281         for (const auto &abi : abiList) {
282             if (Constants::ABI_MAP.find(abi) != Constants::ABI_MAP.end()) {
283                 appqfInfo.cpuAbi = abi;
284                 return true;
285             }
286         }
287         APP_LOGE("None of the abiList are in the ABI_MAP");
288         return false;
289     }
290 
291     APP_LOGD("so exist");
292     if (isDefault) {
293         return DefaultNativeSo(patchExtractor, isSystemLib64Exist, appqfInfo);
294     }
295     for (const auto &abi : abiList) {
296         std::string libsPath;
297         libsPath.append(Constants::LIBS).append(abi).append(Constants::PATH_SEPARATOR);
298         if (Constants::ABI_MAP.find(abi) != Constants::ABI_MAP.end() && patchExtractor.IsDirExist(libsPath)) {
299             appqfInfo.cpuAbi = abi;
300             auto iter = Constants::ABI_MAP.find(abi);
301             if (iter != Constants::ABI_MAP.end()) {
302                 appqfInfo.nativeLibraryPath = Constants::LIBS + iter->second;
303                 return true;
304             }
305             APP_LOGE("Can't find %{public}s in ABI_MAP", abi.c_str());
306             return false;
307         }
308     }
309     return false;
310 }
311 
TransformTo(const std::ostringstream & source,const PatchExtractor & patchExtractor,AppQuickFix & appQuickFix)312 ErrCode PatchProfile::TransformTo(
313     const std::ostringstream &source, const PatchExtractor &patchExtractor, AppQuickFix &appQuickFix)
314 {
315     nlohmann::json jsonObject = nlohmann::json::parse(source.str(), nullptr, false);
316     if (jsonObject.is_discarded()) {
317         APP_LOGE("bad profile");
318         return ERR_APPEXECFWK_PARSE_BAD_PROFILE;
319     }
320     PatchProfileReader::PatchJson patchJson;
321     {
322         std::lock_guard<std::mutex> lock(PatchProfileReader::g_mutex);
323         PatchProfileReader::g_parseResult = ERR_OK;
324         patchJson = jsonObject.get<PatchProfileReader::PatchJson>();
325         if (PatchProfileReader::g_parseResult != ERR_OK) {
326             APP_LOGE("g_parseResult is %{public}d", PatchProfileReader::g_parseResult);
327             int32_t ret = PatchProfileReader::g_parseResult;
328             PatchProfileReader::g_parseResult = ERR_OK;
329             return ret;
330         }
331     }
332     if (!PatchProfileReader::ToPatchInfo(patchJson, appQuickFix)) {
333         APP_LOGE("bundle or module name is invalid");
334         return ERR_APPEXECFWK_PARSE_PROFILE_PROP_CHECK_ERROR;
335     }
336     // hot reload does not process so files
337     if ((appQuickFix.deployingAppqfInfo.type == QuickFixType::PATCH) &&
338         (!ParseNativeSo(patchExtractor, appQuickFix.deployingAppqfInfo))) {
339         APP_LOGE("ParseNativeSo failed");
340         return ERR_APPEXECFWK_PARSE_NATIVE_SO_FAILED;
341     }
342     return ERR_OK;
343 }
344 }  // namespace AppExecFwk
345 }  // namespace OHOS