• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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