1 /*
2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "notification_clone_manager.h"
17
18 #include <fcntl.h>
19 #include <unistd.h>
20 #include <fstream>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <sys/sendfile.h>
24
25 #include "ans_log_wrapper.h"
26 #include "nlohmann/json.hpp"
27 #include "notification_clone_disturb_service.h"
28 #include "notification_clone_bundle_service.h"
29 #include "notification_clone_util.h"
30
31 namespace OHOS {
32 namespace Notification {
33
34 const int ANS_CLONE_ERROR = -1;
35 constexpr const char *CLONE_ITEM_BUNDLE_INFO = "notificationBundle";
36 constexpr const char *CLONE_ITEM_DISTURB = "notificationDisturb";
37 constexpr const char *BACKUP_CONFIG_FILE_PATH = "/data/service/el1/public/notification/backup_config.conf";
38
GetInstance()39 NotificationCloneManager& NotificationCloneManager::GetInstance()
40 {
41 static NotificationCloneManager notificationCloneManager;
42 return notificationCloneManager;
43 }
44
SetBackUpReply()45 static std::string SetBackUpReply()
46 {
47 nlohmann::json reply;
48 nlohmann::json resultInfo = nlohmann::json::array();
49 nlohmann::json errorInfo;
50
51 errorInfo["type"] = "ErrorInfo";
52 errorInfo["errorCode"] = std::to_string(ERR_OK);
53 errorInfo["errorInfo"] = "";
54
55 resultInfo.emplace_back(errorInfo);
56 reply["resultInfo"] = resultInfo;
57
58 return reply.dump();
59 }
60
OnBackup(MessageParcel & data,MessageParcel & reply)61 int32_t NotificationCloneManager::OnBackup(MessageParcel& data, MessageParcel& reply)
62 {
63 if (cloneTemplates.empty()) {
64 ANS_LOGI("Notification no need Backup.");
65 return ERR_OK;
66 }
67
68 nlohmann::json jsonObject;
69 for (auto iter = cloneTemplates.begin(); iter != cloneTemplates.end(); ++iter) {
70 nlohmann::json jsonItem;
71 auto cloneTemplate = iter->second;
72 if (cloneTemplate == nullptr) {
73 ANS_LOGW("Notification OnBackup %{public}s funtion is null.", iter->first.c_str());
74 continue;
75 }
76 if (iter->second->OnBackup(jsonItem) != ERR_OK) {
77 ANS_LOGW("Notification OnBackup %{public}s failed.", iter->first.c_str());
78 continue;
79 }
80 jsonObject[iter->first] = jsonItem;
81 }
82
83 if (SaveConfig(jsonObject.dump()) != ERR_OK) {
84 return ANS_CLONE_ERROR;
85 }
86
87 UniqueFd fd = UniqueFd(open(BACKUP_CONFIG_FILE_PATH, O_RDONLY));
88 if (fd.Get() < 0) {
89 ANS_LOGW("Notification open file failed.");
90 return ANS_CLONE_ERROR;
91 }
92
93 if (reply.WriteFileDescriptor(fd) == false) {
94 close(fd.Release());
95 ANS_LOGW("Notification write file descriptor failed!");
96 return ANS_CLONE_ERROR;
97 }
98
99 ANS_LOGI("Notification OnBackup end fd: %{public}d.", fd.Get());
100 close(fd.Release());
101 return ERR_OK;
102 }
103
OnRestore(MessageParcel & data,MessageParcel & reply)104 int32_t NotificationCloneManager::OnRestore(MessageParcel& data, MessageParcel& reply)
105 {
106 reply.WriteString(SetBackUpReply());
107 std::string storeMessage;
108 UniqueFd fd(data.ReadFileDescriptor());
109 if (LoadConfig(fd, storeMessage) != ERR_OK) {
110 close(fd.Release());
111 RemoveBackUpFile();
112 return ANS_CLONE_ERROR;
113 }
114
115 RemoveBackUpFile();
116 if (storeMessage.empty() || !nlohmann::json::accept(storeMessage)) {
117 ANS_LOGE("Invalid JSON");
118 return ANS_CLONE_ERROR;
119 }
120 nlohmann::json jsonObject = nlohmann::json::parse(storeMessage, nullptr, false);
121 if (jsonObject.is_null() || !jsonObject.is_object()) {
122 ANS_LOGE("Invalid JSON object");
123 return ANS_CLONE_ERROR;
124 }
125 for (auto iter = cloneTemplates.begin(); iter != cloneTemplates.end(); ++iter) {
126 if (jsonObject.contains(iter->first) && iter->second != nullptr) {
127 iter->second->OnRestore(jsonObject.at(iter->first));
128 }
129 }
130 return ERR_OK;
131 }
132
NotificationCloneManager()133 NotificationCloneManager::NotificationCloneManager()
134 {
135 ANS_LOGI("Notification clone manager init.");
136 cloneTemplates.insert_or_assign(CLONE_ITEM_BUNDLE_INFO, NotificationCloneBundle::GetInstance());
137 cloneTemplates.insert_or_assign(CLONE_ITEM_DISTURB, NotificationCloneDisturb::GetInstance());
138 }
139
~NotificationCloneManager()140 NotificationCloneManager::~NotificationCloneManager()
141 {
142 ANS_LOGI("Notification clone manager destory.");
143 }
144
LoadConfig(UniqueFd & fd,std::string & config)145 ErrCode NotificationCloneManager::LoadConfig(UniqueFd &fd, std::string& config)
146 {
147 ANS_LOGI("Load notification config.");
148 struct stat statBuf;
149 if (fstat(fd.Get(), &statBuf) < 0) {
150 ANS_LOGW("LoadConfig fstat fd fail %{public}d.", fd.Get());
151 return ANS_CLONE_ERROR;
152 }
153 int destFd = open(BACKUP_CONFIG_FILE_PATH, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
154 if (destFd < 0) {
155 ANS_LOGW("LoadConfig open file fail.");
156 return ANS_CLONE_ERROR;
157 }
158 if (sendfile(destFd, fd.Get(), nullptr, statBuf.st_size) < 0) {
159 ANS_LOGW("LoadConfig fd sendfile(size: %{public}d) to destFd fail.", static_cast<int>(statBuf.st_size));
160 close(destFd);
161 return ANS_CLONE_ERROR;
162 }
163 close(destFd);
164 std::ifstream fs(BACKUP_CONFIG_FILE_PATH);
165 if (!fs.is_open()) {
166 ANS_LOGW("Loading config file%{public}s is_open() failed!", BACKUP_CONFIG_FILE_PATH);
167 return ANS_CLONE_ERROR;
168 }
169 config.clear();
170 std::string line;
171 while (std::getline(fs, line)) {
172 config.append(line);
173 }
174 fs.close();
175 return ERR_OK;
176 }
177
SaveConfig(const std::string & config)178 ErrCode NotificationCloneManager::SaveConfig(const std::string& config)
179 {
180 ANS_LOGD("Save config file %{public}s", config.c_str());
181 RemoveBackUpFile();
182 FILE* fp = fopen(BACKUP_CONFIG_FILE_PATH, "w");
183 if (!fp) {
184 ANS_LOGW("Save config file: %{public}s, fopen() failed!", BACKUP_CONFIG_FILE_PATH);
185 return ANS_CLONE_ERROR;
186 }
187
188 int ret = static_cast<int>(fwrite(config.c_str(), 1, config.length(), fp));
189 if (ret != (int)config.length()) {
190 ANS_LOGW("Save config file: %{public}s, fwrite %{public}d failed!", BACKUP_CONFIG_FILE_PATH, ret);
191 }
192 (void)fflush(fp);
193 (void)fsync(fileno(fp));
194 (void)fclose(fp);
195 ANS_LOGI("Save config file %{public}zu", config.size());
196 return ERR_OK;
197 }
198
RemoveBackUpFile()199 void NotificationCloneManager::RemoveBackUpFile()
200 {
201 remove(BACKUP_CONFIG_FILE_PATH);
202 }
203
OnUserSwitch(int32_t userId)204 void NotificationCloneManager::OnUserSwitch(int32_t userId)
205 {
206 for (auto iter = cloneTemplates.begin(); iter != cloneTemplates.end(); ++iter) {
207 if (iter->second != nullptr) {
208 iter->second->OnUserSwitch(userId);
209 }
210 }
211 }
212
OnRestoreStart(EventFwk::Want want)213 void NotificationCloneManager::OnRestoreStart(EventFwk::Want want)
214 {
215 int32_t appIndex = want.GetIntParam("index", -1);
216 std::string bundleName = want.GetStringParam("bundleName");
217 int32_t userId = NotificationCloneUtil::GetActiveUserId();
218 if (appIndex == -1 || bundleName.empty()) {
219 ANS_LOGW("Invalid restore data %{public}d %{public}d %{public}s",
220 appIndex, userId, bundleName.c_str());
221 return;
222 }
223 int32_t uid = NotificationCloneUtil::GetBundleUid(bundleName, userId, appIndex);
224 for (auto iter = cloneTemplates.begin(); iter != cloneTemplates.end(); ++iter) {
225 if (iter->second != nullptr) {
226 iter->second->OnRestoreStart(bundleName, appIndex, userId, uid);
227 }
228 }
229 }
230 }
231 }
232