1 /*
2  * Copyright (c) 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 "hiview_config_util.h"
17 
18 #include <algorithm>
19 
20 #include "file_util.h"
21 #include "hiview_logger.h"
22 #include "hiview_zip_util.h"
23 
24 namespace OHOS {
25 namespace HiviewDFX {
26 namespace HiViewConfigUtil {
27 namespace {
28 DEFINE_LOG_TAG("HiViewConfigUtil");
29 constexpr char CFG_VERSION_FILE_NAME[] = "hiview_config_version";
30 constexpr char LOCAL_CFG_PATH[] = "/system/etc/hiview/";
31 constexpr char CLOUD_CFG_PATH[] = "/data/system/hiview/";
32 constexpr char LOCAL_CFG_UNZIP_DIR[] = "unzip_configs/";
33 
GetConfigFilePath(const std::string & configFileName,bool isLocal)34 inline std::string GetConfigFilePath(const std::string& configFileName, bool isLocal)
35 {
36     if (isLocal) {
37         return LOCAL_CFG_PATH + configFileName;
38     }
39     return CLOUD_CFG_PATH + configFileName;
40 }
41 
GetConfigFilePathByVersion(const std::string & localVer,const std::string & cloudVer,const std::string & configFileName)42 inline std::string GetConfigFilePathByVersion(const std::string& localVer, const std::string& cloudVer,
43     const std::string& configFileName)
44 {
45     std::string cloudConfigFilePath = GetConfigFilePath(configFileName, false);
46     if ((cloudVer > localVer) && FileUtil::FileExists(cloudConfigFilePath)) {
47         return cloudConfigFilePath;
48     }
49     return GetConfigFilePath(configFileName, true);
50 }
51 
GetConfigVersion(bool isLocal)52 inline std::string GetConfigVersion(bool isLocal)
53 {
54     std::string versionFile = GetConfigFilePath(CFG_VERSION_FILE_NAME, isLocal);
55     std::string version;
56     (void)FileUtil::LoadStringFromFile(versionFile, version);
57     return version;
58 }
59 
CopyConfigVersionFile(const std::string & destConfigDir,bool isLocal)60 bool CopyConfigVersionFile(const std::string& destConfigDir, bool isLocal)
61 {
62     if (!FileUtil::FileExists(destConfigDir) && !FileUtil::ForceCreateDirectory(destConfigDir)) {
63         HIVIEW_LOGE("%{public}s isn't exist and failed to create it", destConfigDir.c_str());
64         return false;
65     }
66     std::string originVersionFile = GetConfigFilePath(CFG_VERSION_FILE_NAME, isLocal);
67     std::string destVersionFile = destConfigDir + CFG_VERSION_FILE_NAME;
68     if (FileUtil::CopyFile(originVersionFile, destVersionFile) != 0) {
69         HIVIEW_LOGE("failed to copy %{public}s to %{public}s", originVersionFile.c_str(), destVersionFile.c_str());
70         return false;
71     }
72     return true;
73 }
74 
GetUnZipConfigDir()75 inline std::string GetUnZipConfigDir()
76 {
77     return std::string(CLOUD_CFG_PATH) + LOCAL_CFG_UNZIP_DIR;
78 }
79 
UnZipConfigFile(const std::string & srcDir,const std::string & zipFileName,const std::string & destDir,const std::string & configFileName)80 bool UnZipConfigFile(const std::string& srcDir, const std::string& zipFileName, const std::string& destDir,
81     const std::string& configFileName)
82 {
83     if (!FileUtil::FileExists(destDir) && !FileUtil::ForceCreateDirectory(destDir)) {
84         HIVIEW_LOGE("%{public}s isn't exist and failed to create it", destDir.c_str());
85         return false;
86     }
87     std::string zipConfigFile = srcDir + zipFileName;
88     if (!FileUtil::FileExists(zipConfigFile)) {
89         HIVIEW_LOGW("%{public}s isn't exist", zipConfigFile.c_str());
90         std::string srcFile = srcDir + configFileName;
91         std::string destFile = destDir + configFileName;
92         if (FileUtil::CopyFile(srcFile, destFile) != 0) {
93             HIVIEW_LOGE("failed to copy %{public}s to %{public}s", srcFile.c_str(), destFile.c_str());
94             return false;
95         }
96         return true;
97     }
98     HiviewUnzipUnit unzipUnit(zipConfigFile, destDir);
99     if (!unzipUnit.UnzipFile()) {
100         HIVIEW_LOGE("failed to unzip %{public}s to %{public}s", zipConfigFile.c_str(), destDir.c_str());
101         return false;
102     }
103     return true;
104 }
105 }
106 
GetConfigFilePath(const std::string & configFileName)107 std::string GetConfigFilePath(const std::string& configFileName)
108 {
109     std::string localVer = GetConfigVersion(true);
110     std::string cloudVer = GetConfigVersion(false);
111     return GetConfigFilePathByVersion(localVer, cloudVer, configFileName);
112 }
113 
GetConfigFilePath(const std::string & configZipFileName,const std::string & configDir,const std::string & configFileName)114 std::string GetConfigFilePath(const std::string& configZipFileName, const std::string& configDir,
115     const std::string& configFileName)
116 {
117     std::string destConfigDir = FileUtil::IncludeTrailingPathDelimiter(GetUnZipConfigDir() + configDir);
118     std::string destVer;
119     (void)FileUtil::LoadStringFromFile(destConfigDir + CFG_VERSION_FILE_NAME, destVer);
120 
121     std::string localVer = GetConfigVersion(true);
122     std::string cloudVer = GetConfigVersion(false);
123     std::string destConfigFilePath = destConfigDir + configFileName;
124     HIVIEW_LOGI("versions:[%{public}s|%{public}s|%{public}s]", localVer.c_str(), cloudVer.c_str(), destVer.c_str());
125     // if dest version is newest, return dest config file path directly
126     if (!destVer.empty() && destVer >= std::max(cloudVer, localVer) && FileUtil::FileExists(destConfigFilePath)) {
127         return destConfigFilePath;
128     }
129     // do cloud update if cloud version is newer than local version
130     if ((cloudVer > localVer) &&
131         UnZipConfigFile(CLOUD_CFG_PATH, configZipFileName, destConfigDir, configFileName) &&
132         CopyConfigVersionFile(destConfigDir, false)) {
133         HIVIEW_LOGI("succeed to do cloud update for %{public}s", configFileName.c_str());
134         return destConfigFilePath;
135     }
136     // do local update if local version is newer than cloud version or cloud update is failed
137     if (UnZipConfigFile(LOCAL_CFG_PATH, configZipFileName, destConfigDir, configFileName) &&
138         CopyConfigVersionFile(destConfigDir, true)) {
139         HIVIEW_LOGI("succeed to do local update for %{public}s", configFileName.c_str());
140         return destConfigFilePath;
141     }
142     // return file path directly if dest config file exist
143     if (FileUtil::FileExists(destConfigFilePath)) {
144         return destConfigFilePath;
145     }
146     return GetConfigFilePathByVersion(localVer, cloudVer, configFileName);
147 }
148 } // namespace ConfigUtil
149 } // namespace HiviewDFX
150 } // namespace OHOS
151