1 /*
2 * Copyright (c) 2025 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 "ets_context_utils.h"
17
18 #include "ani_common_util.h"
19 #include "ani_enum_convert.h"
20 #include "application_context.h"
21 #include "application_context_manager.h"
22 #include "common_fun_ani.h"
23 #include "ets_application_context_utils.h"
24 #include "ets_error_utils.h"
25 #include "ets_native_reference.h"
26 #include "hilog_tag_wrapper.h"
27 #include "ipc_skeleton.h"
28 #include "resourceManager.h"
29 #include "tokenid_kit.h"
30
31 namespace OHOS {
32 namespace AbilityRuntime {
33 namespace ContextUtil {
34 namespace {
35 static std::once_flag g_bindNativeMethodsFlag;
36 constexpr const char* CONTEXT_CLASS_NAME = "Lapplication/Context/Context;";
37 constexpr const char* AREA_MODE_ENUM_NAME = "L@ohos/app/ability/contextConstant/contextConstant/AreaMode;";
38 constexpr const char* CLEANER_CLASS = "Lapplication/Context/Cleaner;";
39
BindContextDir(ani_env * aniEnv,ani_object contextObj,std::shared_ptr<Context> context)40 void BindContextDir(ani_env *aniEnv, ani_object contextObj, std::shared_ptr<Context> context)
41 {
42 if (aniEnv == nullptr || context == nullptr) {
43 TAG_LOGE(AAFwkTag::APPKIT, "aniEnv or context is nullptr");
44 return;
45 }
46 ani_status status = ANI_ERROR;
47 auto preferencesDir = context->GetPreferencesDir();
48 ani_string preferencesDirString = nullptr;
49 aniEnv->String_NewUTF8(preferencesDir.c_str(), preferencesDir.size(), &preferencesDirString);
50 if ((status = aniEnv->Object_SetFieldByName_Ref(contextObj, "preferencesDir", preferencesDirString)) != ANI_OK) {
51 TAG_LOGE(AAFwkTag::APPKIT, "preferencesDir SetField status: %{public}d", status);
52 return;
53 }
54
55 auto databaseDir = context->GetDatabaseDir();
56 ani_string databaseDirString = nullptr;
57 aniEnv->String_NewUTF8(databaseDir.c_str(), databaseDir.size(), &databaseDirString);
58 if ((status = aniEnv->Object_SetFieldByName_Ref(contextObj, "databaseDir", databaseDirString)) != ANI_OK) {
59 TAG_LOGE(AAFwkTag::APPKIT, "databaseDir SetField status: %{public}d", status);
60 return;
61 }
62
63 auto cacheDir = context->GetCacheDir();
64 ani_string cacheDirString = nullptr;
65 aniEnv->String_NewUTF8(cacheDir.c_str(), cacheDir.size(), &cacheDirString);
66 if ((status = aniEnv->Object_SetFieldByName_Ref(contextObj, "cacheDir", cacheDirString)) != ANI_OK) {
67 TAG_LOGE(AAFwkTag::APPKIT, "cacheDir SetField status: %{public}d", status);
68 return;
69 }
70
71 auto filesDir = context->GetFilesDir();
72 ani_string filesDirString = nullptr;
73 aniEnv->String_NewUTF8(filesDir.c_str(), filesDir.size(), &filesDirString);
74 if ((status = aniEnv->Object_SetFieldByName_Ref(contextObj, "filesDir", filesDirString)) != ANI_OK) {
75 TAG_LOGE(AAFwkTag::APPKIT, "filesDir SetField status: %{public}d", status);
76 return;
77 }
78
79 auto tempDir = context->GetTempDir();
80 ani_string tempDirString = nullptr;
81 aniEnv->String_NewUTF8(tempDir.c_str(), tempDir.size(), &tempDirString);
82 if ((status = aniEnv->Object_SetFieldByName_Ref(contextObj, "tempDir", tempDirString)) != ANI_OK) {
83 TAG_LOGE(AAFwkTag::APPKIT, "tempDir SetField status: %{public}d", status);
84 return;
85 }
86 }
87 } // namespace
88
Clean(ani_env * env,ani_object object)89 void Clean(ani_env *env, ani_object object)
90 {
91 TAG_LOGD(AAFwkTag::APPKIT, "Clean called");
92 if (env == nullptr) {
93 TAG_LOGE(AAFwkTag::APPKIT, "null env");
94 return;
95 }
96 ani_long ptr = 0;
97 ani_status status = env->Object_GetFieldByName_Long(object, "ptr", &ptr);
98 if (status != ANI_OK) {
99 TAG_LOGE(AAFwkTag::APPKIT, "ptr GetField status: %{public}d", status);
100 return;
101 }
102 if (ptr != 0) {
103 delete reinterpret_cast<Context *>(ptr);
104 }
105 }
106
SetNativeContextLong(ani_env * env,ani_object aniObj,ani_long nativeContextLong)107 bool SetNativeContextLong(ani_env *env, ani_object aniObj, ani_long nativeContextLong)
108 {
109 if (env == nullptr) {
110 TAG_LOGE(AAFwkTag::APPKIT, "null env");
111 return false;
112 }
113 auto status = env->Object_SetFieldByName_Long(aniObj, "nativeContext", nativeContextLong);
114 if (status != ANI_OK) {
115 TAG_LOGE(AAFwkTag::APPKIT, "nativeContextLong SetField status: %{public}d", status);
116 return false;
117 }
118 ani_class contextCls = nullptr;
119 if (env->FindClass(CONTEXT_CLASS_NAME, &contextCls) != ANI_OK) {
120 TAG_LOGE(AAFwkTag::APPKIT, "FindClass Context failed");
121 return false;
122 }
123 ani_method method = nullptr;
124 if ((status = env->Class_FindMethod(contextCls, "<ctor>", ":V", &method)) != ANI_OK ||
125 method == nullptr) {
126 TAG_LOGE(AAFwkTag::APPKIT, "ctor FindMethod status: %{public}d, or null method", status);
127 return false;
128 }
129 ani_object contextObj = nullptr;
130 if ((status = env->Object_New(contextCls, method, &contextObj)) != ANI_OK || contextObj == nullptr) {
131 TAG_LOGE(AAFwkTag::APPKIT, "Object_New status: %{public}d, or null contextObj", status);
132 return false;
133 }
134 if ((status = env->Class_FindMethod(contextCls, "setEtsContextPtr", "J:V", &method)) != ANI_OK ||
135 method == nullptr) {
136 TAG_LOGE(AAFwkTag::APPKIT, "setEtsContextPtr FindMethod status: %{public}d, or null method", status);
137 return false;
138 }
139 if ((status = env->Object_CallMethod_Void(contextObj, method, nativeContextLong)) != ANI_OK) {
140 TAG_LOGE(AAFwkTag::APPKIT, "call contextObj method failed, status: %{public}d", status);
141 return false;
142 }
143 return true;
144 }
145
BindApplicationInfo(ani_env * aniEnv,ani_class contextClass,ani_object contextObj,std::shared_ptr<Context> context)146 void BindApplicationInfo(ani_env *aniEnv, ani_class contextClass, ani_object contextObj,
147 std::shared_ptr<Context> context)
148 {
149 if (aniEnv == nullptr || context == nullptr) {
150 TAG_LOGE(AAFwkTag::APPKIT, "null aniEnv or null context");
151 }
152 ani_field applicationInfoField;
153 if (ANI_OK != aniEnv->Class_FindField(contextClass, "applicationInfo", &applicationInfoField)) {
154 TAG_LOGE(AAFwkTag::APPKIT, "find applicationInfo failed");
155 return;
156 }
157 auto appInfo = context->GetApplicationInfo();
158 ani_object appInfoObj = AppExecFwk::CommonFunAni::ConvertApplicationInfo(aniEnv, *appInfo);
159 if (aniEnv->Object_SetField_Ref(contextObj, applicationInfoField,
160 reinterpret_cast<ani_ref>(appInfoObj)) != ANI_OK) {
161 TAG_LOGE(AAFwkTag::APPKIT, "Object_SetField_Ref failed");
162 return;
163 }
164 }
165
BindResourceManager(ani_env * aniEnv,ani_class contextClass,ani_object contextObj,std::shared_ptr<Context> context)166 void BindResourceManager(ani_env *aniEnv, ani_class contextClass, ani_object contextObj,
167 std::shared_ptr<Context> context)
168 {
169 if (aniEnv == nullptr || context == nullptr) {
170 TAG_LOGE(AAFwkTag::APPKIT, "null aniEnv or null context");
171 }
172 ani_field resourceManagerField;
173 if (ANI_OK != aniEnv->Class_FindField(contextClass, "resourceManager", &resourceManagerField)) {
174 TAG_LOGE(AAFwkTag::APPKIT, "find resourceManager failed");
175 return;
176 }
177 auto resourceManager = context->GetResourceManager();
178 ani_object resourceMgrObj = Global::Resource::ResMgrAddon::CreateResMgr(aniEnv, "", resourceManager, context);
179 if (aniEnv->Object_SetField_Ref(contextObj, resourceManagerField,
180 reinterpret_cast<ani_ref>(resourceMgrObj)) != ANI_OK) {
181 TAG_LOGE(AAFwkTag::APPKIT, "Object_SetField_Ref failed");
182 return;
183 }
184 }
185
BindParentProperty(ani_env * aniEnv,ani_class contextClass,ani_object contextObj,std::shared_ptr<Context> context)186 void BindParentProperty(ani_env *aniEnv, ani_class contextClass, ani_object contextObj,
187 std::shared_ptr<Context> context)
188 {
189 if (aniEnv == nullptr || context == nullptr) {
190 TAG_LOGE(AAFwkTag::APPKIT, "null aniEnv or null context");
191 }
192 BindApplicationInfo(aniEnv, contextClass, contextObj, context);
193 BindResourceManager(aniEnv, contextClass, contextObj, context);
194 BindContextDir(aniEnv, contextObj, context);
195 }
196
BindNativeFunction(ani_env * aniEnv)197 void BindNativeFunction(ani_env *aniEnv)
198 {
199 if (aniEnv == nullptr) {
200 TAG_LOGE(AAFwkTag::APPKIT, "env is null");
201 return;
202 }
203 ani_class contextCls = nullptr;
204 if (aniEnv->FindClass(CONTEXT_CLASS_NAME, &contextCls) != ANI_OK) {
205 TAG_LOGE(AAFwkTag::APPKIT, "FindClass Context failed");
206 return;
207 }
208 ani_status status = ANI_ERROR;
209 std::call_once(g_bindNativeMethodsFlag, [&status, aniEnv, contextCls]() {
210 std::array contextFunctions = {
211 ani_native_function {"getApplicationContextSync", ":Lapplication/ApplicationContext/ApplicationContext;",
212 reinterpret_cast<void *>(AbilityRuntime::ContextUtil::GetApplicationContextSync)},
213 ani_native_function {"switchArea", nullptr,
214 reinterpret_cast<void *>(AbilityRuntime::ContextUtil::SwitchArea)},
215 ani_native_function {"getArea", nullptr,
216 reinterpret_cast<void *>(AbilityRuntime::ContextUtil::GetArea)},
217 ani_native_function {"createModuleResourceManagerSync", "Lstd/core/String;Lstd/core/String;"
218 ":L@ohos/resourceManager/resourceManager/ResourceManager;",
219 reinterpret_cast<void *>(AbilityRuntime::ContextUtil::CreateModuleResourceManagerSync)},
220 };
221 status = aniEnv->Class_BindNativeMethods(contextCls, contextFunctions.data(),
222 contextFunctions.size());
223 if (status != ANI_OK) {
224 TAG_LOGE(AAFwkTag::APPKIT, "Class_BindNativeMethods failed status: %{public}d", status);
225 return;
226 }
227 ani_class cleanerCls = nullptr;
228 if ((status = aniEnv->FindClass(CLEANER_CLASS, &cleanerCls)) != ANI_OK || cleanerCls == nullptr) {
229 TAG_LOGE(AAFwkTag::APPKIT, "Cleaner FindClass failed status: %{public}d, or null cleanerCls", status);
230 return;
231 }
232 std::array cleanerMethods = {
233 ani_native_function {"clean", nullptr, reinterpret_cast<void *>(Clean) },
234 };
235 if ((status = aniEnv->Class_BindNativeMethods(cleanerCls,
236 cleanerMethods.data(), cleanerMethods.size())) != ANI_OK) {
237 TAG_LOGE(AAFwkTag::APPKIT, "Class_BindNativeMethods failed status: %{public}d", status);
238 return;
239 }
240 });
241 }
242
SetHapModuleInfo(ani_env * env,ani_class cls,ani_object contextObj,const std::shared_ptr<OHOS::AbilityRuntime::Context> & context)243 bool SetHapModuleInfo(
244 ani_env *env, ani_class cls, ani_object contextObj, const std::shared_ptr<OHOS::AbilityRuntime::Context> &context)
245 {
246 if (env == nullptr || context == nullptr) {
247 TAG_LOGE(AAFwkTag::APPKIT, "null env or context");
248 return false;
249 }
250 auto hapModuleInfo = context->GetHapModuleInfo();
251 if (hapModuleInfo == nullptr) {
252 TAG_LOGE(AAFwkTag::APPKIT, "hapModuleInfo is nullptr");
253 return false;
254 }
255 ani_ref hapModuleInfoRef = AppExecFwk::CommonFunAni::ConvertHapModuleInfo(env, *hapModuleInfo);
256 if (hapModuleInfoRef == nullptr) {
257 TAG_LOGE(AAFwkTag::APPKIT, "hapModuleInfoRef is nullptr");
258 return false;
259 }
260 ani_status status = ANI_OK;
261 status = env->Object_SetPropertyByName_Ref(contextObj, "currentHapModuleInfo", hapModuleInfoRef);
262 if (status != ANI_OK) {
263 TAG_LOGE(AAFwkTag::APPKIT, "Object_SetPropertyByName_Ref failed, status: %{public}d", status);
264 return false;
265 }
266 return true;
267 }
268
CreateEtsBaseContext(ani_env * aniEnv,ani_class contextClass,ani_object contextObj,std::shared_ptr<Context> context)269 void CreateEtsBaseContext(ani_env *aniEnv, ani_class contextClass, ani_object contextObj,
270 std::shared_ptr<Context> context)
271 {
272 if (aniEnv == nullptr || context == nullptr) {
273 TAG_LOGE(AAFwkTag::APPKIT, "null aniEnv or null context");
274 return;
275 }
276 if (!SetHapModuleInfo(aniEnv, contextClass, contextObj, context)) {
277 TAG_LOGE(AAFwkTag::APPKIT, "SetHapModuleInfo fail");
278 }
279 BindParentProperty(aniEnv, contextClass, contextObj, context);
280 BindNativeFunction(aniEnv);
281 }
282
GetBaseContext(ani_env * env,ani_object aniObj)283 std::shared_ptr<Context> GetBaseContext(ani_env *env, ani_object aniObj)
284 {
285 ani_status status = ANI_ERROR;
286 if (env == nullptr) {
287 TAG_LOGE(AAFwkTag::APPKIT, "null env");
288 return nullptr;
289 }
290 ani_class cls = nullptr;
291 if ((status = env->FindClass(CONTEXT_CLASS_NAME, &cls)) != ANI_OK) {
292 TAG_LOGE(AAFwkTag::APPKIT, "status: %{public}d", status);
293 return nullptr;
294 }
295 ani_field contextField = nullptr;
296 if ((status = env->Class_FindField(cls, "nativeContext", &contextField)) != ANI_OK) {
297 TAG_LOGE(AAFwkTag::APPKIT, "status: %{public}d", status);
298 return nullptr;
299 }
300 ani_long nativeContextLong;
301 if ((status = env->Object_GetField_Long(aniObj, contextField, &nativeContextLong)) != ANI_OK) {
302 TAG_LOGE(AAFwkTag::APPKIT, "status: %{public}d", status);
303 return nullptr;
304 }
305 auto weakContext = reinterpret_cast<std::weak_ptr<Context>*>(nativeContextLong);
306 return weakContext != nullptr ? weakContext->lock() : nullptr;
307 }
308
CheckCallerIsSystemApp()309 bool CheckCallerIsSystemApp()
310 {
311 auto selfToken = IPCSkeleton::GetSelfTokenID();
312 return Security::AccessToken::TokenIdKit::IsSystemAppByFullTokenID(selfToken);
313 }
314
CreateModuleResourceManagerSync(ani_env * env,ani_object aniObj,ani_string bundleName,ani_string moduleName)315 ani_object CreateModuleResourceManagerSync(ani_env *env, ani_object aniObj,
316 ani_string bundleName, ani_string moduleName)
317 {
318 if (env == nullptr) {
319 TAG_LOGE(AAFwkTag::APPKIT, "null env");
320 return nullptr;
321 }
322 std::string stdBundleName = "";
323 AppExecFwk::GetStdString(env, bundleName, stdBundleName);
324 std::string stdModuleName = "";
325 AppExecFwk::GetStdString(env, moduleName, stdModuleName);
326 auto context = GetBaseContext(env, aniObj);
327 if (!context) {
328 TAG_LOGE(AAFwkTag::APPKIT, "null context");
329 EtsErrorUtil::ThrowError(env, AbilityErrorCode::ERROR_CODE_INVALID_PARAM);
330 return nullptr;
331 }
332 if (!CheckCallerIsSystemApp()) {
333 TAG_LOGE(AAFwkTag::APPKIT, "not system-app");
334 EtsErrorUtil::ThrowError(env, AbilityErrorCode::ERROR_CODE_NOT_SYSTEM_APP);
335 return nullptr;
336 }
337 auto resourceManager = context->CreateModuleResourceManager(stdBundleName, stdModuleName);
338 if (resourceManager == nullptr) {
339 TAG_LOGE(AAFwkTag::APPKIT, "null resourceManager");
340 EtsErrorUtil::ThrowError(env, AbilityErrorCode::ERROR_CODE_INVALID_PARAM);
341 return nullptr;
342 }
343 return Global::Resource::ResMgrAddon::CreateResMgr(env, "", resourceManager, context);
344 }
345
GetApplicationContext(ani_env * env,const std::shared_ptr<ApplicationContext> applicationContext)346 ani_object GetApplicationContext(ani_env *env, const std::shared_ptr<ApplicationContext> applicationContext)
347 {
348 if (env == nullptr) {
349 TAG_LOGE(AAFwkTag::APPKIT, "null env");
350 return {};
351 }
352 ani_object applicationContextObject =
353 EtsApplicationContextUtils::CreateEtsApplicationContext(env, applicationContext);
354 if (applicationContextObject == nullptr) {
355 TAG_LOGE(AAFwkTag::APPKIT, "null applicationContextObject");
356 return {};
357 }
358 applicationContext->SetApplicationInfoUpdateFlag(false);
359 return applicationContextObject;
360 }
361
GetApplicationContextSync(ani_env * env,ani_object aniObj)362 ani_object GetApplicationContextSync(ani_env *env, ani_object aniObj)
363 {
364 if (env == nullptr) {
365 TAG_LOGE(AAFwkTag::APPKIT, "null env");
366 }
367 auto context = GetBaseContext(env, aniObj);
368 if (!context) {
369 TAG_LOGW(AAFwkTag::APPKIT, "null context");
370 EtsErrorUtil::ThrowError(env, (int32_t)AbilityErrorCode::ERROR_CODE_INVALID_PARAM);
371 return {};
372 }
373 auto applicationContext = context->GetApplicationContext();
374 if (applicationContext == nullptr) {
375 TAG_LOGE(AAFwkTag::APPKIT, "null applicationContext");
376 EtsErrorUtil::ThrowError(env, (int32_t)AbilityErrorCode::ERROR_CODE_INVALID_PARAM);
377 return {};
378 }
379 if (!applicationContext->GetApplicationInfoUpdateFlag()) {
380 auto appContextObj = ApplicationContextManager::GetApplicationContextManager().GetEtsGlobalObject();
381 if (appContextObj != nullptr && appContextObj->aniRef != nullptr) {
382 TAG_LOGD(AAFwkTag::APPKIT, "appContextObj is not nullptr");
383 return reinterpret_cast<ani_object>(appContextObj->aniRef);
384 }
385 }
386 return GetApplicationContext(env, applicationContext);
387 }
388
SwitchArea(ani_env * env,ani_object obj,ani_enum_item areaModeItem)389 void SwitchArea(ani_env *env, ani_object obj, ani_enum_item areaModeItem)
390 {
391 if (env == nullptr) {
392 TAG_LOGE(AAFwkTag::APPKIT, "null env");
393 }
394 int32_t areaMode = 0;
395 if (!AAFwk::AniEnumConvertUtil::EnumConvert_EtsToNative(env, areaModeItem, areaMode)) {
396 TAG_LOGE(AAFwkTag::APPKIT, "Parse area failed");
397 return;
398 }
399 auto context = GetBaseContext(env, obj);
400 if (context == nullptr) {
401 TAG_LOGE(AAFwkTag::APPKIT, "null context");
402 return;
403 }
404 context->SwitchArea(areaMode);
405 BindContextDir(env, obj, context);
406 }
407
GetArea(ani_env * env,ani_object obj)408 ani_enum_item GetArea(ani_env *env, ani_object obj)
409 {
410 ani_enum_item areaModeItem = nullptr;
411 auto context = GetBaseContext(env, obj);
412 if (env == nullptr || context == nullptr) {
413 TAG_LOGE(AAFwkTag::APPKIT, "env or context is null");
414 return areaModeItem;
415 }
416 int32_t areaMode = static_cast<int32_t>(context->GetArea());
417 OHOS::AAFwk::AniEnumConvertUtil::EnumConvert_NativeToEts(env, AREA_MODE_ENUM_NAME, areaMode, areaModeItem);
418 return areaModeItem;
419 }
420 }
421 } // namespace AbilityRuntime
422 } // namespace OHOS