* Copyright (C) 2022-2024 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 "userfile_client.h"
#include "ability.h"
#include "iservice_registry.h"
#include "media_asset_rdbstore.h"
#include "medialibrary_errno.h"
#include "medialibrary_napi_log.h"
#include "medialibrary_helper_container.h"
#include "media_file_utils.h"
#include "safe_map.h"
using namespace std;
using namespace OHOS::DataShare;
using namespace OHOS::AppExecFwk;
namespace OHOS {
namespace Media {
constexpr int32_t BUNDLE_MGR_SERVICE_SYS_ABILITY_ID = 401;
int32_t UserFileClient::userId_ = -1;
string UserFileClient::bundleName_ = "";
std::string MULTI_USER_URI_FLAG = "user=";
std::string USER_STR = "user";
SafeMap<int32_t, std::shared_ptr<DataShare::DataShareHelper>> UserFileClient::dataShareHelperMap_ = {};
sptr<AppExecFwk::IBundleMgr> UserFileClient::bundleMgr_ = nullptr;
mutex UserFileClient::bundleMgrMutex_;
static std::string GetMediaLibraryDataUri(const int32_t userId)
{
std::string mediaLibraryDataUri = MEDIALIBRARY_DATA_URI;
if (userId != -1) {
mediaLibraryDataUri = mediaLibraryDataUri + "?" + MULTI_USER_URI_FLAG + to_string(userId);
}
return mediaLibraryDataUri;
}
void UriAppendKeyValue(std::string &uri, const std::string &key, const std::string &value)
{
std::string uriKey = key + '=';
if (uri.find(uriKey) != std::string::npos) {
return;
}
char queryMark = (uri.find('?') == std::string::npos) ? '?' : '&';
std::string append = queryMark + key + '=' + value;
size_t posJ = uri.find('#');
if (posJ == std::string::npos) {
uri += append;
} else {
uri.insert(posJ, append);
}
}
static Uri MultiUserUriRecognition(Uri &uri, const int32_t userId)
{
if (userId == -1) {
return uri;
}
std::string uriString = uri.ToString();
UriAppendKeyValue(uriString, USER_STR, to_string(userId));
return Uri(uriString);
}
static void DataShareCreator(const sptr<IRemoteObject> &token,
shared_ptr<DataShare::DataShareHelper> &dataShareHelper, const int32_t userId)
{
dataShareHelper = DataShare::DataShareHelper::Creator(token, GetMediaLibraryDataUri(userId));
if (dataShareHelper == nullptr) {
NAPI_ERR_LOG("dataShareHelper Creator failed");
dataShareHelper = DataShare::DataShareHelper::Creator(token, GetMediaLibraryDataUri(userId));
}
}
shared_ptr<DataShare::DataShareHelper> UserFileClient::GetDataShareHelper(napi_env env,
napi_callback_info info, const int32_t userId)
{
size_t argc = ARGS_ONE;
napi_value argv[ARGS_ONE] = {0};
napi_value thisVar = nullptr;
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
std::shared_ptr<DataShare::DataShareHelper> dataShareHelper = nullptr;
bool isStageMode = false;
napi_status status = OHOS::AbilityRuntime::IsStageContext(env, argv[0], isStageMode);
if (status != napi_ok || !isStageMode) {
NAPI_INFO_LOG("status: %{public}d, isStageMode: %{public}d", status, static_cast<int32_t>(isStageMode));
auto ability = OHOS::AbilityRuntime::GetCurrentAbility(env);
if (ability == nullptr) {
NAPI_ERR_LOG("Failed to get native ability instance");
return nullptr;
}
auto context = ability->GetContext();
if (context == nullptr) {
NAPI_ERR_LOG("Failed to get native context instance");
return nullptr;
}
DataShareCreator(context->GetToken(), dataShareHelper, userId);
} else {
auto context = OHOS::AbilityRuntime::GetStageModeContext(env, argv[0]);
if (context == nullptr) {
NAPI_ERR_LOG("Failed to get native stage context instance");
return nullptr;
}
DataShareCreator(context->GetToken(), dataShareHelper, userId);
}
MediaLibraryHelperContainer::GetInstance()->SetDataShareHelper(dataShareHelper);
return dataShareHelper;
}
napi_status UserFileClient::CheckIsStage(napi_env env, napi_callback_info info, bool &result)
{
size_t argc = ARGS_ONE;
napi_value argv[ARGS_ONE] = {0};
napi_value thisVar = nullptr;
napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
if (status != napi_ok) {
NAPI_ERR_LOG("Failed to get cb info, status=%{public}d", (int) status);
return status;
}
result = false;
status = OHOS::AbilityRuntime::IsStageContext(env, argv[0], result);
if (status != napi_ok) {
NAPI_ERR_LOG("Failed to get stage mode, status=%{public}d", (int) status);
return status;
}
return napi_ok;
}
sptr<IRemoteObject> UserFileClient::ParseTokenInStageMode(napi_env env, napi_callback_info info)
{
size_t argc = ARGS_ONE;
napi_value argv[ARGS_ONE] = {0};
napi_value thisVar = nullptr;
if (napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr) != napi_ok) {
NAPI_ERR_LOG("Failed to get cb info");
return nullptr;
}
auto context = OHOS::AbilityRuntime::GetStageModeContext(env, argv[0]);
if (context == nullptr) {
NAPI_ERR_LOG("Failed to get native stage context instance");
return nullptr;
}
return context->GetToken();
}
sptr<IRemoteObject> UserFileClient::ParseTokenInAbility(napi_env env, napi_callback_info info)
{
size_t argc = ARGS_ONE;
napi_value argv[ARGS_ONE] = {0};
napi_value thisVar = nullptr;
if (napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr) != napi_ok) {
NAPI_ERR_LOG("Failed to get cb info");
return nullptr;
}
auto ability = OHOS::AbilityRuntime::GetCurrentAbility(env);
if (ability == nullptr) {
NAPI_ERR_LOG("Failed to get native ability instance");
return nullptr;
}
auto context = ability->GetContext();
if (context == nullptr) {
NAPI_ERR_LOG("Failed to get native context instance");
return nullptr;
}
return context->GetToken();
}
bool UserFileClient::IsValid(const int32_t userId)
{
std::shared_ptr<DataShare::DataShareHelper> helper;
if (dataShareHelperMap_.Find(userId, helper)) {
return helper != nullptr;
}
return false;
}
std::shared_ptr<DataShare::DataShareHelper> UserFileClient::GetDataShareHelperByUser(const int32_t userId)
{
return dataShareHelperMap_.ReadVal(userId);
}
void UserFileClient::Init(const sptr<IRemoteObject> &token, bool isSetHelper, const int32_t userId)
{
if (GetDataShareHelperByUser(userId) == nullptr) {
std::shared_ptr<DataShare::DataShareHelper> dataShareHelper =
DataShare::DataShareHelper::Creator(token, GetMediaLibraryDataUri(userId));
if (isSetHelper) {
MediaLibraryHelperContainer::GetInstance()->SetDataShareHelper(dataShareHelper);
}
if (dataShareHelper != nullptr) {
if (!IsValid(userId)) {
dataShareHelperMap_.EnsureInsert(userId, dataShareHelper);
} else {
NAPI_ERR_LOG("dataShareHelperMap has userId and value");
}
} else {
NAPI_ERR_LOG("Failed to getDataShareHelper, dataShareHelper is null");
}
}
}
void UserFileClient::Init(napi_env env, napi_callback_info info, const int32_t userId)
{
if (GetDataShareHelperByUser(userId) == nullptr) {
std::shared_ptr<DataShare::DataShareHelper> dataShareHelper = GetDataShareHelper(env, info, userId);
if (dataShareHelper != nullptr) {
if (!IsValid(userId)) {
dataShareHelperMap_.EnsureInsert(userId, dataShareHelper);
} else {
NAPI_ERR_LOG("dataShareHelperMap has userId and value");
}
} else {
NAPI_ERR_LOG("Failed to getDataShareHelper, dataShareHelper is null");
}
}
}
shared_ptr<DataShareResultSet> UserFileClient::Query(Uri &uri, const DataSharePredicates &predicates,
std::vector<std::string> &columns, int &errCode, const int32_t userId)
{
if (!IsValid(userId)) {
NAPI_ERR_LOG("Query fail, helper null, userId is %{public}d", userId);
return nullptr;
}
shared_ptr<DataShareResultSet> resultSet = nullptr;
OperationObject object = OperationObject::UNKNOWN_OBJECT;
if (MediaAssetRdbStore::GetInstance()->IsQueryAccessibleViaSandBox(uri, object, predicates) && userId == -1) {
resultSet = MediaAssetRdbStore::GetInstance()->Query(predicates, columns, object, errCode);
} else {
uri = MultiUserUriRecognition(uri, userId);
DatashareBusinessError businessError;
resultSet = GetDataShareHelperByUser(userId)->Query(uri, predicates, columns, &businessError);
errCode = businessError.GetCode();
}
return resultSet;
}
shared_ptr<NativeRdb::ResultSet> UserFileClient::QueryByStep(const std::string &sql)
{
std::shared_ptr<NativeRdb::ResultSet> resultSet = MediaAssetRdbStore::GetInstance()->QueryByStep(sql);
return resultSet;
}
std::pair<bool, shared_ptr<DataShareResultSet>> UserFileClient::QueryAccessibleViaSandBox(Uri &uri,
const DataSharePredicates &predicates, std::vector<std::string> &columns, int &errCode, const int32_t userId)
{
OperationObject object = OperationObject::UNKNOWN_OBJECT;
if (MediaAssetRdbStore::GetInstance()->IsQueryAccessibleViaSandBox(uri, object, predicates) && userId == -1) {
return {true, MediaAssetRdbStore::GetInstance()->Query(predicates, columns, object, errCode)};
}
return {false, nullptr};
}
std::shared_ptr<NativeRdb::ResultSet> UserFileClient::QueryRdb(Uri &uri,
const DataShare::DataSharePredicates &predicates, std::vector<std::string> &columns)
{
shared_ptr<NativeRdb::ResultSet> resultSet = nullptr;
OperationObject object = OperationObject::UNKNOWN_OBJECT;
if (MediaAssetRdbStore::GetInstance()->IsSupportSharedAssetQuery(uri, object)) {
resultSet = MediaAssetRdbStore::GetInstance()->QueryRdb(predicates, columns, object);
}
return resultSet;
}
int UserFileClient::Insert(Uri &uri, const DataShareValuesBucket &value, const int32_t userId)
{
if (!IsValid(userId)) {
NAPI_ERR_LOG("insert fail, helper null, userId is %{public}d", userId);
return E_FAIL;
}
int index = GetDataShareHelperByUser(userId)->Insert(uri, value);
return index;
}
int UserFileClient::InsertExt(Uri &uri, const DataShareValuesBucket &value, string &result, const int32_t userId)
{
if (!IsValid(userId)) {
NAPI_ERR_LOG("insert fail, helper null, userId is %{public}d", userId);
return E_FAIL;
}
int index = GetDataShareHelperByUser(userId)->InsertExt(uri, value, result);
return index;
}
int UserFileClient::BatchInsert(Uri &uri, const std::vector<DataShare::DataShareValuesBucket> &values)
{
if (!IsValid(GetUserId())) {
NAPI_ERR_LOG("Batch insert fail, helper null, userId is %{public}d", GetUserId());
return E_FAIL;
}
return GetDataShareHelperByUser(GetUserId())->BatchInsert(uri, values);
}
int UserFileClient::Delete(Uri &uri, const DataSharePredicates &predicates)
{
if (!IsValid(GetUserId())) {
NAPI_ERR_LOG("delete fail, helper null, userId is %{public}d", GetUserId());
return E_FAIL;
}
return GetDataShareHelperByUser(GetUserId())->Delete(uri, predicates);
}
void UserFileClient::NotifyChange(const Uri &uri)
{
if (!IsValid(GetUserId())) {
NAPI_ERR_LOG("notify change fail, helper null, userId is %{public}d", GetUserId());
return;
}
GetDataShareHelperByUser(GetUserId())->NotifyChange(uri);
}
void UserFileClient::RegisterObserver(const Uri &uri, const sptr<AAFwk::IDataAbilityObserver> &dataObserver)
{
if (!IsValid(GetUserId())) {
NAPI_ERR_LOG("register observer fail, helper null, userId is %{public}d", GetUserId());
return;
}
GetDataShareHelperByUser(GetUserId())->RegisterObserver(uri, dataObserver);
}
void UserFileClient::UnregisterObserver(const Uri &uri, const sptr<AAFwk::IDataAbilityObserver> &dataObserver)
{
if (!IsValid(GetUserId())) {
NAPI_ERR_LOG("unregister observer fail, helper null, userId is %{public}d", GetUserId());
return;
}
GetDataShareHelperByUser(GetUserId())->UnregisterObserver(uri, dataObserver);
}
int UserFileClient::OpenFile(Uri &uri, const std::string &mode, const int32_t userId)
{
if (!IsValid(userId)) {
NAPI_ERR_LOG("Open file fail, helper null, userId is %{public}d", userId);
return E_FAIL;
}
uri = MultiUserUriRecognition(uri, userId);
return GetDataShareHelperByUser(userId)->OpenFile(uri, mode);
}
int UserFileClient::OpenFileWithErrCode(Uri &uri, const std::string &mode, int32_t &realErr, const int32_t userId)
{
if (!IsValid(userId)) {
NAPI_ERR_LOG("Open file fail, helper null, userId is %{public}d", userId);
return E_FAIL;
}
uri = MultiUserUriRecognition(uri, userId);
return GetDataShareHelperByUser(userId)->OpenFileWithErrCode(uri, mode, realErr);
}
int UserFileClient::Update(Uri &uri, const DataSharePredicates &predicates,
const DataShareValuesBucket &value, const int32_t userId)
{
if (!IsValid(userId)) {
NAPI_ERR_LOG("update fail, helper null, userId is %{public}d", userId);
return E_FAIL;
}
return GetDataShareHelperByUser(userId)->Update(uri, predicates, value);
}
void UserFileClient::RegisterObserverExt(const Uri &uri,
shared_ptr<DataShare::DataShareObserver> dataObserver, bool isDescendants)
{
if (!IsValid(GetUserId())) {
NAPI_ERR_LOG("register observer fail, helper null, userId is %{public}d", GetUserId());
return;
}
GetDataShareHelperByUser(GetUserId())->RegisterObserverExt(uri, std::move(dataObserver), isDescendants);
}
void UserFileClient::UnregisterObserverExt(const Uri &uri, std::shared_ptr<DataShare::DataShareObserver> dataObserver)
{
if (!IsValid(GetUserId())) {
NAPI_ERR_LOG("unregister observer fail, helper null, userId is %{public}d", GetUserId());
return;
}
GetDataShareHelperByUser(GetUserId())->UnregisterObserverExt(uri, std::move(dataObserver));
}
std::string UserFileClient::GetType(Uri &uri)
{
if (!IsValid(GetUserId())) {
NAPI_ERR_LOG("get type fail, helper null, userId is %{public}d", GetUserId());
return "";
}
return GetDataShareHelperByUser(GetUserId())->GetType(uri);
}
int32_t UserFileClient::UserDefineFunc(MessageParcel &data, MessageParcel &reply, MessageOption &option)
{
if (!IsValid(GetUserId())) {
NAPI_ERR_LOG("JS UserDefineFunc fail, helper null %{public}d", GetUserId());
return E_FAIL;
}
return GetDataShareHelperByUser(GetUserId())->UserDefineFunc(data, reply, option);
}
int32_t UserFileClient::UserDefineFunc(const int32_t &userId, MessageParcel &data, MessageParcel &reply,
MessageOption &option)
{
if (!IsValid(userId)) {
NAPI_ERR_LOG("JS UserDefineFunc fail, helper null %{public}d", userId);
return E_FAIL;
}
return GetDataShareHelperByUser(userId)->UserDefineFunc(data, reply, option);
}
void UserFileClient::Clear()
{
dataShareHelperMap_.Clear();
}
void UserFileClient::SetUserId(const int32_t userId)
{
userId_ = userId;
}
int32_t UserFileClient::GetUserId()
{
return userId_;
}
sptr<AppExecFwk::IBundleMgr> UserFileClient::GetSysBundleManager()
{
lock_guard<mutex> lock(bundleMgrMutex_);
if (bundleMgr_ != nullptr) {
return bundleMgr_;
}
auto systemAbilityMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
if (systemAbilityMgr == nullptr) {
NAPI_ERR_LOG("Failed to get SystemAbilityManager.");
return nullptr;
}
auto bundleObj = systemAbilityMgr->GetSystemAbility(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID);
if (bundleObj == nullptr) {
NAPI_ERR_LOG("Remote object is nullptr.");
return nullptr;
}
bundleMgr_ = iface_cast<AppExecFwk::IBundleMgr>(bundleObj);
if (bundleMgr_ == nullptr) {
NAPI_ERR_LOG("Failed to iface_cast");
return nullptr;
}
return bundleMgr_;
}
string UserFileClient::GetBundleName()
{
if (bundleName_ != "") {
return bundleName_;
}
bundleMgr_ = GetSysBundleManager();
if (bundleMgr_ == nullptr) {
NAPI_ERR_LOG("bundleMgr_ is null");
return bundleName_;
}
int32_t uid = static_cast<int32_t>(getuid());
string bundleName;
auto result = bundleMgr_->GetBundleNameForUid(uid, bundleName);
if (!result) {
NAPI_ERR_LOG("result is false");
return bundleName_;
}
NAPI_INFO_LOG("hap bundleName: %{public}s", bundleName.c_str());
bundleName_ = bundleName;
return bundleName_;
}
int32_t UserFileClient::RegisterObserverExtProvider(const Uri &uri,
std::shared_ptr<DataShare::DataShareObserver> dataObserver, bool isDescendants)
{
if (!IsValid(GetUserId())) {
NAPI_ERR_LOG("register observer fail, helper null, userId is %{public}d", GetUserId());
return E_FAIL;
}
return
GetDataShareHelperByUser(GetUserId())->RegisterObserverExtProvider(uri, std::move(dataObserver), isDescendants);
}
int32_t UserFileClient::UnregisterObserverExtProvider(const Uri &uri,
std::shared_ptr<DataShare::DataShareObserver> dataObserver)
{
if (!IsValid(GetUserId())) {
NAPI_ERR_LOG("unregister observer fail, helper null, userId is %{public}d", GetUserId());
return E_FAIL;
}
return GetDataShareHelperByUser(GetUserId())->UnregisterObserverExtProvider(uri, std::move(dataObserver));
}
}
}