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