1 /*
2 * Copyright (c) 2022 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 "user_delegate.h"
17
18 #define LOG_TAG "UserDelegate"
19
20 #include <thread>
21 #include "communicator/communication_provider.h"
22 #include "executor_factory.h"
23 #include "log_print.h"
24 #include "metadata/meta_data_manager.h"
25 #include "utils/anonymous.h"
26 namespace OHOS::DistributedData {
27 using OHOS::AppDistributedKv::CommunicationProvider;
28 using namespace OHOS::DistributedKv;
GetLocalDeviceId()29 std::string GetLocalDeviceId()
30 {
31 static std::string deviceId;
32 if (deviceId.empty()) {
33 deviceId = CommunicationProvider::GetInstance().GetLocalDevice().uuid;
34 }
35
36 return deviceId;
37 }
38
GetLocalUserStatus()39 std::vector<UserStatus> UserDelegate::GetLocalUserStatus()
40 {
41 ZLOGI("begin");
42 auto deviceId = GetLocalDeviceId();
43 if (deviceId.empty()) {
44 ZLOGE("failed to get local device id");
45 return {};
46 }
47 return GetUsers(deviceId);
48 }
49
GetLocalUsers()50 std::set<std::string> UserDelegate::GetLocalUsers()
51 {
52 auto deviceId = GetLocalDeviceId();
53 if (deviceId.empty()) {
54 ZLOGE("failed to get local device id");
55 return {};
56 }
57 if (!deviceUserMap_.Contains(deviceId)) {
58 LoadFromMeta(deviceId);
59 }
60 std::set<std::string> users;
61 deviceUserMap_.ComputeIfPresent(deviceId, [&users](auto&, std::map<int, bool> &value) {
62 for (auto [user, active] : value) {
63 users.emplace(std::to_string(user));
64 }
65 return !value.empty();
66 });
67 return users;
68 }
69
GetRemoteUserStatus(const std::string & deviceId)70 std::vector<DistributedData::UserStatus> UserDelegate::GetRemoteUserStatus(const std::string &deviceId)
71 {
72 if (deviceId.empty()) {
73 ZLOGE("error input device id");
74 return {};
75 }
76 return GetUsers(deviceId);
77 }
78
GetUsers(const std::string & deviceId)79 std::vector<UserStatus> UserDelegate::GetUsers(const std::string &deviceId)
80 {
81 std::vector<UserStatus> userStatus;
82 if (!deviceUserMap_.Contains(deviceId)) {
83 LoadFromMeta(deviceId);
84 }
85 deviceUserMap_.ComputeIfPresent(deviceId, [&userStatus](const auto &, std::map<int, bool> &userMap) {
86 for (const auto &[key, value] : userMap) {
87 userStatus.emplace_back(key, value);
88 }
89 return true;
90 });
91
92 ZLOGI("device:%{public}s, users:%{public}s", Anonymous::Change(deviceId).c_str(),
93 Serializable::Marshall(userStatus).c_str());
94 return userStatus;
95 }
96
DeleteUsers(const std::string & deviceId)97 void UserDelegate::DeleteUsers(const std::string &deviceId)
98 {
99 deviceUserMap_.Erase(deviceId);
100 }
101
UpdateUsers(const std::string & deviceId,const std::vector<UserStatus> & userStatus)102 void UserDelegate::UpdateUsers(const std::string &deviceId, const std::vector<UserStatus> &userStatus)
103 {
104 ZLOGI("begin, device:%{public}.10s, users:%{public}zu", Anonymous::Change(deviceId).c_str(), userStatus.size());
105 deviceUserMap_.Compute(deviceId, [&userStatus](const auto &key, std::map<int, bool> &userMap) {
106 userMap = {};
107 for (const auto &user : userStatus) {
108 userMap[user.id] = user.isActive;
109 }
110 ZLOGI("end, device:%{public}.10s, users:%{public}zu", Anonymous::Change(key).c_str(), userMap.size());
111 return true;
112 });
113 }
114
InitLocalUserMeta()115 bool UserDelegate::InitLocalUserMeta()
116 {
117 std::vector<int> users;
118 auto ret = AccountDelegate::GetInstance()->QueryUsers(users);
119 if (!ret || users.empty()) {
120 ZLOGE("failed to query os accounts, ret:%{public}d", ret);
121 return false;
122 }
123 std::vector<UserStatus> userStatus = { { 0, true } };
124 for (const auto &user : users) {
125 userStatus.emplace_back(user, true);
126 }
127 UserMetaData userMetaData;
128 userMetaData.deviceId = GetLocalDeviceId();
129 UpdateUsers(userMetaData.deviceId, userStatus);
130 deviceUserMap_.ComputeIfPresent(userMetaData.deviceId, [&userMetaData](const auto &, std::map<int, bool> &userMap) {
131 for (const auto &[key, value] : userMap) {
132 userMetaData.users.emplace_back(key, value);
133 }
134 return true;
135 });
136 ZLOGI("put user meta data save meta data");
137 return MetaDataManager::GetInstance().SaveMeta(UserMetaRow::GetKeyFor(userMetaData.deviceId), userMetaData);
138 }
139
LoadFromMeta(const std::string & deviceId)140 void UserDelegate::LoadFromMeta(const std::string &deviceId)
141 {
142 UserMetaData userMetaData;
143 MetaDataManager::GetInstance().LoadMeta(UserMetaRow::GetKeyFor(deviceId), userMetaData);
144 std::map<int, bool> userMap;
145 for (const auto &user : userMetaData.users) {
146 userMap[user.id] = user.isActive;
147 }
148 deviceUserMap_.Compute(deviceId, [&userMap](const auto &, auto &value) {
149 value = userMap;
150 return true;
151 });
152 }
153
GetInstance()154 UserDelegate &UserDelegate::GetInstance()
155 {
156 static UserDelegate instance;
157 return instance;
158 }
159
Init()160 void UserDelegate::Init()
161 {
162 KvStoreTask retryTask([this]() {
163 do {
164 static constexpr int RETRY_INTERVAL = 500; // millisecond
165 std::this_thread::sleep_for(std::chrono::milliseconds(RETRY_INTERVAL));
166 if (!InitLocalUserMeta()) {
167 continue;
168 }
169 break;
170 } while (true);
171 ZLOGI("update user meta ok");
172 });
173
174 auto ret = AccountDelegate::GetInstance()->Subscribe(std::make_shared<LocalUserObserver>(*this));
175 MetaDataManager::GetInstance().Subscribe(
176 UserMetaRow::KEY_PREFIX, [this](const std::string &key, const std::string &value, int32_t flag) -> auto {
177 UserMetaData metaData;
178 UserMetaData::Unmarshall(value, metaData);
179 ZLOGD("flag:%{public}d, value:%{public}s", flag, Anonymous::Change(metaData.deviceId).c_str());
180 if (metaData.deviceId == GetLocalDeviceId()) {
181 ZLOGD("ignore local device user meta change");
182 return false;
183 }
184 if (flag == MetaDataManager::INSERT || flag == MetaDataManager::UPDATE) {
185 UpdateUsers(metaData.deviceId, metaData.users);
186 } else if (flag == MetaDataManager::DELETE) {
187 DeleteUsers(metaData.deviceId);
188 } else {
189 ZLOGD("ignored operation");
190 }
191 return true;
192 });
193 if (!InitLocalUserMeta()) {
194 ExecutorFactory::GetInstance().Execute(std::move(retryTask));
195 }
196 ZLOGD("subscribe os account ret:%{public}d", ret);
197 }
198
NotifyUserEvent(const UserDelegate::UserEvent & userEvent)199 bool UserDelegate::NotifyUserEvent(const UserDelegate::UserEvent &userEvent)
200 {
201 // update all local user status
202 (void) userEvent;
203 return InitLocalUserMeta();
204 }
205
LocalUserObserver(UserDelegate & userDelegate)206 UserDelegate::LocalUserObserver::LocalUserObserver(UserDelegate &userDelegate) : userDelegate_(userDelegate)
207 {
208 }
209
OnAccountChanged(const DistributedKv::AccountEventInfo & eventInfo)210 void UserDelegate::LocalUserObserver::OnAccountChanged(const DistributedKv::AccountEventInfo &eventInfo)
211 {
212 ZLOGI("event info:%{public}s, %{public}d", eventInfo.userId.c_str(), eventInfo.status);
213 userDelegate_.NotifyUserEvent({}); // just notify
214 }
215
Name()216 std::string UserDelegate::LocalUserObserver::Name()
217 {
218 return "user_delegate";
219 }
220 } // namespace OHOS::DistributedData
221