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