• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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