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