• 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 #include "first_use_dialog.h"
16 
17 #include <fcntl.h>
18 #include <fstream>
19 #include <sys/stat.h>
20 #include <sys/types.h>
21 #include <unistd.h>
22 #include "ability_manager_client.h"
23 #include "accesstoken_kit.h"
24 #include "sec_comp_err.h"
25 #include "sec_comp_log.h"
26 #include "want_params_wrapper.h"
27 #include "want.h"
28 
29 namespace OHOS {
30 namespace Security {
31 namespace SecurityComponent {
32 namespace {
33 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, SECURITY_DOMAIN_SECURITY_COMPONENT, "FirstUseDialog"};
34 static const std::string SEC_COMP_SRV_CFG_PATH = "/data/service/el1/public/security_component_service";
35 static const std::string FIRST_USE_RECORD_JSON = SEC_COMP_SRV_CFG_PATH + "/first_use_record.json";
36 static const std::string FIRST_USE_RECORD_TAG = "FirstUseRecord";
37 static const std::string TOKEN_ID_TAG = "TokenId";
38 static const std::string COMP_TYPE_TAG = "CompType";
39 
40 const std::string GRANT_ABILITY_BUNDLE_NAME = "com.ohos.permissionmanager";
41 const std::string GRANT_ABILITY_ABILITY_NAME = "com.ohos.permissionmanager.SecurityExtAbility";
42 const std::string TYPE_KEY = "ohos.user.security.type";
43 const std::string TOKEN_KEY = "ohos.ability.params.token";
44 
45 constexpr uint32_t MAX_CFG_FILE_SIZE = 100 * 1024; // 100k
46 constexpr uint64_t LOCATION_BUTTON_FIRST_USE = 1 << 0;
47 constexpr uint64_t SAVE_BUTTON_FIRST_USE = 1 << 1;
48 }
49 
IsCfgDirExist(void)50 bool FirstUseDialog::IsCfgDirExist(void)
51 {
52     struct stat fstat = {};
53     if (stat(SEC_COMP_SRV_CFG_PATH.c_str(), &fstat) != 0) {
54         SC_LOG_INFO(LABEL, "path %{public}s errno %{public}d.", SEC_COMP_SRV_CFG_PATH.c_str(), errno);
55         return false;
56     }
57 
58     if (!S_ISDIR(fstat.st_mode)) {
59         SC_LOG_ERROR(LABEL, "path %{public}s is not directory.", SEC_COMP_SRV_CFG_PATH.c_str());
60         return false;
61     }
62     return true;
63 }
64 
IsCfgFileExist(void)65 bool FirstUseDialog::IsCfgFileExist(void)
66 {
67     struct stat fstat = {};
68     if (stat(FIRST_USE_RECORD_JSON.c_str(), &fstat) != 0) {
69         SC_LOG_INFO(LABEL, "path %{public}s errno %{public}d.", FIRST_USE_RECORD_JSON.c_str(), errno);
70         return false;
71     }
72     return true;
73 }
74 
IsCfgFileValid(void)75 bool FirstUseDialog::IsCfgFileValid(void)
76 {
77     struct stat fstat = {};
78     if (stat(FIRST_USE_RECORD_JSON.c_str(), &fstat) != 0) {
79         SC_LOG_INFO(LABEL, "path %{public}s errno %{public}d.", FIRST_USE_RECORD_JSON.c_str(), errno);
80         return false;
81     }
82     if (fstat.st_size > MAX_CFG_FILE_SIZE) {
83         SC_LOG_INFO(LABEL, "path %{public}s size too large.", FIRST_USE_RECORD_JSON.c_str());
84         return false;
85     }
86     return true;
87 }
88 
ReadCfgContent(std::string & content)89 bool FirstUseDialog::ReadCfgContent(std::string& content)
90 {
91     std::stringstream buffer;
92     std::ifstream i(FIRST_USE_RECORD_JSON);
93     if (!i.is_open()) {
94         SC_LOG_ERROR(LABEL, "cannot open file %{public}s, errno %{public}d.", FIRST_USE_RECORD_JSON.c_str(), errno);
95         return false;
96     }
97     buffer << i.rdbuf();
98     content = buffer.str();
99     i.close();
100     return true;
101 }
102 
WriteCfgContent(const std::string & content)103 void FirstUseDialog::WriteCfgContent(const std::string& content)
104 {
105     std::ofstream out(FIRST_USE_RECORD_JSON);
106     if (!out.is_open()) {
107         SC_LOG_ERROR(LABEL, "cannot open file %{public}s, errno %{public}d.", FIRST_USE_RECORD_JSON.c_str(), errno);
108         return;
109     }
110     out << content;
111     out.close();
112 }
113 
ParseRecord(nlohmann::json & jsonRes,AccessToken::AccessTokenID & id,uint64_t & type)114 bool FirstUseDialog::ParseRecord(nlohmann::json& jsonRes,
115     AccessToken::AccessTokenID& id, uint64_t& type)
116 {
117     if (jsonRes.find(TOKEN_ID_TAG) == jsonRes.end() ||
118         !jsonRes.at(TOKEN_ID_TAG).is_number()) {
119         SC_LOG_ERROR(LABEL, "parse TokenId failed.");
120         return false;
121     }
122     id = jsonRes.at(TOKEN_ID_TAG).get<uint32_t>();
123     if (id == AccessToken::INVALID_TOKENID) {
124         SC_LOG_ERROR(LABEL, "TokenId is not invalid.");
125         return false;
126     }
127 
128     if (jsonRes.find(COMP_TYPE_TAG) == jsonRes.end() ||
129         !jsonRes.at(COMP_TYPE_TAG).is_number()) {
130         SC_LOG_ERROR(LABEL, "parse CompType failed.");
131         return false;
132     }
133     type = jsonRes.at(COMP_TYPE_TAG).get<uint64_t>();
134     return true;
135 }
136 
ParseRecords(nlohmann::json & jsonRes)137 void FirstUseDialog::ParseRecords(nlohmann::json& jsonRes)
138 {
139     std::unique_lock<std::mutex> lock(useMapMutex_);
140     if (jsonRes.find(FIRST_USE_RECORD_TAG) == jsonRes.end() ||
141         !jsonRes.at(FIRST_USE_RECORD_TAG).is_array()) {
142         SC_LOG_ERROR(LABEL, "parse tag failed.");
143         return;
144     }
145 
146     nlohmann::json recordListJson = jsonRes.at(FIRST_USE_RECORD_TAG);
147     for (auto& recordJson : recordListJson) {
148         AccessToken::AccessTokenID id;
149         uint64_t type;
150         if (!ParseRecord(recordJson, id, type)) {
151             SC_LOG_ERROR(LABEL, "parse record failed.");
152             return;
153         }
154         firstUseMap_[id] = type;
155     }
156 }
157 
LoadFirstUseRecord(void)158 void FirstUseDialog::LoadFirstUseRecord(void)
159 {
160     if (!IsCfgFileValid()) {
161         SC_LOG_INFO(LABEL, "first use record is invalid.");
162         return;
163     }
164 
165     std::string content;
166     if (!ReadCfgContent(content)) {
167         return;
168     }
169 
170     nlohmann::json jsonRes = nlohmann::json::parse(content, nullptr, false);
171     if (jsonRes.is_discarded()) {
172         SC_LOG_ERROR(LABEL, "cfg info format is invalid");
173         return;
174     }
175 
176     ParseRecords(jsonRes);
177 }
178 
SaveFirstUseRecord(void)179 void FirstUseDialog::SaveFirstUseRecord(void)
180 {
181     SC_LOG_INFO(LABEL, "start save first_use_record json");
182     if (!IsCfgDirExist()) {
183         SC_LOG_ERROR(LABEL, "dir %{public}s is not exist, errno %{public}d",
184             SEC_COMP_SRV_CFG_PATH.c_str(), errno);
185         return;
186     }
187 
188     if (!IsCfgFileExist()) {
189         if (creat(FIRST_USE_RECORD_JSON.c_str(), S_IRUSR | S_IWUSR) == -1) {
190             SC_LOG_ERROR(LABEL, "create %{public}s failed, errno %{public}d",
191                 FIRST_USE_RECORD_JSON.c_str(), errno);
192             return;
193         }
194     }
195 
196     nlohmann::json jsonRes;
197     {
198         std::unique_lock<std::mutex> lock(useMapMutex_);
199         nlohmann::json recordsJson;
200         for (auto iter = firstUseMap_.begin(); iter != firstUseMap_.end(); ++iter) {
201             AccessToken::AccessTokenID id = iter->first;
202             AccessToken::HapTokenInfo info;
203             if (AccessToken::AccessTokenKit::GetHapTokenInfo(id, info) != AccessToken::RET_SUCCESS) {
204                 SC_LOG_INFO(LABEL, "token id %{public}d is not exist, do not update it.", id);
205                 continue;
206             }
207             nlohmann::json recordJson;
208             recordJson[TOKEN_ID_TAG] = id;
209             recordJson[COMP_TYPE_TAG] = iter->second;
210             recordsJson.emplace_back(recordJson);
211         }
212 
213         jsonRes[FIRST_USE_RECORD_TAG] = recordsJson;
214     }
215     WriteCfgContent(jsonRes.dump());
216 }
217 
StartDialogAbility(SecCompType type,sptr<IRemoteObject> callerToken)218 void FirstUseDialog::StartDialogAbility(SecCompType type, sptr<IRemoteObject> callerToken)
219 {
220     int32_t typeNum;
221     if (type == LOCATION_COMPONENT) {
222         typeNum = 0;
223     } else if (type == SAVE_COMPONENT) {
224         typeNum = 1;
225     } else {
226         SC_LOG_ERROR(LABEL, "unknown type.");
227         return;
228     }
229 
230     AAFwk::Want want;
231     want.SetElementName(GRANT_ABILITY_BUNDLE_NAME, GRANT_ABILITY_ABILITY_NAME);
232     want.SetParam(TYPE_KEY, typeNum);
233     want.SetParam(TOKEN_KEY, callerToken);
234     int startRes = AAFwk::AbilityManagerClient::GetInstance()->StartExtensionAbility(want, callerToken);
235     SC_LOG_INFO(LABEL, "start ability res %{public}d", startRes);
236 }
237 
SendSaveEventHandler(void)238 void FirstUseDialog::SendSaveEventHandler(void)
239 {
240     std::function<void()> delayed = ([this]() {
241         this->SaveFirstUseRecord();
242     });
243 
244     SC_LOG_INFO(LABEL, "Delay first_use_record json");
245     secHandler_->ProxyPostTask(delayed);
246 }
247 
NotifyFirstUseDialog(AccessToken::AccessTokenID tokenId,SecCompType type,sptr<IRemoteObject> callerToken)248 bool FirstUseDialog::NotifyFirstUseDialog(AccessToken::AccessTokenID tokenId, SecCompType type,
249     sptr<IRemoteObject> callerToken)
250 {
251     if (secHandler_ == nullptr) {
252         SC_LOG_ERROR(LABEL, "event handler invalid.");
253         return false;
254     }
255     if (callerToken == nullptr) {
256         SC_LOG_INFO(LABEL, "callerToken is null, no need to notify dialog");
257         return false;
258     }
259 
260     uint64_t typeMask;
261     if (type == LOCATION_COMPONENT) {
262         typeMask = LOCATION_BUTTON_FIRST_USE;
263     } else if (type == SAVE_COMPONENT) {
264         typeMask = SAVE_BUTTON_FIRST_USE;
265     } else {
266         SC_LOG_INFO(LABEL, "this type need not notify dialog to user");
267         return false;
268     }
269 
270     std::unique_lock<std::mutex> lock(useMapMutex_);
271     auto iter = firstUseMap_.find(tokenId);
272     if (iter == firstUseMap_.end()) {
273         SC_LOG_INFO(LABEL, "has not use record, start dialog");
274         StartDialogAbility(type, callerToken);
275         firstUseMap_[tokenId] = typeMask;
276         SendSaveEventHandler();
277         return true;
278     }
279 
280     uint64_t compTypes = firstUseMap_[tokenId];
281     if ((compTypes & typeMask) == typeMask) {
282         SC_LOG_INFO(LABEL, "no need notify again.");
283         return true;
284     }
285     StartDialogAbility(type, callerToken);
286     firstUseMap_[tokenId] |= typeMask;
287     SendSaveEventHandler();
288     return true;
289 }
290 
Init(std::shared_ptr<SecEventHandler> secHandler)291 void FirstUseDialog::Init(std::shared_ptr<SecEventHandler> secHandler)
292 {
293     SC_LOG_DEBUG(LABEL, "Init!!");
294     secHandler_ = secHandler;
295     LoadFirstUseRecord();
296 }
297 }  // namespace SecurityComponent
298 }  // namespace Security
299 }  // namespace OHOS
300