mirror of
https://github.com/openharmony/applications_settings.git
synced 2026-08-27 03:12:19 -04:00
92b10f9465
Issue: https://gitcode.com/openharmony/arkcompiler_runtime_core/issues/11866 Co-Authored-By: Agent Signed-off-by: Ivan Tyulyandin <ivan.tyulyandin@huawei.com>
333 lines
11 KiB
C++
333 lines
11 KiB
C++
/*
|
|
* Copyright (c) 2025-2026 Huawei Device Co., Ltd.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <map>
|
|
#include "ani_settings_observer.h"
|
|
#include "napi_settings_log.h"
|
|
#include "abs_shared_result_set.h"
|
|
#include "values_bucket.h"
|
|
#include "ani_base_context.h"
|
|
#include "os_account_manager.h"
|
|
|
|
using namespace OHOS::AppExecFwk;
|
|
using namespace OHOS::DataShare;
|
|
using namespace OHOS::AccountSA;
|
|
|
|
namespace OHOS {
|
|
namespace Settings {
|
|
std::map<std::string, sptr<SettingsObserver>> g_observerMap;
|
|
std::mutex g_observerMapMutex;
|
|
|
|
SettingsObserver::~SettingsObserver()
|
|
{
|
|
if (this->cbInfo == nullptr) {
|
|
return;
|
|
}
|
|
delete this->cbInfo;
|
|
this->cbInfo = nullptr;
|
|
}
|
|
|
|
bool IsExistObserver(SettingsObserver *settingsObserver)
|
|
{
|
|
for (auto it = g_observerMap.begin(); it != g_observerMap.end(); ++it) {
|
|
if (&(*(it->second)) == settingsObserver) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
ani_object BoolToObject(ani_env *env, bool value)
|
|
{
|
|
ani_object aniObject = nullptr;
|
|
ani_boolean boolValue = static_cast<bool>(value);
|
|
const char *className = "std.core.Boolean";
|
|
ani_class aniClass;
|
|
if (ANI_OK != env->FindClass(className, &aniClass)) {
|
|
SETTING_LOG_ERROR("Not found '%{public}s.'", className);
|
|
return aniObject;
|
|
}
|
|
|
|
ani_method personInfoCtor;
|
|
if (ANI_OK != env->Class_FindMethod(aniClass, "<ctor>", "z:", &personInfoCtor)) {
|
|
SETTING_LOG_ERROR("Class_GetMethod Failed '%{public}s' <ctor>.", className);
|
|
return aniObject;
|
|
}
|
|
|
|
if (ANI_OK != env->Object_New(aniClass, personInfoCtor, &aniObject, boolValue)) {
|
|
SETTING_LOG_ERROR("Object_New Failed '%{public}s' <ctor>.", className);
|
|
}
|
|
|
|
return aniObject;
|
|
}
|
|
|
|
ani_object CreateError(ani_env *env, const std::string &msg)
|
|
{
|
|
ani_class cls{};
|
|
ani_method method{};
|
|
ani_object obj = nullptr;
|
|
ani_status status = ANI_ERROR;
|
|
if (env == nullptr) {
|
|
SETTING_LOG_ERROR("null env");
|
|
return nullptr;
|
|
}
|
|
|
|
ani_string aniMsg = nullptr;
|
|
if ((status = env->String_NewUTF8(msg.c_str(), msg.size(), &aniMsg)) != ANI_OK) {
|
|
SETTING_LOG_ERROR("String_NewUTF8 failed %{public}d", status);
|
|
return nullptr;
|
|
}
|
|
|
|
ani_ref undefRef;
|
|
if ((status = env->GetUndefined(&undefRef)) != ANI_OK) {
|
|
SETTING_LOG_ERROR("GetUndefined failed %{public}d", status);
|
|
return nullptr;
|
|
}
|
|
|
|
if ((status = env->FindClass("escompat.Error", &cls)) != ANI_OK) {
|
|
SETTING_LOG_ERROR("FindClass failed %{public}d", status);
|
|
return nullptr;
|
|
}
|
|
if ((status = env->Class_FindMethod(cls, "<ctor>", "C{std.core.String}C{escompat.ErrorOptions}:", &method)) !=
|
|
ANI_OK) {
|
|
SETTING_LOG_ERROR("Class_FindMethod failed %{public}d", status);
|
|
return nullptr;
|
|
}
|
|
|
|
if ((status = env->Object_New(cls, method, &obj, aniMsg, undefRef)) != ANI_OK) {
|
|
SETTING_LOG_ERROR("Object_New failed %{public}d", status);
|
|
return nullptr;
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
ani_object CreateBusinessError(ani_env *env, int code, const std::string &msg)
|
|
{
|
|
ani_class cls{};
|
|
ani_method method{};
|
|
ani_object obj = nullptr;
|
|
ani_status status = ANI_ERROR;
|
|
if (env == nullptr) {
|
|
SETTING_LOG_ERROR("null env");
|
|
return nullptr;
|
|
}
|
|
if ((status = env->FindClass("@ohos.base.BusinessError", &cls)) != ANI_OK) {
|
|
SETTING_LOG_ERROR("FindClass failed %{public}d", status);
|
|
return nullptr;
|
|
}
|
|
if ((status = env->Class_FindMethod(cls, "<ctor>", "iC{escompat.Error}:", &method)) != ANI_OK) {
|
|
SETTING_LOG_ERROR("Class_FindMethod failed %{public}d", status);
|
|
return nullptr;
|
|
}
|
|
ani_object error = CreateError(env, msg);
|
|
if (error == nullptr) {
|
|
SETTING_LOG_ERROR("error null");
|
|
return nullptr;
|
|
}
|
|
ani_double dCode(code);
|
|
if ((status = env->Object_New(cls, method, &obj, dCode, error)) != ANI_OK) {
|
|
SETTING_LOG_ERROR("Object_New failed %{public}d", status);
|
|
return nullptr;
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
void SettingsObserver::OnChange()
|
|
{
|
|
SETTING_LOG_INFO("n_s_o_c");
|
|
std::lock_guard<std::mutex> lockGuard(g_observerMapMutex);
|
|
if (this->cbInfo == nullptr) {
|
|
SETTING_LOG_ERROR("%{public}s, cbInfo is null.", __func__);
|
|
return;
|
|
}
|
|
|
|
SETTING_LOG_INFO("n_s_o_c_a");
|
|
SettingsObserver *settingsObserver = reinterpret_cast<SettingsObserver *>(this);
|
|
if (!IsExistObserver(settingsObserver) || settingsObserver == nullptr || settingsObserver->cbInfo == nullptr ||
|
|
settingsObserver->toBeDelete) {
|
|
SETTING_LOG_ERROR("ani_call_function: cbInfo invalid.");
|
|
return;
|
|
}
|
|
|
|
ani_env *env = nullptr;
|
|
ani_options aniArgs{0, nullptr};
|
|
if (settingsObserver->vm_ == nullptr) {
|
|
SETTING_LOG_ERROR("VM is nullptr");
|
|
return;
|
|
}
|
|
if (ANI_OK != settingsObserver->vm_->AttachCurrentThread(&aniArgs, ANI_VERSION_1, &env)) {
|
|
SETTING_LOG_ERROR("AttachCurrentThread failed");
|
|
if (ANI_OK != settingsObserver->vm_->GetEnv(ANI_VERSION_1, &env)) {
|
|
SETTING_LOG_ERROR("GetEnv failed");
|
|
return;
|
|
}
|
|
}
|
|
|
|
ani_size nr_refs = 16;
|
|
env->CreateLocalScope(nr_refs);
|
|
|
|
ani_ref result;
|
|
auto fnObj = static_cast<ani_fn_object>(settingsObserver->callback_);
|
|
if (fnObj == nullptr) {
|
|
SETTING_LOG_ERROR("%{public}s: fnObj == nullptr", __func__);
|
|
return;
|
|
}
|
|
|
|
std::vector<ani_ref> args;
|
|
std::string msg = "";
|
|
ani_object errObj = CreateBusinessError(env, 802, msg);
|
|
|
|
ani_ref dataObj = BoolToObject(env, false);
|
|
args.push_back(errObj);
|
|
args.push_back(dataObj);
|
|
|
|
ani_status callStatus = env->FunctionalObject_Call(fnObj, args.size(), args.data(), &result);
|
|
if (ANI_OK != callStatus) {
|
|
SETTING_LOG_ERROR("ani_call_function failed status : %{public}d", callStatus);
|
|
return;
|
|
}
|
|
|
|
SETTING_LOG_INFO("%{public}s, ani_eventhandler_work success.", __func__);
|
|
env->DestroyLocalScope();
|
|
settingsObserver->vm_->DetachCurrentThread();
|
|
}
|
|
|
|
int GetObserverIdStr()
|
|
{
|
|
int currentUserId = -1;
|
|
OHOS::AccountSA::OsAccountManager::GetOsAccountLocalIdFromProcess(currentUserId);
|
|
int tmpId = 100;
|
|
if (currentUserId > 0) {
|
|
tmpId = currentUserId;
|
|
SETTING_LOG_INFO("userId is %{public}d", tmpId);
|
|
} else if (currentUserId == 0) {
|
|
OHOS::AccountSA::OsAccountManager::GetForegroundOsAccountLocalId(currentUserId);
|
|
tmpId = currentUserId;
|
|
SETTING_LOG_INFO("user0 userId is %{public}d", tmpId);
|
|
} else {
|
|
SETTING_LOG_INFO("%{public}s, user id 100.", __func__);
|
|
}
|
|
return tmpId;
|
|
}
|
|
|
|
void DeleteAsyncCallbackInfo(AsyncCallbackInfo *asyncCallbackInfo)
|
|
{
|
|
if (asyncCallbackInfo != nullptr) {
|
|
delete asyncCallbackInfo;
|
|
asyncCallbackInfo = nullptr;
|
|
}
|
|
}
|
|
|
|
ani_boolean ani_settings_register_observer(
|
|
ani_env *env, ani_object context, ani_string name, ani_string domainName, ani_object observer)
|
|
{
|
|
SETTING_LOG_INFO("n_s_r_o");
|
|
|
|
ani_boolean stageMode = false;
|
|
ani_status status = OHOS::AbilityRuntime::IsStageContext(env, context, stageMode);
|
|
if (status != ANI_OK) {
|
|
SETTING_LOG_ERROR("%{public}s, not stage mode.", __func__);
|
|
return false;
|
|
}
|
|
AsyncCallbackInfo *callbackInfo = new AsyncCallbackInfo();
|
|
if (callbackInfo == nullptr) {
|
|
SETTING_LOG_ERROR("%{public}s, failed to get callbackInfo.", __func__);
|
|
return false;
|
|
}
|
|
|
|
callbackInfo->env = env;
|
|
ani_vm *vm = nullptr;
|
|
if (env->GetVM(&vm) != ANI_OK) {
|
|
SETTING_LOG_ERROR("GetVM failed");
|
|
DeleteAsyncCallbackInfo(callbackInfo);
|
|
return false;
|
|
}
|
|
callbackInfo->key = unwrap_string_from_js(env, name);
|
|
callbackInfo->tableName = unwrap_string_from_js(env, domainName);
|
|
env->GlobalReference_Create(observer, &(callbackInfo->callbackRef));
|
|
|
|
std::lock_guard<std::mutex> lockGuard(g_observerMapMutex);
|
|
if (g_observerMap.find(callbackInfo->key) != g_observerMap.end() && g_observerMap[callbackInfo->key] != nullptr) {
|
|
SETTING_LOG_INFO("%{public}s, already registered.", __func__);
|
|
env->GlobalReference_Delete(callbackInfo->callbackRef);
|
|
DeleteAsyncCallbackInfo(callbackInfo);
|
|
return false;
|
|
}
|
|
|
|
auto dataShareHelper = getDataShareHelper(env, context, callbackInfo->tableName);
|
|
if (dataShareHelper == nullptr) {
|
|
env->GlobalReference_Delete(callbackInfo->callbackRef);
|
|
DeleteAsyncCallbackInfo(callbackInfo);
|
|
return false;
|
|
}
|
|
|
|
std::string strUri = GetStageUriStr(callbackInfo->tableName, GetObserverIdStr(), callbackInfo->key);
|
|
OHOS::Uri uri(strUri);
|
|
sptr<SettingsObserver> settingsObserver =
|
|
sptr<SettingsObserver>(new (std::nothrow) SettingsObserver(vm, observer, callbackInfo));
|
|
if (settingsObserver != nullptr && settingsObserver->callback_ != nullptr) {
|
|
env->GlobalReference_Create(observer, &(settingsObserver->callback_));
|
|
}
|
|
|
|
g_observerMap[callbackInfo->key] = settingsObserver;
|
|
dataShareHelper->RegisterObserver(uri, settingsObserver);
|
|
dataShareHelper->Release();
|
|
return true;
|
|
}
|
|
|
|
ani_boolean ani_settings_unregister_observer(ani_env *env, ani_object context, ani_string name, ani_string domainName)
|
|
{
|
|
SETTING_LOG_INFO("n_s_u_o");
|
|
|
|
ani_boolean stageMode = false;
|
|
ani_status status = OHOS::AbilityRuntime::IsStageContext(env, context, stageMode);
|
|
if (status != ANI_OK) {
|
|
SETTING_LOG_ERROR("%{public}s, not stage mode.", __func__);
|
|
return false;
|
|
}
|
|
|
|
std::string key = unwrap_string_from_js(env, name);
|
|
std::string tableName = unwrap_string_from_js(env, domainName);
|
|
|
|
std::lock_guard<std::mutex> lockGuard(g_observerMapMutex);
|
|
if (g_observerMap.find(key) == g_observerMap.end()) {
|
|
SETTING_LOG_ERROR("%{public}s, null.", __func__);
|
|
return false;
|
|
}
|
|
|
|
if (g_observerMap[key] == nullptr) {
|
|
g_observerMap.erase(key);
|
|
return false;
|
|
}
|
|
|
|
auto dataShareHelper = getDataShareHelper(env, context, tableName);
|
|
if (dataShareHelper == nullptr) {
|
|
SETTING_LOG_ERROR("%{public}s, data share is null.", __func__);
|
|
return false;
|
|
}
|
|
std::string strUri = GetStageUriStr(tableName, GetObserverIdStr(), key);
|
|
OHOS::Uri uri(strUri);
|
|
|
|
env->GlobalReference_Delete(g_observerMap[key]->cbInfo->callbackRef);
|
|
env->GlobalReference_Delete(g_observerMap[key]->callback_);
|
|
dataShareHelper->UnregisterObserver(uri, g_observerMap[key]);
|
|
dataShareHelper->Release();
|
|
g_observerMap[key]->toBeDelete = true;
|
|
g_observerMap[key] = nullptr;
|
|
g_observerMap.erase(key);
|
|
return true;
|
|
}
|
|
} // namespace Settings
|
|
} // namespace OHOS
|