mirror of
https://github.com/openharmony/ability_ability_runtime.git
synced 2026-08-24 12:43:16 -04:00
Add serialization and parsing capabilities for wantParams
Signed-off-by: xhz-sz <xiehuandong@huawei.com>
This commit is contained in:
@@ -205,6 +205,58 @@ public:
|
||||
*/
|
||||
static std::shared_ptr<WantAgent> FromString(const std::string &jsonString, int32_t uid = -1);
|
||||
|
||||
/**
|
||||
* Convert WantAgentInfo object to string with WantParams envelope for extraInfo.
|
||||
* This function is the upgrade path for ToString when extraInfo must round
|
||||
* trip safely. ToString stores extraInfo through WantParamWrapper::ToString,
|
||||
* which uses manual string concatenation and inherits the legacy
|
||||
* WantParamsWrapper escaping and parsing limitations. This function stores
|
||||
* extraInfo through WantParamWrapperJson::Serialize so the WantParams payload
|
||||
* is wrapped by the envelope format and JSON escaping is applied.
|
||||
*
|
||||
* The output keeps the same outer WantAgent string format as ToString, but
|
||||
* extraInfo.extraInfoValue is generated by WantParamWrapperJson::Serialize:
|
||||
* {"extraInfo":{"extraInfoValue":"{\"ohos.want.paramsStringEnvelope\":{...}}"}}
|
||||
*
|
||||
* @param agent WantAgent object.
|
||||
* @return WantAgentInfo object's serialized string.
|
||||
*/
|
||||
static std::string ToStringWithEnvelope(const std::shared_ptr<WantAgent> &agent);
|
||||
|
||||
/**
|
||||
* @brief Parses a WantAgent string generated by ToStringWithEnvelope.
|
||||
*
|
||||
* Convert string with WantParams envelope extraInfo to WantAgentInfo object.
|
||||
* This function is the upgrade path for FromString when the input was
|
||||
* generated by ToStringWithEnvelope. FromString parses extraInfo with
|
||||
* WantParamWrapper::Parse and therefore has the same legacy limitations:
|
||||
* unescaped quotes/backslashes/control characters, delimiter-like content,
|
||||
* manually embedded typeId text, unsupported types, and some truncated or
|
||||
* trailing inputs may fail or restore incorrectly.
|
||||
*
|
||||
* Before calling this function, callers must use HasWantParamsEnvelope
|
||||
* to check that the input string is generated by ToStringWithEnvelope,
|
||||
* unless the data source is already guaranteed to be generated by
|
||||
* ToStringWithEnvelope.
|
||||
*
|
||||
* @param jsonString String to parse.
|
||||
* @return WantAgentInfo object.
|
||||
*/
|
||||
static std::shared_ptr<WantAgent> FromStringWithEnvelope(
|
||||
const std::string &jsonString, int32_t uid = -1);
|
||||
|
||||
/**
|
||||
* Check whether the input string contains WantParams envelope in extraInfo.
|
||||
*
|
||||
* This function is used to distinguish data generated by
|
||||
* ToStringWithEnvelope from legacy data generated by ToString.
|
||||
*
|
||||
* @param jsonString String to check.
|
||||
* @return Returns true if the WantParamWrapperJson envelope is detected;
|
||||
* returns false otherwise.
|
||||
*/
|
||||
static bool HasWantParamsEnvelope(const std::string &jsonString);
|
||||
|
||||
private:
|
||||
WantAgentHelper();
|
||||
virtual ~WantAgentHelper() = default;
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "local_pending_want.h"
|
||||
#include "multi_app_utils.h"
|
||||
#include "want_params_wrapper.h"
|
||||
#include "want_params_wrapper_json.h"
|
||||
#include "pending_want.h"
|
||||
#include "permission_verification.h"
|
||||
#include "want_agent_client.h"
|
||||
@@ -574,6 +575,129 @@ std::shared_ptr<WantAgent> WantAgentHelper::FromString(const std::string &jsonSt
|
||||
return GetWantAgent(info, userId, uid);
|
||||
}
|
||||
|
||||
std::string WantAgentHelper::ToStringWithEnvelope(const std::shared_ptr<WantAgent> &agent)
|
||||
{
|
||||
if (agent == nullptr) {
|
||||
TAG_LOGE(AAFwkTag::WANTAGENT, "invalid param");
|
||||
return "";
|
||||
}
|
||||
|
||||
std::shared_ptr<PendingWant> pendingWant = agent->GetPendingWant();
|
||||
if (pendingWant == nullptr) {
|
||||
TAG_LOGE(AAFwkTag::WANTAGENT, "invalid param");
|
||||
return "";
|
||||
}
|
||||
|
||||
std::shared_ptr<WantSenderInfo> info = pendingWant->GetWantSenderInfo(pendingWant->GetTarget());
|
||||
if (info == nullptr) {
|
||||
TAG_LOGE(AAFwkTag::WANTAGENT, "invalid param");
|
||||
return "";
|
||||
}
|
||||
nlohmann::json jsonObject;
|
||||
jsonObject["requestCode"] = (*info.get()).requestCode;
|
||||
jsonObject["operationType"] = (*info.get()).type;
|
||||
jsonObject["flags"] = (*info.get()).flags;
|
||||
jsonObject["userId"] = (*info.get()).userId;
|
||||
jsonObject["appIndex"] = (*info.get()).appIndex;
|
||||
|
||||
nlohmann::json wants = nlohmann::json::array();
|
||||
for (auto &wantInfo : (*info.get()).allWants) {
|
||||
wants.emplace_back(wantInfo.want.ToString());
|
||||
}
|
||||
jsonObject["wants"] = wants;
|
||||
|
||||
if ((*info.get()).allWants.size() > 0) {
|
||||
nlohmann::json paramsObj;
|
||||
std::string paramsString;
|
||||
if (!AAFwk::WantParamWrapperJson::Serialize((*info.get()).allWants[0].want.GetParams(), paramsString)) {
|
||||
TAG_LOGE(AAFwkTag::WANTAGENT, "serialize want params json failed");
|
||||
}
|
||||
paramsObj["extraInfoValue"] = paramsString;
|
||||
jsonObject["extraInfo"] = paramsObj;
|
||||
}
|
||||
|
||||
return jsonObject.dump();
|
||||
}
|
||||
|
||||
std::shared_ptr<WantAgent> WantAgentHelper::FromStringWithEnvelope(
|
||||
const std::string &jsonString, int32_t uid)
|
||||
{
|
||||
if (jsonString.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
nlohmann::json jsonObject = nlohmann::json::parse(jsonString, nullptr, false);
|
||||
if (jsonObject.is_discarded()) {
|
||||
TAG_LOGE(AAFwkTag::WANTAGENT, "Failed to parse json string");
|
||||
return nullptr;
|
||||
}
|
||||
int requestCode = -1;
|
||||
if (jsonObject.contains("requestCode") && jsonObject["requestCode"].is_number_integer()) {
|
||||
requestCode = jsonObject.at("requestCode").get<int>();
|
||||
}
|
||||
|
||||
int userId = -1;
|
||||
if (jsonObject.contains("userId") && jsonObject["userId"].is_number_integer()) {
|
||||
userId = jsonObject.at("userId").get<int>();
|
||||
}
|
||||
|
||||
WantAgentConstant::OperationType operationType = WantAgentConstant::OperationType::UNKNOWN_TYPE;
|
||||
if (jsonObject.contains("operationType") && jsonObject["operationType"].is_number_integer()) {
|
||||
operationType = static_cast<WantAgentConstant::OperationType>(jsonObject.at("operationType").get<int>());
|
||||
}
|
||||
|
||||
std::vector<WantAgentConstant::Flags> flagsVec = ParseFlags(jsonObject);
|
||||
std::vector<std::shared_ptr<AAFwk::Want>> wants = {};
|
||||
if (jsonObject.contains("wants") && jsonObject["wants"].is_array()) {
|
||||
for (auto &wantObj : jsonObject.at("wants")) {
|
||||
if (wantObj.is_string()) {
|
||||
auto wantString = wantObj.get<std::string>();
|
||||
wants.emplace_back(std::make_shared<AAFwk::Want>(*Want::FromString(wantString)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<AAFwk::WantParams> extraInfo = nullptr;
|
||||
if (jsonObject.contains("extraInfo") && jsonObject["extraInfo"].is_object()) {
|
||||
auto extraInfoObj = jsonObject.at("extraInfo");
|
||||
if (extraInfoObj.contains("extraInfoValue") && extraInfoObj["extraInfoValue"].is_string()) {
|
||||
AAFwk::WantParams params;
|
||||
if (!AAFwk::WantParamWrapperJson::Parse(extraInfoObj.at("extraInfoValue").get<std::string>(), params)) {
|
||||
TAG_LOGE(AAFwkTag::WANTAGENT, "parse want params json failed");
|
||||
}
|
||||
extraInfo = std::make_shared<AAFwk::WantParams>(params);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t appIndex = 0;
|
||||
if (jsonObject.contains("appIndex") && jsonObject["appIndex"].is_number_integer()) {
|
||||
appIndex = jsonObject.at("appIndex").get<int>();
|
||||
}
|
||||
|
||||
WantAgentInfo info(requestCode, appIndex, operationType, flagsVec, wants, extraInfo);
|
||||
return GetWantAgent(info, userId, uid);
|
||||
}
|
||||
|
||||
bool WantAgentHelper::HasWantParamsEnvelope(const std::string &jsonString)
|
||||
{
|
||||
if (jsonString.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nlohmann::json jsonObject = nlohmann::json::parse(jsonString, nullptr, false);
|
||||
if (jsonObject.is_discarded() || !jsonObject.is_object()) {
|
||||
return false;
|
||||
}
|
||||
if (!jsonObject.contains("extraInfo") || !jsonObject["extraInfo"].is_object()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto &extraInfoObj = jsonObject["extraInfo"];
|
||||
if (!extraInfoObj.contains("extraInfoValue") || !extraInfoObj["extraInfoValue"].is_string()) {
|
||||
return false;
|
||||
}
|
||||
return AAFwk::WantParamWrapperJson::HasEnvelope(extraInfoObj["extraInfoValue"].get<std::string>());
|
||||
}
|
||||
|
||||
std::vector<WantAgentConstant::Flags> WantAgentHelper::ParseFlags(nlohmann::json jsonObject)
|
||||
{
|
||||
int flags = -1;
|
||||
|
||||
@@ -1533,4 +1533,152 @@ HWTEST_F(WantAgentHelperTest, GetWantFromProxy_0100, TestSize.Level1)
|
||||
auto want = WantAgentHelper::GetWantFromProxy(wantAgent);
|
||||
EXPECT_EQ(want, nullptr);
|
||||
}
|
||||
|
||||
/*
|
||||
* @tc.number : WantAgentHelper_6700
|
||||
* @tc.name : WantAgentHelper ToStringWithEnvelope
|
||||
* @tc.desc : Test ToStringWithEnvelope uses WantParamWrapperJson without changing ToString format.
|
||||
*/
|
||||
HWTEST_F(WantAgentHelperTest, WantAgentHelper_6700, Function | MediumTest | Level1)
|
||||
{
|
||||
std::shared_ptr<Want> want = std::make_shared<Want>();
|
||||
ElementName element("device", "bundleName", "abilityNameToJson");
|
||||
want->SetElement(element);
|
||||
WantAgentInfo wantAgentInfo;
|
||||
wantAgentInfo.wants_.emplace_back(want);
|
||||
wantAgentInfo.operationType_ = WantAgentConstant::OperationType::START_ABILITY;
|
||||
wantAgentInfo.requestCode_ = 10;
|
||||
std::shared_ptr<WantParams> wParams = std::make_shared<WantParams>();
|
||||
wParams->SetParam("key", Boolean::Box(true));
|
||||
wantAgentInfo.extraInfo_ = wParams;
|
||||
auto wantAgent = WantAgentHelper::GetWantAgent(wantAgentInfo);
|
||||
ASSERT_NE(wantAgent, nullptr);
|
||||
|
||||
auto legacyString = WantAgentHelper::ToString(wantAgent);
|
||||
auto jsonString = WantAgentHelper::ToStringWithEnvelope(wantAgent);
|
||||
ASSERT_FALSE(legacyString.empty());
|
||||
ASSERT_FALSE(jsonString.empty());
|
||||
|
||||
auto legacyObject = nlohmann::json::parse(legacyString, nullptr, false);
|
||||
auto jsonObject = nlohmann::json::parse(jsonString, nullptr, false);
|
||||
ASSERT_FALSE(legacyObject.is_discarded());
|
||||
ASSERT_FALSE(jsonObject.is_discarded());
|
||||
auto legacyExtraInfo = legacyObject.at("extraInfo").at("extraInfoValue").get<std::string>();
|
||||
auto jsonExtraInfo = jsonObject.at("extraInfo").at("extraInfoValue").get<std::string>();
|
||||
EXPECT_EQ(legacyExtraInfo.find("ohos.want.paramsStringEnvelope"), std::string::npos);
|
||||
EXPECT_NE(jsonExtraInfo.find("ohos.want.paramsStringEnvelope"), std::string::npos);
|
||||
EXPECT_FALSE(WantAgentHelper::HasWantParamsEnvelope(legacyString));
|
||||
EXPECT_TRUE(WantAgentHelper::HasWantParamsEnvelope(jsonString));
|
||||
}
|
||||
|
||||
/*
|
||||
* @tc.number : WantAgentHelper_6710
|
||||
* @tc.name : WantAgentHelper FromStringWithEnvelope
|
||||
* @tc.desc : Test FromStringWithEnvelope restores WantAgent from WantParamWrapperJson extraInfo.
|
||||
*/
|
||||
HWTEST_F(WantAgentHelperTest, WantAgentHelper_6710, Function | MediumTest | Level1)
|
||||
{
|
||||
std::shared_ptr<Want> want = std::make_shared<Want>();
|
||||
ElementName element("device", "bundleName", "abilityNameFromJson");
|
||||
want->SetElement(element);
|
||||
WantAgentInfo wantAgentInfo;
|
||||
wantAgentInfo.wants_.emplace_back(want);
|
||||
wantAgentInfo.operationType_ = WantAgentConstant::OperationType::START_ABILITY;
|
||||
wantAgentInfo.requestCode_ = 10;
|
||||
std::shared_ptr<WantParams> wParams = std::make_shared<WantParams>();
|
||||
wParams->SetParam("key", Boolean::Box(true));
|
||||
wantAgentInfo.extraInfo_ = wParams;
|
||||
auto wantAgent = WantAgentHelper::GetWantAgent(wantAgentInfo);
|
||||
ASSERT_NE(wantAgent, nullptr);
|
||||
|
||||
auto jsonString = WantAgentHelper::ToStringWithEnvelope(wantAgent);
|
||||
auto restoredWantAgent = WantAgentHelper::FromStringWithEnvelope(jsonString);
|
||||
ASSERT_NE(restoredWantAgent, nullptr);
|
||||
|
||||
auto restoredWant = WantAgentHelper::GetWant(restoredWantAgent);
|
||||
ASSERT_NE(restoredWant, nullptr);
|
||||
auto value = restoredWant->GetParams().GetParam("key");
|
||||
auto boolValue = IBoolean::Query(value);
|
||||
ASSERT_NE(boolValue, nullptr);
|
||||
EXPECT_TRUE(Boolean::Unbox(boolValue));
|
||||
}
|
||||
|
||||
/*
|
||||
* @tc.number : WantAgentHelper_6720
|
||||
* @tc.name : WantAgentHelper ToStringWithEnvelope invalid input
|
||||
* @tc.desc : Test ToStringWithEnvelope invalid agent branches.
|
||||
*/
|
||||
HWTEST_F(WantAgentHelperTest, WantAgentHelper_6720, Function | MediumTest | Level1)
|
||||
{
|
||||
EXPECT_TRUE(WantAgentHelper::ToStringWithEnvelope(nullptr).empty());
|
||||
|
||||
auto wantAgentWithoutPendingWant = std::make_shared<WantAgent>(std::shared_ptr<PendingWant>(nullptr));
|
||||
EXPECT_TRUE(WantAgentHelper::ToStringWithEnvelope(wantAgentWithoutPendingWant).empty());
|
||||
|
||||
auto pendingWantWithoutTarget = std::make_shared<PendingWant>(sptr<IWantSender>(nullptr));
|
||||
auto wantAgentWithoutInfo = std::make_shared<WantAgent>(pendingWantWithoutTarget);
|
||||
EXPECT_TRUE(WantAgentHelper::ToStringWithEnvelope(wantAgentWithoutInfo).empty());
|
||||
}
|
||||
|
||||
/*
|
||||
* @tc.number : WantAgentHelper_6730
|
||||
* @tc.name : WantAgentHelper FromStringWithEnvelope invalid input
|
||||
* @tc.desc : Test FromStringWithEnvelope invalid string and malformed field branches.
|
||||
*/
|
||||
HWTEST_F(WantAgentHelperTest, WantAgentHelper_6730, Function | MediumTest | Level1)
|
||||
{
|
||||
EXPECT_EQ(WantAgentHelper::FromStringWithEnvelope(""), nullptr);
|
||||
EXPECT_EQ(WantAgentHelper::FromStringWithEnvelope("{"), nullptr);
|
||||
EXPECT_EQ(WantAgentHelper::FromStringWithEnvelope(R"({"requestCode":"bad","wants":[]})"),
|
||||
nullptr);
|
||||
EXPECT_EQ(WantAgentHelper::FromStringWithEnvelope(R"({"wants":[100]})"), nullptr);
|
||||
|
||||
Want want;
|
||||
ElementName element("device", "bundleName", "abilityNameFromJsonInvalid");
|
||||
want.SetElement(element);
|
||||
const auto originParamSize = want.GetParams().Size();
|
||||
nlohmann::json jsonObject;
|
||||
jsonObject["requestCode"] = 6730;
|
||||
jsonObject["operationType"] = static_cast<int32_t>(WantAgentConstant::OperationType::START_ABILITY);
|
||||
jsonObject["flags"] = static_cast<int32_t>(FLAG_UPDATE_CURRENT);
|
||||
jsonObject["userId"] = -1;
|
||||
jsonObject["appIndex"] = "bad";
|
||||
jsonObject["wants"] = nlohmann::json::array({ want.ToString() });
|
||||
jsonObject["extraInfo"] = { { "extraInfoValue", "invalid want params json" } };
|
||||
|
||||
auto wantAgent = WantAgentHelper::FromStringWithEnvelope(jsonObject.dump());
|
||||
ASSERT_NE(wantAgent, nullptr);
|
||||
auto restoredWant = WantAgentHelper::GetWant(wantAgent);
|
||||
ASSERT_NE(restoredWant, nullptr);
|
||||
EXPECT_EQ(restoredWant->GetParams().Size(), originParamSize);
|
||||
|
||||
jsonObject["requestCode"] = 6731;
|
||||
jsonObject["extraInfo"] = "bad";
|
||||
EXPECT_NE(WantAgentHelper::FromStringWithEnvelope(jsonObject.dump()), nullptr);
|
||||
|
||||
jsonObject["requestCode"] = 6732;
|
||||
jsonObject["extraInfo"] = { { "extraInfoValue", 100 } };
|
||||
EXPECT_NE(WantAgentHelper::FromStringWithEnvelope(jsonObject.dump()), nullptr);
|
||||
}
|
||||
|
||||
/*
|
||||
* @tc.number : WantAgentHelper_6740
|
||||
* @tc.name : WantAgentHelper HasWantParamsEnvelope
|
||||
* @tc.desc : Test HasWantParamsEnvelope dispatches only when extraInfoValue uses WantParamWrapperJson envelope.
|
||||
*/
|
||||
HWTEST_F(WantAgentHelperTest, WantAgentHelper_6740, Function | MediumTest | Level1)
|
||||
{
|
||||
nlohmann::json jsonObject;
|
||||
jsonObject["extraInfo"] = { { "extraInfoValue", R"( {"ohos.want.paramsStringEnvelope":{}} )" } };
|
||||
EXPECT_TRUE(WantAgentHelper::HasWantParamsEnvelope(jsonObject.dump()));
|
||||
|
||||
jsonObject["extraInfo"] = { { "extraInfoValue", "legacy want params" } };
|
||||
EXPECT_FALSE(WantAgentHelper::HasWantParamsEnvelope(jsonObject.dump()));
|
||||
|
||||
EXPECT_FALSE(WantAgentHelper::HasWantParamsEnvelope(""));
|
||||
EXPECT_FALSE(WantAgentHelper::HasWantParamsEnvelope("{"));
|
||||
EXPECT_FALSE(WantAgentHelper::HasWantParamsEnvelope(R"({"extraInfo":"bad"})"));
|
||||
EXPECT_FALSE(WantAgentHelper::HasWantParamsEnvelope(R"({"extraInfo":{"extraInfoValue":100}})"));
|
||||
EXPECT_FALSE(WantAgentHelper::HasWantParamsEnvelope(R"({"wants":[]})"));
|
||||
}
|
||||
} // namespace OHOS::AbilityRuntime::WantAgent
|
||||
|
||||
Reference in New Issue
Block a user