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