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