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