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     if (storeMessage.empty() || !nlohmann::json::accept(storeMessage)) {
99         ANS_LOGE("Invalid JSON");
100         return ANS_CLONE_ERROR;
101     }
102     nlohmann::json jsonObject = nlohmann::json::parse(storeMessage, nullptr, false);
103     if (jsonObject.is_null() || !jsonObject.is_object()) {
104         ANS_LOGE("Invalid JSON object");
105         return ANS_CLONE_ERROR;
106     }
107     for (auto iter = cloneTemplates.begin(); iter != cloneTemplates.end(); ++iter) {
108         if (jsonObject.contains(iter->first) && iter->second != nullptr) {
109             iter->second->OnRestore(jsonObject.at(iter->first));
110         }
111     }
112     return ERR_OK;
113 }
114 
NotificationCloneManager()115 NotificationCloneManager::NotificationCloneManager()
116 {
117     ANS_LOGI("Notification clone manager init.");
118     cloneTemplates.insert_or_assign(CLONE_ITEM_BUNDLE_INFO, NotificationCloneBundle::GetInstance());
119     cloneTemplates.insert_or_assign(CLONE_ITEM_DISTURB, NotificationCloneDisturb::GetInstance());
120 }
121 
~NotificationCloneManager()122 NotificationCloneManager::~NotificationCloneManager()
123 {
124     ANS_LOGI("Notification clone manager destory.");
125 }
126 
LoadConfig(UniqueFd &fd, std::string& config)127 ErrCode NotificationCloneManager::LoadConfig(UniqueFd &fd, std::string& config)
128 {
129     ANS_LOGI("Load notification config.");
130     struct stat statBuf;
131     if (fstat(fd.Get(), &statBuf) < 0) {
132         ANS_LOGW("LoadConfig fstat fd fail %{public}d.", fd.Get());
133         return ANS_CLONE_ERROR;
134     }
135     int destFd = open(BACKUP_CONFIG_FILE_PATH, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
136     if (destFd < 0) {
137         ANS_LOGW("LoadConfig open file fail.");
138         return ANS_CLONE_ERROR;
139     }
140     if (sendfile(destFd, fd.Get(), nullptr, statBuf.st_size) < 0) {
141         ANS_LOGW("LoadConfig fd sendfile(size: %{public}d) to destFd fail.", static_cast<int>(statBuf.st_size));
142         close(destFd);
143         return ANS_CLONE_ERROR;
144     }
145     close(destFd);
146     std::ifstream fs(BACKUP_CONFIG_FILE_PATH);
147     if (!fs.is_open()) {
148         ANS_LOGW("Loading config file%{public}s is_open() failed!", BACKUP_CONFIG_FILE_PATH);
149         return ANS_CLONE_ERROR;
150     }
151     config.clear();
152     std::string line;
153     while (std::getline(fs, line)) {
154         config.append(line);
155     }
156     fs.close();
157     return ERR_OK;
158 }
159 
SaveConfig(const std::string& config)160 ErrCode NotificationCloneManager::SaveConfig(const std::string& config)
161 {
162     ANS_LOGD("Save config file %{public}s", config.c_str());
163     RemoveBackUpFile();
164     FILE* fp = fopen(BACKUP_CONFIG_FILE_PATH, "w");
165     if (!fp) {
166         ANS_LOGW("Save config file: %{public}s, fopen() failed!", BACKUP_CONFIG_FILE_PATH);
167         return ANS_CLONE_ERROR;
168     }
169 
170     int ret = static_cast<int>(fwrite(config.c_str(), 1, config.length(), fp));
171     if (ret != (int)config.length()) {
172         ANS_LOGW("Save config file: %{public}s, fwrite %{public}d failed!", BACKUP_CONFIG_FILE_PATH, ret);
173     }
174     (void)fflush(fp);
175     (void)fsync(fileno(fp));
176     (void)fclose(fp);
177     ANS_LOGI("Save config file %{public}zu", config.size());
178     return ERR_OK;
179 }
180 
RemoveBackUpFile()181 void NotificationCloneManager::RemoveBackUpFile()
182 {
183     remove(BACKUP_CONFIG_FILE_PATH);
184 }
185 
OnUserSwitch(int32_t userId)186 void NotificationCloneManager::OnUserSwitch(int32_t userId)
187 {
188     for (auto iter = cloneTemplates.begin(); iter != cloneTemplates.end(); ++iter) {
189         iter->second->OnUserSwitch(userId);
190     }
191 }
192 }
193 }
194