* Copyright (c) 2023 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 "push_callback_stub.h"
#include "ans_log_wrapper.h"
#include "event_handler.h"
#include "ipc_types.h"
#include "message_parcel.h"
#include "push_callback_proxy.h"
#include "ans_inner_errors.h"
#include "ans_service_errors.h"
#include "nlohmann/json.hpp"
using namespace OHOS::AppExecFwk;
namespace OHOS {
namespace Notification {
PushCallBackStub::PushCallBackStub() {}
PushCallBackStub::~PushCallBackStub() {}
enum PushCheckErrCode : int32_t {
SUCCESS = 0,
FIXED_PARAMETER_INVALID = 1,
NETWORK_UNREACHABLE = 2,
SPECIFIED_NOTIFICATIONS_FAILED = 3,
SYSTEM_ERROR = 4,
OPTIONAL_PARAMETER_INVALID = 5,
PUSH_CHECK_WEAK_NETWORK = 6,
};
constexpr int32_t MAX_LIVEVIEW_CONFIG_SIZE = 60;
ErrCode PushCallBackStub::ConvertPushCheckCodeToErrCode(int32_t pushCheckCode)
{
ErrCode errCode;
PushCheckErrCode checkCode = static_cast<PushCheckErrCode>(pushCheckCode);
switch (checkCode) {
case PushCheckErrCode::SUCCESS:
errCode = ERR_OK;
break;
case PushCheckErrCode::FIXED_PARAMETER_INVALID:
errCode = ERR_ANS_INNER_TASK_ERR;
break;
case PushCheckErrCode::NETWORK_UNREACHABLE:
errCode = ERR_ANS_INNER_PUSH_CHECK_NETWORK_UNREACHABLE;
break;
case PushCheckErrCode::SPECIFIED_NOTIFICATIONS_FAILED:
errCode = ERR_ANS_INNER_PUSH_CHECK_FAILED;
break;
case PushCheckErrCode::SYSTEM_ERROR:
errCode = ERR_ANS_INNER_TASK_ERR;
break;
case PushCheckErrCode::OPTIONAL_PARAMETER_INVALID:
errCode = ERR_ANS_INNER_PUSH_CHECK_EXTRAINFO_INVALID;
break;
case PushCheckErrCode::PUSH_CHECK_WEAK_NETWORK:
errCode = ERR_ANS_INNER_CHECK_WEAK_NETWORK;
break;
default:
errCode = ERR_ANS_INNER_PUSH_CHECK_FAILED;
break;
}
return errCode;
}
int PushCallBackStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option)
{
ANS_LOGD("called");
if (data.ReadInterfaceToken() != GetDescriptor()) {
ANS_LOGE("local descriptor is not equal to remote");
return ERR_INVALID_STATE;
}
switch (code) {
case static_cast<uint32_t>(NotificationInterfaceCode::ON_CHECK_NOTIFICATION): {
auto notificationData = data.ReadString();
int32_t checkResult = ERR_ANS_INNER_TASK_ERR;
std::shared_ptr<PushCallBackParam> pushCallBackParam = std::make_shared<PushCallBackParam>();
int32_t result = this->OnCheckNotification(notificationData, pushCallBackParam);
checkResult = ConvertPushCheckCodeToErrCode(result);
ANS_LOGI("Push check result:%{public}d %{public}d,eventControl:%{public}s",
result, checkResult, pushCallBackParam->eventControl.c_str());
if (!reply.WriteInt32(checkResult)) {
ANS_LOGE("Failed to write reply ");
return ERR_INVALID_REPLY;
}
if (!reply.WriteString(pushCallBackParam->eventControl)) {
ANS_LOGE("Failed to write reply ");
return ERR_INVALID_REPLY;
}
return NO_ERROR;
}
case static_cast<uint32_t>(NotificationInterfaceCode::ON_CHECK_LIVEVIEW): {
std::string requestId = data.ReadString();
auto vsize = data.ReadUint64();
vsize = (vsize < MAX_LIVEVIEW_CONFIG_SIZE) ? vsize : MAX_LIVEVIEW_CONFIG_SIZE;
std::vector<std::string> bundlesName;
for (uint64_t it = 0; it < vsize; ++it) {
std::string bundle = data.ReadString();
bundlesName.emplace_back(bundle);
}
int32_t checkResult = this->OnCheckLiveView(requestId, bundlesName);
ANS_LOGI("Push check liveview: %{public}zu %{public}d.", bundlesName.size(), checkResult);
if (!reply.WriteInt32(checkResult)) {
ANS_LOGE("Failed to write reply ");
return ERR_INVALID_REPLY;
}
return NO_ERROR;
}
default: {
return IPCObjectStub::OnRemoteRequest(code, data, reply, option);
}
}
}
int32_t PushCallBackProxy::OnCheckNotification(
const std::string ¬ificationData, const std::shared_ptr<PushCallBackParam> &pushCallBackParam)
{
MessageParcel data;
MessageParcel reply;
MessageOption option;
if (!data.WriteInterfaceToken(PushCallBackProxy::GetDescriptor())) {
ANS_LOGE("Write interface token failed.");
return false;
}
if (!data.WriteString(notificationData)) {
ANS_LOGE("Connect done element error.");
return false;
}
auto remote = Remote();
if (remote == nullptr) {
ANS_LOGE("null remote");
return false;
}
int error = remote->SendRequest(static_cast<uint32_t>(NotificationInterfaceCode::ON_CHECK_NOTIFICATION),
data, reply, option);
if (error != NO_ERROR) {
ANS_LOGE("error: %{public}d", error);
return false;
}
int result = reply.ReadInt32();
std::string eventControl;
if (reply.ReadString(eventControl)) {
HandleEventControl(eventControl, pushCallBackParam);
}
return result;
}
int32_t PushCallBackProxy::OnCheckLiveView(const std::string& requestId, const std::vector<std::string>& bundles)
{
MessageParcel data;
MessageParcel reply;
MessageOption option;
if (!data.WriteInterfaceToken(PushCallBackProxy::GetDescriptor())) {
ANS_LOGE("Write interface token failed.");
return ERROR_IPC_ERROR;
}
if (!data.WriteString(requestId)) {
ANS_LOGE("Connect done element error.");
return ERROR_IPC_ERROR;
}
if (!data.WriteUint64(bundles.size())) {
ANS_LOGE("Failed to write the size of bundles");
return ERROR_IPC_ERROR;
}
for (auto item : bundles) {
if (!data.WriteString(item)) {
ANS_LOGE("Failed to write bundle name");
return ERROR_IPC_ERROR;
}
}
auto remote = Remote();
if (remote == nullptr) {
ANS_LOGE("null remote");
return ERROR_IPC_ERROR;
}
int error = remote->SendRequest(static_cast<uint32_t>(NotificationInterfaceCode::ON_CHECK_LIVEVIEW),
data, reply, option);
if (error != NO_ERROR) {
ANS_LOGE("error: %{public}d", error);
return ERROR_IPC_ERROR;
}
int result = reply.ReadInt32();
return result;
}
void PushCallBackProxy::HandleEventControl(
std::string eventControl, const std::shared_ptr<PushCallBackParam> &pushCallBackParam)
{
if (pushCallBackParam == nullptr) {
ANS_LOGE("null pushCallBackParam");
return;
}
std::string event = pushCallBackParam->event;
ANS_LOGI("eventControl:%{public}s,event:%{public}s", eventControl.c_str(), event.c_str());
if (eventControl.empty() || !nlohmann::json::accept(eventControl)) {
return;
}
auto jsonObject = nlohmann::json::parse(eventControl);
if (jsonObject.is_null() || !jsonObject.is_object()) {
ANS_LOGE("jsonObject is not right");
return;
}
std::string key = event;
if (event.empty() || jsonObject.find(event) == jsonObject.cend()) {
ANS_LOGW("Event is empty or not found, fallback to ALL");
if (jsonObject.find("ALL") == jsonObject.cend()) {
ANS_LOGW("ALL has not eventControl");
return;
}
key = "ALL";
}
pushCallBackParam->eventControl = jsonObject.at(key).dump(-1, ' ',
false, nlohmann::json::error_handler_t::replace);
}
}
}