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