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_wrapper.h"
21 #include "bundle_constants.h"
22 #include "bundle_util.h"
23 #include "json_util.h"
24 #include "parameter.h"
25 #include "string_ex.h"
26
27 namespace OHOS {
28 namespace AppExecFwk {
29 namespace PatchProfileReader {
30 constexpr const char* BUNDLE_PATCH_PROFILE_APP_KEY_BUNDLE_NAME = "bundleName";
31 constexpr const char* BUNDLE_PATCH_PROFILE_APP_KEY_VERSION_CODE = "versionCode";
32 constexpr const char* BUNDLE_PATCH_PROFILE_APP_KEY_VERSION_NAME = "versionName";
33 constexpr const char* BUNDLE_PATCH_PROFILE_APP_KEY_PATCH_VERSION_CODE = "patchVersionCode";
34 constexpr const char* BUNDLE_PATCH_PROFILE_APP_KEY_PATCH_VERSION_NAME = "patchVersionName";
35 constexpr const char* BUNDLE_PATCH_PROFILE_MODULE_KEY_NAME = "name";
36 constexpr const char* BUNDLE_PATCH_PROFILE_MODULE_KEY_TYPE = "type";
37 constexpr const char* BUNDLE_PATCH_PROFILE_MODULE_KEY_DEVICE_TYPES = "deviceTypes";
38 constexpr const char* BUNDLE_PATCH_PROFILE_MODULE_KEY_ORIGINAL_MODULE_HASH = "originalModuleHash";
39 constexpr const char* BUNDLE_PATCH_PROFILE_KEY_APP = "app";
40 constexpr const char* BUNDLE_PATCH_PROFILE_KEY_MODULE = "module";
41 constexpr const char* BUNDLE_PATCH_TYPE_PATCH = "patch";
42 constexpr const char* BUNDLE_PATCH_TYPE_HOT_RELOAD = "hotreload";
43
44 thread_local int32_t parseResult = 0;
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 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 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 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 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 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 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 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 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 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 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 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 APP_LOGW("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 return false;
184 }
185 if (name.find(Constants::RELATIVE_PATH) != std::string::npos) {
186 return false;
187 }
188 return true;
189 }
190
ToPatchInfo(const PatchJson & patchJson,AppQuickFix & appQuickFix)191 bool ToPatchInfo(const PatchJson &patchJson, AppQuickFix &appQuickFix)
192 {
193 if (!CheckNameIsValid(patchJson.app.bundleName)) {
194 APP_LOGE("bundle name is invalid");
195 return false;
196 }
197 if (!CheckNameIsValid(patchJson.module.name)) {
198 APP_LOGE("module name is invalid");
199 return false;
200 }
201 appQuickFix.bundleName = patchJson.app.bundleName;
202 appQuickFix.versionCode = patchJson.app.versionCode;
203 appQuickFix.versionName = patchJson.app.versionName;
204 appQuickFix.deployingAppqfInfo.versionCode = patchJson.app.patchVersionCode;
205 appQuickFix.deployingAppqfInfo.versionName = patchJson.app.patchVersionName;
206 appQuickFix.deployingAppqfInfo.type = GetQuickFixType(patchJson.module.type);
207 HqfInfo hqfInfo;
208 hqfInfo.moduleName = patchJson.module.name;
209 hqfInfo.hapSha256 = patchJson.module.originalModuleHash;
210 hqfInfo.type = GetQuickFixType(patchJson.module.type);
211 appQuickFix.deployingAppqfInfo.hqfInfos.emplace_back(hqfInfo);
212 return true;
213 }
214 }
215
DefaultNativeSo(const PatchExtractor & patchExtractor,bool isSystemLib64Exist,AppqfInfo & appqfInfo)216 bool PatchProfile::DefaultNativeSo(
217 const PatchExtractor &patchExtractor, bool isSystemLib64Exist, AppqfInfo &appqfInfo)
218 {
219 if (isSystemLib64Exist) {
220 if (patchExtractor.IsDirExist(Constants::LIBS + Constants::ARM64_V8A)) {
221 appqfInfo.cpuAbi = Constants::ARM64_V8A;
222 auto iter = Constants::ABI_MAP.find(Constants::ARM64_V8A);
223 if (iter != Constants::ABI_MAP.end()) {
224 appqfInfo.nativeLibraryPath = Constants::LIBS + iter->second;
225 return true;
226 }
227 APP_LOGE("Can't find ARM64_V8A in ABI_MAP");
228 return false;
229 }
230 APP_LOGE(" ARM64_V8A's directory doesn't exist");
231 return false;
232 }
233
234 if (patchExtractor.IsDirExist(Constants::LIBS + Constants::ARM_EABI_V7A)) {
235 appqfInfo.cpuAbi = Constants::ARM_EABI_V7A;
236 auto iter = Constants::ABI_MAP.find(Constants::ARM_EABI_V7A);
237 if (iter != Constants::ABI_MAP.end()) {
238 appqfInfo.nativeLibraryPath = Constants::LIBS + iter->second;
239 return true;
240 }
241 APP_LOGE("Can't find ARM_EABI_V7A in ABI_MAP");
242 return false;
243 }
244
245 if (patchExtractor.IsDirExist(Constants::LIBS + Constants::ARM_EABI)) {
246 appqfInfo.cpuAbi = Constants::ARM_EABI;
247 auto iter = Constants::ABI_MAP.find(Constants::ARM_EABI);
248 if (iter != Constants::ABI_MAP.end()) {
249 appqfInfo.nativeLibraryPath = Constants::LIBS + iter->second;
250 return true;
251 }
252 APP_LOGE("Can't find ARM_EABI in ABI_MAP");
253 return false;
254 }
255 APP_LOGE("ARM_EABI_V7A and ARM_EABI directories do not exist");
256 return false;
257 }
258
ParseNativeSo(const PatchExtractor & patchExtractor,AppqfInfo & appqfInfo)259 bool PatchProfile::ParseNativeSo(const PatchExtractor &patchExtractor, AppqfInfo &appqfInfo)
260 {
261 std::string abis = GetAbiList();
262 std::vector<std::string> abiList;
263 SplitStr(abis, Constants::ABI_SEPARATOR, abiList, false, false);
264 if (abiList.empty()) {
265 APP_LOGE("Abi is empty");
266 return false;
267 }
268 bool isDefault = std::find(abiList.begin(), abiList.end(), Constants::ABI_DEFAULT) != abiList.end();
269 bool isSystemLib64Exist = BundleUtil::IsExistDir(Constants::SYSTEM_LIB64);
270 APP_LOGD("abi list : %{public}s, isDefault : %{public}d, isSystemLib64Exist : %{public}d",
271 abis.c_str(), isDefault, isSystemLib64Exist);
272 bool soExist = patchExtractor.IsDirExist(Constants::LIBS);
273 if (!soExist) {
274 APP_LOGD("so not exist");
275 if (isDefault) {
276 appqfInfo.cpuAbi = isSystemLib64Exist ? Constants::ARM64_V8A : Constants::ARM_EABI_V7A;
277 return true;
278 }
279 for (const auto &abi : abiList) {
280 if (Constants::ABI_MAP.find(abi) != Constants::ABI_MAP.end()) {
281 appqfInfo.cpuAbi = abi;
282 return true;
283 }
284 }
285 APP_LOGE("None of the abiList are in the ABI_MAP");
286 return false;
287 }
288
289 APP_LOGD("so exist");
290 if (isDefault) {
291 return DefaultNativeSo(patchExtractor, isSystemLib64Exist, appqfInfo);
292 }
293 for (const auto &abi : abiList) {
294 std::string libsPath;
295 libsPath.append(Constants::LIBS).append(abi).append(Constants::PATH_SEPARATOR);
296 if (Constants::ABI_MAP.find(abi) != Constants::ABI_MAP.end() && patchExtractor.IsDirExist(libsPath)) {
297 appqfInfo.cpuAbi = abi;
298 auto iter = Constants::ABI_MAP.find(abi);
299 if (iter != Constants::ABI_MAP.end()) {
300 appqfInfo.nativeLibraryPath = Constants::LIBS + iter->second;
301 return true;
302 }
303 APP_LOGE("Can't find %{public}s in ABI_MAP", abi.c_str());
304 return false;
305 }
306 }
307 return false;
308 }
309
TransformTo(const std::ostringstream & source,const PatchExtractor & patchExtractor,AppQuickFix & appQuickFix)310 ErrCode PatchProfile::TransformTo(
311 const std::ostringstream &source, const PatchExtractor &patchExtractor, AppQuickFix &appQuickFix)
312 {
313 nlohmann::json jsonObject = nlohmann::json::parse(source.str(), nullptr, false);
314 if (jsonObject.is_discarded()) {
315 APP_LOGE("bad profile");
316 return ERR_APPEXECFWK_PARSE_BAD_PROFILE;
317 }
318 PatchProfileReader::PatchJson patchJson = jsonObject.get<PatchProfileReader::PatchJson>();
319 if (PatchProfileReader::parseResult != ERR_OK) {
320 APP_LOGE("parseResult is %{public}d", PatchProfileReader::parseResult);
321 int32_t ret = PatchProfileReader::parseResult;
322 PatchProfileReader::parseResult = ERR_OK;
323 return ret;
324 }
325 if (!PatchProfileReader::ToPatchInfo(patchJson, appQuickFix)) {
326 APP_LOGE("bundle or module name is invalid");
327 return ERR_APPEXECFWK_PARSE_PROFILE_PROP_CHECK_ERROR;
328 }
329 // hot reload does not process so files
330 if ((appQuickFix.deployingAppqfInfo.type == QuickFixType::PATCH) &&
331 (!ParseNativeSo(patchExtractor, appQuickFix.deployingAppqfInfo))) {
332 APP_LOGE("ParseNativeSo failed");
333 return ERR_APPEXECFWK_PARSE_NATIVE_SO_FAILED;
334 }
335 return ERR_OK;
336 }
337 } // namespace AppExecFwk
338 } // namespace OHOS