1 /*
2  * Copyright (c) 2021-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 "profile_change_handler.h"
17 
18 #include <cinttypes>
19 
20 #include "datetime_ex.h"
21 #include "string_ex.h"
22 
23 #include "authority_manager.h"
24 #include "device_profile_errors.h"
25 #include "device_profile_log.h"
26 #include "device_profile_storage_manager.h"
27 #include "device_profile_utils.h"
28 #include "dp_radar_helper.h"
29 #include "profile_change_notification.h"
30 
31 namespace OHOS {
32 namespace DeviceProfile {
33 using namespace OHOS::DistributedKv;
34 
35 namespace {
36 const std::string TAG = "ProfileChangeHandler";
37 
38 constexpr int32_t NUM_KEY_FILEDS = 3;
39 constexpr int32_t DEVICE_ID_SIZE = 64;
40 }
41 
42 struct ProfileKey {
43     std::string udid;
44     std::string serviceId;
45     KeyType type {KeyType::UNKNOWN};
46 
47     static std::unique_ptr<ProfileKey> Parse(const std::string& entryKey);
48 };
49 
Parse(const std::string & entryKey)50 std::unique_ptr<ProfileKey> ProfileKey::Parse(const std::string& entryKey)
51 {
52     std::vector<std::string> vec;
53     SplitStr(entryKey, "/", vec);
54     if (vec.size() != NUM_KEY_FILEDS) {
55         HILOGE("parse key failed");
56         return nullptr;
57     }
58 
59     int32_t index = 0;
60     auto profileKey = std::make_unique<ProfileKey>();
61     profileKey->udid = std::move(vec[index++]);
62     if (profileKey->udid.size() != DEVICE_ID_SIZE) {
63         HILOGE("parse udid failed");
64         return nullptr;
65     }
66     int32_t type = 0;
67     if (!StrToInt(vec[index++], type)) {
68         HILOGE("parse type failed");
69         return nullptr;
70     }
71     profileKey->type = static_cast<KeyType>(type);
72     profileKey->serviceId = std::move(vec[index]);
73     return profileKey;
74 }
75 
OnChange(const ChangeNotification & changeNotification)76 void ProfileChangeHandler::OnChange(const ChangeNotification& changeNotification)
77 {
78     std::vector<ProfileEntry> profileEntries;
79     const auto& insertedEntries = changeNotification.GetInsertEntries();
80     const auto& updatedEntries = changeNotification.GetUpdateEntries();
81     const auto& deletedEntries = changeNotification.GetDeleteEntries();
82     int32_t numEntries = insertedEntries.size() + updatedEntries.size() + deletedEntries.size();
83     profileEntries.reserve(numEntries);
84     HILOGI("numEntries = %{public}d", numEntries);
85 
86     int64_t begin = GetTickCount();
87     Service2Index service2Index;
88     Entry entry;
89     if (!insertedEntries.empty()) {
90         entry = insertedEntries.front();
91         ConvertEntry(insertedEntries, ProfileChangeType::INSERTED, profileEntries, service2Index);
92     }
93     if (!updatedEntries.empty()) {
94         entry = updatedEntries.front();
95         ConvertEntry(updatedEntries, ProfileChangeType::UPDATED, profileEntries, service2Index);
96     }
97     if (!deletedEntries.empty()) {
98         entry = deletedEntries.front();
99         ConvertEntry(deletedEntries, ProfileChangeType::DELETED, profileEntries, service2Index);
100     }
101     HILOGI("convert entry elapsedTime is %{public}" PRId64 " ms", GetTickCount() - begin);
102 
103     std::string udid;
104     auto profileKey = ProfileKey::Parse(entry.key.ToString());
105     if (profileKey == nullptr) {
106         HILOGE("bad profile entry");
107         return;
108     }
109     udid = std::move(profileKey->udid);
110     HILOGI("udid = %{public}s", DeviceProfileUtils::AnonymizeDeviceId(udid).c_str());
111     std::string localUdid;
112     // won't fail
113     DpDeviceManager::GetInstance().GetLocalDeviceUdid(localUdid);
114 
115     std::string networkId;
116     if (!DpDeviceManager::GetInstance().TransformDeviceId(udid, networkId,
117         DeviceIdType::NETWORKID)) {
118         HILOGE("transform to networkid failed");
119     }
120 
121     ProfileChangeNotification notification(profileEntries, networkId, localUdid == udid);
122     auto notifyTask = [this, notification = std::move(notification),
123         service2Index = std::move(service2Index)]() {
124         NotifyProfileChanged(notification, service2Index);
125     };
126     std::lock_guard<std::mutex> autoLock(notifierLock_);
127     if (eventHandler_ != nullptr && !eventHandler_->PostTask(notifyTask)) {
128         HILOGI("post task failed");
129     }
130 }
131 
ConvertEntry(const std::vector<Entry> & entries,ProfileChangeType changeType,std::vector<ProfileEntry> & profileEntries,Service2Index & service2Index)132 void ProfileChangeHandler::ConvertEntry(const std::vector<Entry>& entries,
133     ProfileChangeType changeType, std::vector<ProfileEntry>& profileEntries,
134     Service2Index& service2Index)
135 {
136     for (const auto& entry : entries) {
137         auto profileKey = ProfileKey::Parse(entry.key.ToString());
138         if (profileKey == nullptr || profileKey->type != KeyType::SERVICE) {
139             HILOGW("profileKey is invalid");
140             continue;
141         }
142 
143         std::string trimmedKey = std::move(profileKey->serviceId);
144         HILOGI("key = %{public}s, state = %{public}u", trimmedKey.c_str(),
145             static_cast<uint8_t>(changeType));
146         service2Index.emplace(trimmedKey, profileEntries.size());
147         profileEntries.emplace_back(std::move(trimmedKey), entry.value.ToString(), changeType);
148         HILOGD("value = %{public}s, state = %{public}u",
149             DeviceProfileUtils::AnonymizeString(entry.value.ToString()).c_str(), static_cast<uint8_t>(changeType));
150     }
151 }
152 
NotifyProfileChanged(const ProfileChangeNotification & changeNotification,const Service2Index & service2Index)153 void ProfileChangeHandler::NotifyProfileChanged(const ProfileChangeNotification& changeNotification,
154     const Service2Index& service2Index)
155 {
156     HILOGD("called");
157     std::lock_guard<std::mutex> autoLock(notifierLock_);
158     HILOGI("subscribers size = %{public}zu", profileEventSubscribeInfos_.size());
159     struct RadarInfo info = {
160         .funcName = "NotifyProfileChanged",
161         .stageRes = static_cast<int32_t>(StageRes::STAGE_SUCC),
162         .hostName = kvNAME,
163     };
164     if (!DpRadarHelper::GetInstance().ReportNotifyDataChange(info)) {
165         HILOGE("ReportNotifyDataChange failed");
166     }
167     for (const auto& [notifier, subscribeInfo] : profileEventSubscribeInfos_) {
168         sptr<IProfileEventNotifier> profileEventNotifier = iface_cast<IProfileEventNotifier>(notifier);
169         if (profileEventNotifier == nullptr) {
170             HILOGE("cast to IProfileEventNotifier failed");
171             continue;
172         }
173 
174         FilterInfo filterInfo;
175         FilterChangedProfileLocked(subscribeInfo, changeNotification, service2Index, filterInfo);
176         int64_t begin = GetTickCount();
177         NotifyProfileChangedLocked(changeNotification, filterInfo, profileEventNotifier);
178         HILOGI("notify elapsedTime is %{public}" PRId64 " ms", GetTickCount() - begin);
179     }
180 }
181 
NotifyProfileChangedLocked(const ProfileChangeNotification & changeNotification,const FilterInfo & filterInfo,const sptr<IProfileEventNotifier> & profileEventNotifier)182 void ProfileChangeHandler::NotifyProfileChangedLocked(const ProfileChangeNotification& changeNotification,
183     const FilterInfo& filterInfo, const sptr<IProfileEventNotifier>& profileEventNotifier)
184 {
185     if (profileEventNotifier == nullptr) {
186         HILOGE("profileEventNotifier is nullptr!");
187         return;
188     }
189     if (!filterInfo.filtered) {
190         HILOGD("not filtered");
191         profileEventNotifier->OnProfileChanged(changeNotification);
192         return;
193     }
194 
195     const auto& indexes = filterInfo.indexes;
196     // filtered but not found satisfied service
197     size_t size = indexes.size();
198     if (size == 0) {
199         return;
200     }
201 
202     std::vector<ProfileEntry> filteredEntries;
203     filteredEntries.reserve(size);
204     const auto& profileEntries = changeNotification.GetProfileEntries();
205     for (auto index : indexes) {
206         filteredEntries.emplace_back(profileEntries[index]);
207     }
208     HILOGI("filtered with %{public}zu entries", size);
209     bool isLocal = changeNotification.IsLocal();
210     std::string deviceId = changeNotification.GetDeviceId();
211     ProfileChangeNotification filteredNotification(filteredEntries, deviceId, isLocal);
212     profileEventNotifier->OnProfileChanged(filteredNotification);
213 }
214 
FilterChangedProfileLocked(const SubscribeInfo & subscribeInfo,const ProfileChangeNotification & changeNotification,const Service2Index & service2Index,FilterInfo & filterInfo)215 void ProfileChangeHandler::FilterChangedProfileLocked(const SubscribeInfo& subscribeInfo,
216     const ProfileChangeNotification& changeNotification,
217     const Service2Index& service2Index, FilterInfo& filterInfo)
218 {
219     const auto& extraInfo = subscribeInfo.extraInfo;
220 
221     // currently only support specific deviceId
222     std::string deviceId = extraInfo["deviceId"];
223     if (!deviceId.empty()) {
224         filterInfo.filtered = true;
225         std::string networkId;
226         if (!DpDeviceManager::GetInstance().TransformDeviceId(deviceId, networkId,
227             DeviceIdType::NETWORKID)) {
228             HILOGE("transform to networkid failed");
229             return;
230         }
231         if (networkId != changeNotification.GetDeviceId()) {
232             return;
233         }
234     }
235 
236     const auto& serviceIdsJson = extraInfo["serviceIds"];
237     auto& indexes = filterInfo.indexes;
238     if (serviceIdsJson.empty()) {
239         return;
240     }
241     filterInfo.filtered = true;
242     for (const auto& serviceIdJson : serviceIdsJson) {
243         std::string serviceId = serviceIdJson;
244         HILOGI("serviceId = %{public}s", serviceId.c_str());
245         auto iter = service2Index.find(serviceId);
246         if (iter != service2Index.end()) {
247             indexes.insert(iter->second);
248         }
249     }
250 }
251 
Register()252 int32_t ProfileChangeHandler::Register()
253 {
254     HILOGI("called");
255     return DeviceProfileStorageManager::GetInstance().SubscribeKvStore(shared_from_this());
256 }
257 
Unregister()258 int32_t ProfileChangeHandler::Unregister()
259 {
260     HILOGI("called");
261     return DeviceProfileStorageManager::GetInstance().UnSubscribeKvStore(shared_from_this());
262 }
263 
Subscribe(const SubscribeInfo & subscribeInfo,const sptr<IRemoteObject> & profileEventNotifier)264 int32_t ProfileChangeHandler::Subscribe(const SubscribeInfo& subscribeInfo,
265     const sptr<IRemoteObject>& profileEventNotifier)
266 {
267     const auto& extraInfo = subscribeInfo.extraInfo;
268     const auto& serviceIdsJson = extraInfo["serviceIds"];
269     std::vector<std::string> serviceIds;
270     for (const auto& serviceIdJson : serviceIdsJson) {
271         std::string serviceId = serviceIdJson;
272         HILOGI("serviceId = %{public}s", serviceId.c_str());
273         serviceIds.emplace_back(std::move(serviceId));
274     }
275 
276     if (!AuthorityManager::GetInstance().CheckServicesAuthority(AuthValue::AUTH_R,
277         serviceIds)) {
278         return ERR_DP_PERMISSION_DENIED;
279     }
280     return ProfileEventHandler::Subscribe(subscribeInfo, profileEventNotifier);
281 }
282 } // namespace DeviceProfile
283 } // namespace OHOS
284