1 /*
2 * Copyright (c) 2023 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 "ipc/cloud_daemon.h"
17
18 #include <exception>
19 #include <stdexcept>
20 #include <thread>
21 #include <malloc.h>
22 #include <sys/stat.h>
23 #include <sys/utsname.h>
24
25 #include "cloud_file_fault_event.h"
26 #include "dfs_error.h"
27 #include "fuse_manager/fuse_manager.h"
28 #include "iremote_object.h"
29 #include "parameters.h"
30 #include "plugin_loader.h"
31 #include "system_ability_definition.h"
32 #include "utils_directory.h"
33 #include "utils_log.h"
34 #ifdef HICOLLIE_ENABLE
35 #include "xcollie_helper.h"
36 #endif
37
38 namespace OHOS {
39 namespace FileManagement {
40 namespace CloudFile {
41 using namespace std;
42 using namespace CloudDisk;
43
44 namespace {
45 static const string LOCAL_PATH_DATA_SERVICE_EL2 = "/data/service/el2/";
46 static const string LOCAL_PATH_HMDFS_DENTRY_CACHE = "/hmdfs/cache/account_cache/dentry_cache/";
47 static const string LOCAL_PATH_HMDFS_CACHE_CLOUD = "/hmdfs/cache/account_cache/dentry_cache/cloud";
48 static const int32_t STAT_MODE_DIR = 0771;
49 static const int32_t STAT_MODE_DIR_DENTRY_CACHE = 02771;
50 static const int32_t OID_DFS = 1009;
51 }
52 REGISTER_SYSTEM_ABILITY_BY_ID(CloudDaemon, FILEMANAGEMENT_CLOUD_DAEMON_SERVICE_SA_ID, true);
53
CloudDaemon(int32_t saID,bool runOnCreate)54 CloudDaemon::CloudDaemon(int32_t saID, bool runOnCreate) : SystemAbility(saID, runOnCreate)
55 {
56 accountStatusListener_ = make_shared<AccountStatusListener>();
57 }
58
PublishSA()59 void CloudDaemon::PublishSA()
60 {
61 LOGI("Begin to init");
62 if (!registerToService_) {
63 bool ret = SystemAbility::Publish(this);
64 if (!ret) {
65 throw runtime_error("Failed to publish the daemon");
66 }
67 registerToService_ = true;
68 }
69 LOGI("Init finished successfully");
70 }
71
CheckDeviceInLinux()72 static bool CheckDeviceInLinux()
73 {
74 struct utsname uts;
75 if (uname(&uts) == -1) {
76 LOGE("uname get failed.");
77 return false;
78 }
79 if (strcmp(uts.sysname, "Linux") == 0) {
80 LOGI("uname system is linux.");
81 return true;
82 }
83 return false;
84 }
85
ModSysParam()86 static void ModSysParam()
87 {
88 if (CheckDeviceInLinux()) {
89 const string photos = "persist.kernel.bundle_name.photos";
90 const string clouddrive = "persist.kernel.bundle_name.clouddrive";
91 system::SetParameter(photos, "");
92 system::SetParameter(clouddrive, "");
93 }
94 }
95
OnStart()96 void CloudDaemon::OnStart()
97 {
98 LOGI("Begin to start service");
99 if (state_ == ServiceRunningState::STATE_RUNNING) {
100 LOGI("Daemon has already started");
101 return;
102 }
103
104 try {
105 PublishSA();
106 AddSystemAbilityListener(COMMON_EVENT_SERVICE_ID);
107 mode_t mode = 002;
108 umask(mode);
109 ModSysParam();
110 } catch (const exception &e) {
111 LOGE("%{public}s", e.what());
112 }
113
114 state_ = ServiceRunningState::STATE_RUNNING;
115 /* load cloud file ext plugin */
116 CloudFile::PluginLoader::GetInstance().LoadCloudKitPlugin();
117 LOGI("Start service successfully");
118 }
119
HandleStartMove(int32_t userId)120 void HandleStartMove(int32_t userId)
121 {
122 const string moveFile = "persist.kernel.move.finish";
123 system::SetParameter(moveFile, "false");
124 const std::string filemanagerKey = "persist.kernel.bundle_name.filemanager";
125 string subList[] = {"com.ohos.photos", system::GetParameter(filemanagerKey, "")};
126 string srcBase = "/data/service/el1/public/cloudfile/" + to_string(userId);
127 string dstBase = "/data/service/el2/" + to_string(userId) + "/hmdfs/cloudfile_manager";
128 string removePath = srcBase + "/" + subList[1] + "/backup";
129 bool ret = Storage::DistributedFile::Utils::ForceRemoveDirectoryDeepFirst(removePath);
130 if (!ret) {
131 LOGE("remove failed path: %{public}s", GetAnonyString(removePath).c_str());
132 }
133 const auto copyOptions = filesystem::copy_options::overwrite_existing | filesystem::copy_options::recursive;
134 for (auto sub : subList) {
135 string srcPath = srcBase + '/' + sub;
136 string dstPath = dstBase + '/' + sub;
137 if (access(srcPath.c_str(), F_OK) != 0) {
138 LOGI("srcPath %{public}s not found", GetAnonyString(srcPath).c_str());
139 continue;
140 }
141 LOGI("Begin to move path: %{public}s", GetAnonyString(srcPath).c_str());
142 error_code errCode;
143 filesystem::copy(srcPath, dstPath, copyOptions, errCode);
144 if (errCode.value() != 0) {
145 LOGE("copy failed path: %{public}s, errCode: %{public}d",
146 GetAnonyString(srcPath).c_str(), errCode.value());
147 }
148 LOGI("End move path: %{public}s", GetAnonyString(srcPath).c_str());
149 bool ret = Storage::DistributedFile::Utils::ForceRemoveDirectoryDeepFirst(srcPath);
150 if (!ret) {
151 LOGE("remove failed path: %{public}s", GetAnonyString(srcPath).c_str());
152 }
153 }
154 system::SetParameter(moveFile, "true");
155 }
156
OnStop()157 void CloudDaemon::OnStop()
158 {
159 LOGI("Begin to stop");
160 state_ = ServiceRunningState::STATE_NOT_START;
161 registerToService_ = false;
162 LOGI("Stop finished successfully");
163 }
164
OnAddSystemAbility(int32_t systemAbilityId,const std::string & deviceId)165 void CloudDaemon::OnAddSystemAbility(int32_t systemAbilityId, const std::string &deviceId)
166 {
167 LOGI("OnAddSystemAbility systemAbilityId:%{public}d added!", systemAbilityId);
168 accountStatusListener_->Start();
169 }
170
ExecuteStartFuse(int32_t userId,int32_t devFd,const std::string & path)171 void CloudDaemon::ExecuteStartFuse(int32_t userId, int32_t devFd, const std::string& path)
172 {
173 std::thread([=]() {
174 int32_t ret = FuseManager::GetInstance().StartFuse(userId, devFd, path);
175 CLOUD_FILE_FAULT_REPORT(CloudFileFaultInfo{"", CloudFile::FaultOperation::SESSION,
176 CloudFile::FaultType::FILE, ret, "start fuse, ret = " + std::to_string(ret)});
177 }).detach();
178 }
179
StartFuse(int32_t userId,int32_t devFd,const string & path)180 int32_t CloudDaemon::StartFuse(int32_t userId, int32_t devFd, const string &path)
181 {
182 #ifdef HICOLLIE_ENABLE
183 const int32_t TIMEOUT_S = 2;
184 int32_t xcollieId = XCollieHelper::SetTimer("CloudFileDaemon_StartFuse", TIMEOUT_S, nullptr, nullptr, true);
185 #endif
186 LOGI("Start Fuse");
187 ExecuteStartFuse(userId, devFd, path);
188
189 string dentryPath = LOCAL_PATH_DATA_SERVICE_EL2 + to_string(userId) + LOCAL_PATH_HMDFS_CACHE_CLOUD;
190 if (access(dentryPath.c_str(), F_OK) != 0) {
191 string cachePath = LOCAL_PATH_DATA_SERVICE_EL2 + to_string(userId) + LOCAL_PATH_HMDFS_DENTRY_CACHE;
192 if (mkdir(cachePath.c_str(), STAT_MODE_DIR) != 0 && errno != EEXIST) {
193 #ifdef HICOLLIE_ENABLE
194 XCollieHelper::CancelTimer(xcollieId);
195 #endif
196 CLOUD_FILE_FAULT_REPORT(CloudFileFaultInfo{"", CloudFile::FaultOperation::SESSION,
197 CloudFile::FaultType::FILE, errno, "create accout_cache path error " + std::to_string(errno)});
198 return E_PATH;
199 }
200 if (chmod(cachePath.c_str(), STAT_MODE_DIR_DENTRY_CACHE) != 0) {
201 CLOUD_FILE_FAULT_REPORT(CloudFileFaultInfo{"", CloudFile::FaultOperation::SESSION,
202 CloudFile::FaultType::FILE, errno, "chmod cachepath error " + std::to_string(errno)});
203 }
204 if (chown(cachePath.c_str(), OID_DFS, OID_DFS) != 0) {
205 CLOUD_FILE_FAULT_REPORT(CloudFileFaultInfo{"", CloudFile::FaultOperation::SESSION,
206 CloudFile::FaultType::FILE, errno, "chown cachepath error " + std::to_string(errno)});
207 }
208 if (mkdir(dentryPath.c_str(), STAT_MODE_DIR) != 0 && errno != EEXIST) {
209 #ifdef HICOLLIE_ENABLE
210 XCollieHelper::CancelTimer(xcollieId);
211 #endif
212 CLOUD_FILE_FAULT_REPORT(CloudFileFaultInfo{"", CloudFile::FaultOperation::SESSION,
213 CloudFile::FaultType::FILE, errno, "create dentrypath " + std::to_string(errno)});
214 return E_PATH;
215 }
216 if (chown(dentryPath.c_str(), OID_DFS, OID_DFS) != 0) {
217 CLOUD_FILE_FAULT_REPORT(CloudFileFaultInfo{"", CloudFile::FaultOperation::SESSION,
218 CloudFile::FaultType::FILE, errno, "chown cachepath error " + std::to_string(errno)});
219 }
220 }
221 if (path.find("cloud_fuse") != string::npos) {
222 std::thread([userId]() {
223 HandleStartMove(userId);
224 }).detach();
225 }
226 #ifdef HICOLLIE_ENABLE
227 XCollieHelper::CancelTimer(xcollieId);
228 #endif
229 return E_OK;
230 }
231 } // namespace CloudFile
232 } // namespace FileManagement
233 } // namespace OHOS
234