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