diff --git a/BUILD.gn b/BUILD.gn index 95fe9bedc502baa67fecd3eeff41bec2edd91de3..9be9551d7f4b34a551ee0d0a931a77bb5116c302 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -382,6 +382,7 @@ ohos_shared_library("form_manager") { "jsoncpp:jsoncpp", "napi:ace_napi", "samgr:samgr_proxy", + "os_account:os_account_innerkits", ] subsystem_name = "ability" diff --git a/interfaces/inner_api/include/form_js_info.h b/interfaces/inner_api/include/form_js_info.h index 3b12bd2e8ffc09e0d3ecd55ab3f59e52184c19bb..43b94b49ccaae26954d89b70c1dfc740ee7a72cf 100644 --- a/interfaces/inner_api/include/form_js_info.h +++ b/interfaces/inner_api/include/form_js_info.h @@ -30,6 +30,7 @@ namespace AppExecFwk { */ struct FormJsInfo : public Parcelable { static constexpr int IMAGE_DATA_THRESHOLD = 128; + static constexpr int BIG_DATA = 32 * 1024; int64_t formId; std::string formName; std::string bundleName; @@ -50,10 +51,14 @@ struct FormJsInfo : public Parcelable { FormType uiSyntax = FormType::JS; bool isDynamic = true; bool transparencyEnabled = false; + bool isSystemApp = false; bool ReadFromParcel(Parcel &parcel); virtual bool Marshalling(Parcel &parcel) const override; static FormJsInfo *Unmarshalling(Parcel &parcel); + bool GetCurrentUserId(int &userId) const; + bool CheckIsSystemApp(const std::string& bundleName) const; + bool WriteFormData(Parcel &parcel) const; bool WriteObjects(Parcel &parcel) const; bool WriteImageData(Parcel &parcel) const; void ReadImageData(Parcel &parcel); diff --git a/interfaces/inner_api/include/form_provider_data.h b/interfaces/inner_api/include/form_provider_data.h index fa532548e70529bab2d1a6bd185bcb9b33ec2d6e..3976b545fc713d976d83e2ce4e327cadea038367 100644 --- a/interfaces/inner_api/include/form_provider_data.h +++ b/interfaces/inner_api/include/form_provider_data.h @@ -24,6 +24,7 @@ #include "message_parcel.h" #include "nlohmann/json.hpp" #include "parcel.h" +#include "securec.h" namespace OHOS { namespace AppExecFwk { @@ -159,6 +160,27 @@ public: */ static FormProviderData* Unmarshalling(Parcel &parcel); + bool WriteFormData(Parcel &parcel) const; + + bool WriteAshmemDataToParcel(Parcel &parcel, size_t size, const char* dataPtr) const; + + char *ReadAshmemDataFromParcel(Parcel &parcel, int32_t bufferSize); + + bool WriteFileDescriptor(Parcel &parcel, int fd) const; + + int ReadFileDescriptor(Parcel &parcel); + + static bool CheckAshmemSize(const int &fd, const int32_t &bufferSize, bool isAstc = false) + { + if (fd < 0) { + return false; + } + int32_t ashmemSize = AshmemGetSize(fd); + return isAstc || bufferSize == ashmemSize; + } + + void ReleaseMemory(int32_t allocType, void *addr, void *context, uint32_t size); + /** * @brief Clear imageDataMap, rawImageBytesMap, imageDataState and jsonFormProviderData. */ @@ -179,6 +201,7 @@ public: static constexpr int IMAGE_DATA_STATE_REMOVED = -1; static constexpr int IMAGE_DATA_STATE_NO_OPERATION = 0; static constexpr int IMAGE_DATA_STATE_ADDED = 1; + nlohmann::json jsonFormProviderData_; private: bool WriteImageDataToParcel(Parcel &parcel, const std::string &picName, const std::shared_ptr &data, @@ -197,7 +220,6 @@ private: delete[] bytes; } }; - nlohmann::json jsonFormProviderData_; std::map, int32_t>> imageDataMap_; std::map, int32_t>> rawImageBytesMap_; int32_t imageDataState_ = 0; diff --git a/interfaces/inner_api/src/form_js_info.cpp b/interfaces/inner_api/src/form_js_info.cpp index 25586d6a7cf8ebe8bb113da75cb365f938a9e657..f472166f7e91ec9a68c4036bac31990a59dd99dd 100644 --- a/interfaces/inner_api/src/form_js_info.cpp +++ b/interfaces/inner_api/src/form_js_info.cpp @@ -16,6 +16,11 @@ #include "form_js_info.h" #include "fms_log_wrapper.h" #include "string_ex.h" +#include "message_parcel.h" + +#include "iservice_registry.h" +#include "bundle_mgr_interface.h" +#include "os_account_manager.h" namespace OHOS { namespace AppExecFwk { @@ -29,7 +34,16 @@ bool FormJsInfo::ReadFromParcel(Parcel &parcel) formTempFlag = parcel.ReadBool(); jsFormCodePath = Str16ToStr8(parcel.ReadString16()); - formData = Str16ToStr8(parcel.ReadString16()); + MessageParcel* msgParcel = static_cast(&parcel); + int32_t formDataLength = parcel.ReadInt32(); + HILOG_INFO("ReadFromParcel data length is %{public}d , formId:%{public}lld", formDataLength, formId); + if (formDataLength > BIG_DATA) { + HILOG_INFO("data length > 32k"); + const void *rawData = msgParcel->ReadRawData(formDataLength); + formData = static_cast(rawData); + } else { + formData = Str16ToStr8(parcel.ReadString16()); + } formSrc = Str16ToStr8(parcel.ReadString16()); formWindow.designWidth = parcel.ReadInt32(); @@ -43,6 +57,7 @@ bool FormJsInfo::ReadFromParcel(Parcel &parcel) uiSyntax = static_cast(parcel.ReadInt32()); isDynamic = parcel.ReadBool(); transparencyEnabled = parcel.ReadBool(); + isSystemApp = parcel.ReadBool(); std::unique_ptr bindingData(parcel.ReadParcelable()); if (bindingData == nullptr) { @@ -99,7 +114,7 @@ bool FormJsInfo::Marshalling(Parcel &parcel) const } // write formData and formSrc - if (!parcel.WriteString16(Str8ToStr16(formData)) || !parcel.WriteString16(Str8ToStr16(formSrc))) { + if (!WriteFormData(parcel) || !parcel.WriteString16(Str8ToStr16(formSrc))) { return false; } @@ -123,12 +138,84 @@ bool FormJsInfo::Marshalling(Parcel &parcel) const if (!parcel.WriteBool(isDynamic) || !parcel.WriteBool(transparencyEnabled)) { return false; } + bool isSysApp = CheckIsSystemApp(bundleName.c_str()); + if (!parcel.WriteBool(isSysApp)) { + return false; + } if (!WriteObjects(parcel)) { return false; } return true; } +bool FormJsInfo::GetCurrentUserId(int &userId) const +{ + std::vector activeIds; + int ret = OHOS::AccountSA::OsAccountManager::QueryActiveOsAccountIds(activeIds); + if (ret != 0) { + userId = 100; // DEFAULT_USERID = 100 + HILOG_INFO("GetCurrentUserId failed ret:%{public}d", ret); + return false; + } + if (activeIds.empty()) { + userId = 100; // DEFAULT_USERID = 100 + HILOG_INFO("QueryActiveOsAccountIds activeIds empty"); + return false; + } + userId = activeIds[0]; + return true; +} + +bool FormJsInfo::CheckIsSystemApp(const std::string& bundleName) const +{ + int userId = 0; + bool ret = GetCurrentUserId(userId); + HILOG_INFO("check SystemApp, userId: %{public}d", userId); + if (!ret) { + HILOG_INFO("GetCurrentUserId failed"); + return false; + } + auto systemManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (systemManager == nullptr) { + HILOG_INFO("fail to get system ability manager!"); + return false; + } + auto bundleMgrSa = systemManager->GetSystemAbility(401); // BUNDLE_MGR_SERVICE_SYS_ABILITY_ID = 401 + if (bundleMgrSa == nullptr) { + HILOG_INFO("fail to get bundle manager system ability!"); + return false; + } + auto bundleMgr = iface_cast(bundleMgrSa); + if (bundleMgr == nullptr) { + HILOG_INFO("Bundle mgr is nullptr."); + return false; + } + AppExecFwk::ApplicationInfo info; + ErrCode code = bundleMgr->GetApplicationInfoV9(bundleName, 0, userId, info); + if (code != ERR_OK) { + HILOG_INFO("Failed to GetApplicationInfoV9"); + return false; + } + if (info.isSystemApp) { + return true; + } + HILOG_INFO("Not system App."); + return false; +} + +bool FormJsInfo::WriteFormData(Parcel &parcel) const +{ + MessageParcel* msgParcel = static_cast(&parcel); + int32_t formDataLength = formData.length(); + parcel.WriteInt32(formDataLength); + if (formDataLength > BIG_DATA) { + HILOG_INFO("WriteFormData data length is %{public}d", formDataLength); + return msgParcel->WriteRawData(formData.c_str(), formDataLength); + } else { + return parcel.WriteString16(Str8ToStr16(formData)); + } +} + bool FormJsInfo::WriteObjects(Parcel &parcel) const { // write formProviderData diff --git a/interfaces/inner_api/src/form_provider_data.cpp b/interfaces/inner_api/src/form_provider_data.cpp index fc7027de9ab0b786d0f0cccbee0f45393d99d6f1..74fbcb6a7d722d229b102d5f367def3e7cb7ddf0 100644 --- a/interfaces/inner_api/src/form_provider_data.cpp +++ b/interfaces/inner_api/src/form_provider_data.cpp @@ -26,12 +26,20 @@ #include "message_parcel.h" #include "string_ex.h" +#include +#include "ashmem.h" +#include "buffer_handle_parcel.h" +#include "ipc_file_descriptor.h" + namespace OHOS { namespace AppExecFwk { const std::string JSON_EMPTY_STRING = "{}"; const std::string JSON_IMAGES_STRING = "formImages"; constexpr int32_t READ_PARCEL_MAX_IMAGE_DATA_NUM_SIZE = 1000; constexpr int32_t MAX_IMAGE_BYTE_SIZE = 50 * 1024 * 1024; +constexpr int32_t MAX_BUFFER_SIZE = 600 * 1024 * 1024; +constexpr int32_t BIG_DATA = 32 * 1024; +constexpr int32_t SHARE_MEM_ALLOC = 2; /** * @brief Constructor. */ @@ -285,7 +293,15 @@ void FormProviderData::SetImageDataMap(std::map BIG_DATA) { + const void *rawData = ReadAshmemDataFromParcel(parcel, formDataLength); + jsonDataString = static_cast(rawData); + } else { + jsonDataString = Str16ToStr8(parcel.ReadString16()); + } nlohmann::json jsonObject = nlohmann::json::parse(jsonDataString, nullptr, false); if (jsonObject.is_discarded()) { HILOG_ERROR("fail parse jsonDataString: %{private}s.", jsonDataString.c_str()); @@ -325,6 +341,149 @@ bool FormProviderData::ReadFromParcel(Parcel &parcel) return true; } +int FormProviderData::ReadFileDescriptor(Parcel &parcel) +{ + sptr descriptor = parcel.ReadObject(); + if (descriptor == nullptr) { + HILOG_INFO("ReadFileDescriptor get descriptor failed"); + return -1; + } + int fd = descriptor->GetFd(); + if (fd < 0) { + HILOG_INFO("ReadFileDescriptor get fd failed, fd:[%{public}d].", fd); + return -1; + } + return dup(fd); +} + +void FormProviderData::ReleaseMemory(int32_t allocType, void *addr, void *context, uint32_t size) +{ + if (allocType == SHARE_MEM_ALLOC) { + if (context != nullptr) { + int *fd = static_cast(context); + if (addr != nullptr) { + ::munmap(addr, size); + } + if (fd != nullptr) { + ::close(*fd); + } + context = nullptr; + addr = nullptr; + } + } +} + +char *FormProviderData::ReadAshmemDataFromParcel(Parcel &parcel, int32_t bufferSize) +{ + char *base = nullptr; + int fd = ReadFileDescriptor(parcel); + if (!CheckAshmemSize(fd, bufferSize)) { + HILOG_INFO("ReadAshmemDataFromParcel check ashmem size failed, fd:[%{public}d].", fd); + return nullptr; + } + if (bufferSize <= 0 || bufferSize > MAX_BUFFER_SIZE) { + HILOG_INFO("malloc parameter bufferSize:[%{public}d] error.", bufferSize); + return nullptr; + } + + void *ptr = ::mmap(nullptr, bufferSize, PROT_READ, MAP_SHARED, fd, 0); + if (ptr == MAP_FAILED) { + // do not close fd here. fd will be closed in FileDescriptor, ::close(fd) + HILOG_INFO("ReadImageData map failed, errno:%{public}d", errno); + return nullptr; + } + + base = static_cast(malloc(bufferSize)); + if (base == nullptr) { + ::munmap(ptr, bufferSize); + HILOG_INFO("alloc output pixel memory size:[%{public}d] error.", bufferSize); + return nullptr; + } + if (memcpy_s(base, bufferSize, ptr, bufferSize) != 0) { + ::munmap(ptr, bufferSize); + free(base); + base = nullptr; + HILOG_INFO("memcpy pixel data size:[%{public}d] error.", bufferSize); + return nullptr; + } + + ReleaseMemory(SHARE_MEM_ALLOC, ptr, &fd, bufferSize); + return base; +} + +bool FormProviderData::WriteFileDescriptor(Parcel &parcel, int fd) const +{ + if (fd < 0) { + HILOG_INFO("WriteFileDescriptor get fd failed, fd:[%{public}d].", fd); + return false; + } + int dupFd = dup(fd); + if (dupFd < 0) { + HILOG_INFO("WriteFileDescriptor dup fd failed, dupFd:[%{public}d].", dupFd); + return false; + } + sptr descriptor = new IPCFileDescriptor(dupFd); + return parcel.WriteObject(descriptor); +} + +bool FormProviderData::WriteAshmemDataToParcel(Parcel &parcel, size_t size, const char* dataPtr) const +{ + const char *data = dataPtr; + std::string name = "formAshmemData"; + int fd = AshmemCreate(name.c_str(), size); + HILOG_INFO("AshmemCreate:[%{public}d].", fd); + if (fd < 0) { + return false; + } + + int result = AshmemSetProt(fd, PROT_READ | PROT_WRITE); + HILOG_INFO("AshmemSetProt:[%{public}d].", result); + if (result < 0) { + ::close(fd); + return false; + } + void *ptr = ::mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (ptr == MAP_FAILED) { + ::close(fd); + HILOG_INFO("WriteAshmemData map failed, errno:%{public}d", errno); + return false; + } + HILOG_INFO("mmap success"); + + if (memcpy_s(ptr, size, data, size) != EOK) { + ::munmap(ptr, size); + ::close(fd); + HILOG_INFO("WriteAshmemData memcpy_s error"); + return false; + } + + if (!FormProviderData::WriteFileDescriptor(parcel, fd)) { + ::munmap(ptr, size); + ::close(fd); + HILOG_INFO("WriteAshmemData WriteFileDescriptor error"); + return false; + } + HILOG_INFO("WriteAshmemData WriteFileDescriptor success"); + ::munmap(ptr, size); + ::close(fd); + return true; +} + +bool FormProviderData::WriteFormData(Parcel &parcel) const +{ + std::string formData = jsonFormProviderData_.empty() ? + JSON_EMPTY_STRING : jsonFormProviderData_.dump(); + int32_t formDataLength = formData.length(); + parcel.WriteInt32(formDataLength); + if (formDataLength > BIG_DATA) { + const char* dataPtr = formData.c_str(); + HILOG_INFO("FormProviderData::WriteFormData data length is %{public}d", formDataLength); + return WriteAshmemDataToParcel(parcel, formDataLength, dataPtr); + } else { + return parcel.WriteString16(Str8ToStr16(formData)); + } +} + /** * @brief Marshals this {@code FormProviderData} object into a {@link ohos.utils.Parcel} object. * @param parcel Indicates the {@code Parcel} object for marshalling. @@ -333,8 +492,7 @@ bool FormProviderData::ReadFromParcel(Parcel &parcel) bool FormProviderData::Marshalling(Parcel &parcel) const { HILOG_DEBUG("jsonFormProviderData_ is private"); - if (!parcel.WriteString16(Str8ToStr16(jsonFormProviderData_.empty() ? - JSON_EMPTY_STRING : jsonFormProviderData_.dump()))) { + if (!WriteFormData(parcel)) { return false; } diff --git a/interfaces/kits/native/src/form_provider_client.cpp b/interfaces/kits/native/src/form_provider_client.cpp index 6837198a44d3299f36de5f3206cfa2e73e741fda..656778c70c665bde11a0324b6db4a2e3fe8973ac 100644 --- a/interfaces/kits/native/src/form_provider_client.cpp +++ b/interfaces/kits/native/src/form_provider_client.cpp @@ -30,6 +30,7 @@ namespace OHOS { namespace AppExecFwk { +constexpr int32_t BIG_DATA = 32 * 1024; int FormProviderClient::AcquireProviderFormInfo( const FormJsInfo &formJsInfo, const Want &want, @@ -80,6 +81,9 @@ int FormProviderClient::AcquireProviderFormInfo( FormProviderInfo formProviderInfo = ownerAbility->OnCreate(createWant); HILOG_DEBUG("formId:%{public}" PRId64 ", data: %{private}s", formJsInfo.formId, formProviderInfo.GetFormDataString().c_str()); + if (formJsInfo.formProviderData.jsonFormProviderData_.size() > BIG_DATA && !formJsInfo.isSystemApp) { + return ERR_APPEXECFWK_FORM_BIND_PROVIDER_FAILED; + } if (newWant.HasParameter(Constants::PARAM_FORM_HOST_TOKEN)) { HandleRemoteAcquire(formJsInfo, formProviderInfo, newWant, AsObject()); } diff --git a/services/src/form_mgr_adapter.cpp b/services/src/form_mgr_adapter.cpp index 5217f885de4d812e9c570ef482031c04ce4763dd..cbebc84c60e7e439a63c53fafc22b1dadc1600a5 100644 --- a/services/src/form_mgr_adapter.cpp +++ b/services/src/form_mgr_adapter.cpp @@ -91,6 +91,7 @@ constexpr int32_t DEFAULT_USER_ID = 100; constexpr int32_t BUNDLE_NAME_INDEX = 0; constexpr int32_t USER_ID_INDEX = 1; constexpr int32_t INSTANCE_SEQ_INDEX = 2; +constexpr int32_t BIG_DATA = 32 * 1024; const std::string BUNDLE_INFO_SEPARATOR = "_"; const std::string POINT_ETS = ".ets"; constexpr int DATA_FIELD = 1; @@ -812,6 +813,9 @@ int FormMgrAdapter::UpdateForm(const int64_t formId, const int32_t callingUid, HILOG_ERROR("not exist such form:%{public}" PRId64 ".", matchedFormId); return ERR_APPEXECFWK_FORM_NOT_EXIST_ID; } + if (formProviderData.GetData().size() > BIG_DATA && !formRecord.isSystemApp) { + return ERR_APPEXECFWK_FORM_BIND_PROVIDER_FAILED; + } // Checks if the form provider is the currently active user. if (FormUtil::GetCurrentAccountId() != formRecord.providerUserId) { diff --git a/services/src/form_task_mgr.cpp b/services/src/form_task_mgr.cpp index 26f4d3aad7c3b46fbc5308635f15c502be0d87c1..cae6902ba0b4418a98adced2c733573b1bd1ed73 100644 --- a/services/src/form_task_mgr.cpp +++ b/services/src/form_task_mgr.cpp @@ -803,6 +803,7 @@ FormJsInfo FormTaskMgr::CreateFormJsInfo(const int64_t formId, const FormRecord form.uiSyntax = record.uiSyntax; form.isDynamic = record.isDynamic; form.transparencyEnabled = record.transparencyEnabled; + form.isSystemApp = record.isSystemApp; form.modulePkgNameMap = record.modulePkgNameMap; HILOG_DEBUG("jsPath: %{private}s, data: %{private}s", form.jsFormCodePath.c_str(), form.formData.c_str());