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