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
30 namespace OHOS {
31 namespace Notification {
32
33 const int ANS_CLONE_ERROR = -1;
34 constexpr const char *CLONE_ITEM_BUNDLE_INFO = "notificationBundle";
35 constexpr const char *CLONE_ITEM_DISTURB = "notificationDisturb";
36 constexpr const char *BACKUP_CONFIG_FILE_PATH = "/data/service/el1/public/notification/backup_config.conf";
37
GetInstance()38 NotificationCloneManager& NotificationCloneManager::GetInstance()
39 {
40 static NotificationCloneManager notificationCloneManager;
41 return notificationCloneManager;
42 }
43
OnBackup(MessageParcel & data,MessageParcel & reply)44 int32_t NotificationCloneManager::OnBackup(MessageParcel& data, MessageParcel& reply)
45 {
46 if (cloneTemplates.empty()) {
47 ANS_LOGI("Notification no need Backup.");
48 return ERR_OK;
49 }
50
51 nlohmann::json jsonObject;
52 for (auto iter = cloneTemplates.begin(); iter != cloneTemplates.end(); ++iter) {
53 nlohmann::json jsonItem;
54 auto cloneTemplate = iter->second;
55 if (cloneTemplate == nullptr) {
56 ANS_LOGW("Notification OnBackup %{public}s funtion is null.", iter->first.c_str());
57 continue;
58 }
59 if (iter->second->OnBackup(jsonItem) != ERR_OK) {
60 ANS_LOGW("Notification OnBackup %{public}s failed.", iter->first.c_str());
61 continue;
62 }
63 jsonObject[iter->first] = jsonItem;
64 }
65
66 if (SaveConfig(jsonObject.dump()) != ERR_OK) {
67 return ANS_CLONE_ERROR;
68 }
69
70 UniqueFd fd = UniqueFd(open(BACKUP_CONFIG_FILE_PATH, O_RDONLY));
71 if (fd.Get() < 0) {
72 ANS_LOGW("Notification open file failed.");
73 return ANS_CLONE_ERROR;
74 }
75
76 if (reply.WriteFileDescriptor(fd) == false) {
77 close(fd.Release());
78 ANS_LOGW("Notification write file descriptor failed!");
79 return ANS_CLONE_ERROR;
80 }
81
82 ANS_LOGI("Notification OnBackup end fd: %{public}d.", fd.Get());
83 close(fd.Release());
84 return ERR_OK;
85 }
86
OnRestore(MessageParcel & data,MessageParcel & reply)87 int32_t NotificationCloneManager::OnRestore(MessageParcel& data, MessageParcel& reply)
88 {
89 std::string storeMessage;
90 UniqueFd fd(data.ReadFileDescriptor());
91 if (LoadConfig(fd, storeMessage) != ERR_OK) {
92 close(fd.Release());
93 RemoveBackUpFile();
94 return ANS_CLONE_ERROR;
95 }
96
97 RemoveBackUpFile();
98 nlohmann::json jsonObject = nlohmann::json::parse(storeMessage, nullptr, false);
99 if (jsonObject.is_null() || !jsonObject.is_object()) {
100 ANS_LOGE("Invalid JSON object");
101 return ANS_CLONE_ERROR;
102 }
103 for (auto iter = cloneTemplates.begin(); iter != cloneTemplates.end(); ++iter) {
104 if (jsonObject.contains(iter->first) && iter->second != nullptr) {
105 iter->second->OnRestore(jsonObject.at(iter->first));
106 }
107 }
108 return ERR_OK;
109 }
110
NotificationCloneManager()111 NotificationCloneManager::NotificationCloneManager()
112 {
113 ANS_LOGI("Notification clone manager init.");
114 cloneTemplates.insert_or_assign(CLONE_ITEM_BUNDLE_INFO, NotificationCloneBundle::GetInstance());
115 cloneTemplates.insert_or_assign(CLONE_ITEM_DISTURB, NotificationCloneDisturb::GetInstance());
116 }
117
~NotificationCloneManager()118 NotificationCloneManager::~NotificationCloneManager()
119 {
120 ANS_LOGI("Notification clone manager destory.");
121 }
122
LoadConfig(UniqueFd & fd,std::string & config)123 ErrCode NotificationCloneManager::LoadConfig(UniqueFd &fd, std::string& config)
124 {
125 ANS_LOGI("Load notification config.");
126 struct stat statBuf;
127 if (fstat(fd.Get(), &statBuf) < 0) {
128 ANS_LOGW("LoadConfig fstat fd fail %{public}d.", fd.Get());
129 return ANS_CLONE_ERROR;
130 }
131 int destFd = open(BACKUP_CONFIG_FILE_PATH, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
132 if (destFd < 0) {
133 ANS_LOGW("LoadConfig open file fail.");
134 return ANS_CLONE_ERROR;
135 }
136 if (sendfile(destFd, fd.Get(), nullptr, statBuf.st_size) < 0) {
137 ANS_LOGW("LoadConfig fd sendfile(size: %{public}d) to destFd fail.", static_cast<int>(statBuf.st_size));
138 close(destFd);
139 return ANS_CLONE_ERROR;
140 }
141 close(destFd);
142 std::ifstream fs(BACKUP_CONFIG_FILE_PATH);
143 if (!fs.is_open()) {
144 ANS_LOGW("Loading config file%{public}s is_open() failed!", BACKUP_CONFIG_FILE_PATH);
145 return ANS_CLONE_ERROR;
146 }
147 config.clear();
148 std::string line;
149 while (std::getline(fs, line)) {
150 config.append(line);
151 }
152 fs.close();
153 return ERR_OK;
154 }
155
SaveConfig(const std::string & config)156 ErrCode NotificationCloneManager::SaveConfig(const std::string& config)
157 {
158 ANS_LOGD("Save config file %{public}s", config.c_str());
159 RemoveBackUpFile();
160 FILE* fp = fopen(BACKUP_CONFIG_FILE_PATH, "w");
161 if (!fp) {
162 ANS_LOGW("Save config file: %{public}s, fopen() failed!", BACKUP_CONFIG_FILE_PATH);
163 return ANS_CLONE_ERROR;
164 }
165
166 int ret = fwrite(config.c_str(), 1, config.length(), fp);
167 if (ret != (int)config.length()) {
168 ANS_LOGW("Save config file: %{public}s, fwrite %{public}d failed!", BACKUP_CONFIG_FILE_PATH, ret);
169 }
170 (void)fflush(fp);
171 (void)fsync(fileno(fp));
172 (void)fclose(fp);
173 ANS_LOGI("Save config file %{public}zu", config.size());
174 return ERR_OK;
175 }
176
RemoveBackUpFile()177 void NotificationCloneManager::RemoveBackUpFile()
178 {
179 remove(BACKUP_CONFIG_FILE_PATH);
180 }
181
OnUserSwitch(int32_t userId)182 void NotificationCloneManager::OnUserSwitch(int32_t userId)
183 {
184 for (auto iter = cloneTemplates.begin(); iter != cloneTemplates.end(); ++iter) {
185 iter->second->OnUserSwitch(userId);
186 }
187 }
188 }
189 }
190