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