1 /*
2 * Copyright (c) 2025 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 "os_account_constraint_subscribe_manager.h"
17
18 #include <thread>
19 #include "account_constants.h"
20 #include "account_hisysevent_adapter.h"
21 #include "account_log_wrapper.h"
22 #include "os_account_constraint_subscribe_death_recipient.h"
23 #include "ipc_skeleton.h"
24 #include "ios_account_constraint_event.h"
25 #ifdef HICOLLIE_ENABLE
26 #include "account_timer.h"
27 #include "xcollie/xcollie.h"
28 #endif // HICOLLIE_ENABLE
29
30 namespace OHOS {
31 namespace AccountSA {
32 namespace {
33 const char THREAD_CONSTRAINT_EVENT[] = "constraintEvent";
34 }
OsAccountConstraintSubscribeManager()35 OsAccountConstraintSubscribeManager::OsAccountConstraintSubscribeManager()
36 : subscribeDeathRecipient_(sptr<IRemoteObject::DeathRecipient>(
37 new (std::nothrow) OsAccountConstraintSubscribeDeathRecipient()))
38 {}
39
GetInstance()40 OsAccountConstraintSubscribeManager &OsAccountConstraintSubscribeManager::GetInstance()
41 {
42 static OsAccountConstraintSubscribeManager instance;
43 return instance;
44 }
45
RemoveConstraintFromSubscribeRecord(const OsAccountConstraintSubscribeRecordPtr & recordPtr,const std::set<std::string> & constraints)46 void OsAccountConstraintSubscribeManager::RemoveConstraintFromSubscribeRecord(
47 const OsAccountConstraintSubscribeRecordPtr &recordPtr, const std::set<std::string> &constraints)
48 {
49 for (auto const &constraint : constraints) {
50 constraint2RecordMap_[constraint].erase(recordPtr);
51 if (constraint2RecordMap_[constraint].empty()) {
52 constraint2RecordMap_.erase(constraint);
53 }
54 recordPtr->constraintSet_.erase(constraint);
55 }
56 if (recordPtr->constraintSet_.empty()) {
57 constraintRecords_.erase(recordPtr);
58 }
59 }
60
InsertSubscribeRecord(const OsAccountConstraintSubscribeRecordPtr & recordPtr)61 void OsAccountConstraintSubscribeManager::InsertSubscribeRecord(
62 const OsAccountConstraintSubscribeRecordPtr &recordPtr)
63 {
64 constraintRecords_.emplace(recordPtr);
65 for (auto const &constraint : recordPtr->constraintSet_) {
66 constraint2RecordMap_[constraint].emplace(recordPtr);
67 }
68 }
69
SubscribeOsAccountConstraints(const std::set<std::string> & constraints,const sptr<IRemoteObject> & eventListener)70 ErrCode OsAccountConstraintSubscribeManager::SubscribeOsAccountConstraints(const std::set<std::string> &constraints,
71 const sptr<IRemoteObject> &eventListener)
72 {
73 if (eventListener == nullptr) {
74 ACCOUNT_LOGE("EventListener is nullptr");
75 return ERR_ACCOUNT_COMMON_NULL_PTR_ERROR;
76 }
77 std::lock_guard<std::mutex> lock(mutex_);
78 int32_t callingUid = IPCSkeleton::GetCallingUid();
79 for (auto const &recordPtr : constraintRecords_) {
80 if (recordPtr->eventListener_ != eventListener) {
81 continue;
82 }
83 recordPtr->constraintSet_ = constraints;
84 InsertSubscribeRecord(recordPtr);
85 return ERR_OK;
86 }
87 if (subscribeDeathRecipient_ != nullptr) {
88 eventListener->AddDeathRecipient(subscribeDeathRecipient_);
89 }
90 auto recordPtr = std::make_shared<OsAccountConstraintSubscribeRecord>(constraints, eventListener, callingUid);
91 InsertSubscribeRecord(recordPtr);
92 return ERR_OK;
93 }
94
UnsubscribeOsAccountConstraints(const sptr<IRemoteObject> & eventListener)95 ErrCode OsAccountConstraintSubscribeManager::UnsubscribeOsAccountConstraints(const sptr<IRemoteObject> &eventListener)
96 {
97 if (eventListener == nullptr) {
98 ACCOUNT_LOGE("EventListener is nullptr");
99 return ERR_ACCOUNT_COMMON_NULL_PTR_ERROR;
100 }
101 std::lock_guard<std::mutex> lock(mutex_);
102 for (auto const &recordPtr : constraintRecords_) {
103 if (recordPtr->eventListener_ != eventListener) {
104 continue;
105 }
106 if (subscribeDeathRecipient_ != nullptr) {
107 eventListener->RemoveDeathRecipient(subscribeDeathRecipient_);
108 }
109 std::set<std::string> constraints = recordPtr->constraintSet_;
110 RemoveConstraintFromSubscribeRecord(recordPtr, constraints);
111 return ERR_OK;
112 }
113 return ERR_ACCOUNT_COMMON_ACCOUNT_SUBSCRIBE_NOT_FOUND_ERROR;
114 }
115
UnsubscribeOsAccountConstraints(const std::set<std::string> & constraints,const sptr<IRemoteObject> & eventListener)116 ErrCode OsAccountConstraintSubscribeManager::UnsubscribeOsAccountConstraints(const std::set<std::string> &constraints,
117 const sptr<IRemoteObject> &eventListener)
118 {
119 if (eventListener == nullptr) {
120 ACCOUNT_LOGE("EventListener is nullptr");
121 return ERR_ACCOUNT_COMMON_NULL_PTR_ERROR;
122 }
123 std::lock_guard<std::mutex> lock(mutex_);
124 for (auto const &recordPtr : constraintRecords_) {
125 if (recordPtr->eventListener_ != eventListener) {
126 continue;
127 }
128 bool isInclude = std::includes(recordPtr->constraintSet_.begin(), recordPtr->constraintSet_.end(),
129 constraints.begin(), constraints.end());
130 if (!isInclude) {
131 ACCOUNT_LOGE("Constraint set not include.");
132 return ERR_ACCOUNT_COMMON_ACCOUNT_SUBSCRIBE_NOT_FOUND_ERROR;
133 }
134 RemoveConstraintFromSubscribeRecord(recordPtr, constraints);
135 return ERR_OK;
136 }
137 ACCOUNT_LOGE("Constraint record not found.");
138 return ERR_ACCOUNT_COMMON_ACCOUNT_SUBSCRIBE_NOT_FOUND_ERROR;
139 }
140
PublishToSubscriber(const OsAccountConstraintSubscribeRecordPtr & recordPtr,int32_t localId,const std::set<std::string> & constraints,bool isEnabled)141 void OsAccountConstraintSubscribeManager::PublishToSubscriber(const OsAccountConstraintSubscribeRecordPtr &recordPtr,
142 int32_t localId, const std::set<std::string> &constraints, bool isEnabled)
143 {
144 if (recordPtr->eventListener_ == nullptr) {
145 ACCOUNT_LOGE("Subscribe constraint is null, localId=%{public}d, uid=%{public}d.", localId,
146 recordPtr->callingUid_);
147 return;
148 }
149 auto eventProxy = iface_cast<IOsAccountConstraintEvent>(recordPtr->eventListener_);
150 if (eventProxy == nullptr) {
151 ACCOUNT_LOGE("Event proxy is nullptr");
152 return;
153 }
154 int32_t retryTimes = 0;
155 ErrCode result;
156 while (retryTimes < Constants::MAX_RETRY_TIMES) {
157 result = eventProxy->OnConstraintChanged(localId, constraints, isEnabled);
158 if (result == ERR_OK || (result != Constants::E_IPC_ERROR &&
159 result != Constants::E_IPC_SA_DIED)) {
160 break;
161 }
162 retryTimes++;
163 ACCOUNT_LOGE("Failed to send the OS account event, reqCode: %{public}d, retryTimes: %{public}d",
164 result, retryTimes);
165 std::this_thread::sleep_for(std::chrono::milliseconds(Constants::DELAY_FOR_EXCEPTION));
166 }
167 if (result != ERR_OK) {
168 ACCOUNT_LOGE("SendRequest for constraint changed failed! result %{public}d, localId %{public}d.",
169 result, localId);
170 REPORT_OS_ACCOUNT_FAIL(localId, Constants::OPERATION_EVENT_PUBLISH,
171 result, "Send OnConstraintChanged subscribe failed");
172 }
173 }
174
Publish(int32_t localId,const std::set<std::string> & constraints,const bool isEnabled)175 void OsAccountConstraintSubscribeManager::Publish(int32_t localId, const std::set<std::string> &constraints,
176 const bool isEnabled)
177 {
178 std::lock_guard<std::mutex> lock(mutex_);
179 std::set<OsAccountConstraintSubscribeRecordPtr> recordPtrSet;
180 for (auto const &item : constraints) {
181 auto iter = constraint2RecordMap_.find(item);
182 if (iter != constraint2RecordMap_.end()) {
183 recordPtrSet.insert(iter->second.begin(), iter->second.end());
184 }
185 }
186 for (auto const &item : recordPtrSet) {
187 auto task = [item, localId, constraints, isEnabled, this] {
188 ACCOUNT_LOGI("Publish start, to uid=%{public}d asynch, accountId=%{public}d, enable=%{public}d",
189 item->callingUid_, localId, isEnabled);
190 this->PublishToSubscriber(item, localId, constraints, isEnabled);
191 ACCOUNT_LOGI("Publish end.");
192 };
193 std::thread taskThread(task);
194 pthread_setname_np(taskThread.native_handle(), THREAD_CONSTRAINT_EVENT);
195 taskThread.detach();
196 }
197 }
198 } // AccountSA
199 } // OHOS