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