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