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_static_subscriber_manager.h"
17
18 #include <dlfcn.h>
19 #include <thread>
20 #include <pthread.h>
21 #include "account_constants.h"
22 #include "account_log_wrapper.h"
23 #include "account_hisysevent_adapter.h"
24 #ifdef HICOLLIE_ENABLE
25 #include "account_timer.h"
26 #include "xcollie/xcollie.h"
27 #endif // HICOLLIE_ENABLE
28
29 namespace OHOS {
30 namespace AccountSA {
31 namespace {
32 #ifdef _ARM64_
33 static const std::string ROOT_LIB_PATH = "/system/lib64/";
34 #else
35 static const std::string ROOT_LIB_PATH = "/system/lib/";
36 #endif
37 }
38
~StaticSubscriber()39 StaticSubscriber::~StaticSubscriber()
40 {
41 callback = nullptr;
42 if (handle != nullptr) {
43 dlclose(handle);
44 handle = nullptr;
45 }
46 }
47
OsAccountStaticSubscriberManager()48 OsAccountStaticSubscriberManager::OsAccountStaticSubscriberManager()
49 {
50 std::map<OsAccountState, std::set<std::string>> defaultConfig;
51 defaultConfig[OsAccountState::CREATING] = { ROOT_LIB_PATH + "libtheme_manager_client.z.so" };
52 Init(defaultConfig);
53 }
54
GetInstance()55 OsAccountStaticSubscriberManager &OsAccountStaticSubscriberManager::GetInstance()
56 {
57 static OsAccountStaticSubscriberManager instance;
58 return instance;
59 }
60
Init(const std::map<OsAccountState,std::set<std::string>> & staticSubscriberConfig)61 void OsAccountStaticSubscriberManager::Init(
62 const std::map<OsAccountState, std::set<std::string>> &staticSubscriberConfig)
63 {
64 std::lock_guard<std::mutex> lock(mutex_);
65 for (const auto &it : staticSubscriberConfig) {
66 std::set<std::shared_ptr<StaticSubscriber>> subscribers;
67 for (const auto &path : it.second) {
68 auto subscriber = ParseStaticSubscriber(path);
69 if (subscriber != nullptr) {
70 subscribers.insert(subscriber);
71 }
72 }
73 if (!subscribers.empty()) {
74 state2Subscribers_[it.first] = subscribers;
75 }
76 }
77 }
78
ParseStaticSubscriber(const std::string & path)79 std::shared_ptr<StaticSubscriber> OsAccountStaticSubscriberManager::ParseStaticSubscriber(const std::string &path)
80 {
81 auto subIt = staticSubscribers_.find(path);
82 if (subIt != staticSubscribers_.end()) {
83 ACCOUNT_LOGE("Subscriber already exists");
84 return subIt->second;
85 }
86 void* handle = dlopen(path.c_str(), RTLD_LAZY);
87 if (handle == nullptr) {
88 auto errMsg = dlerror();
89 ACCOUNT_LOGE("Failed to dlopen, path: %{public}s, error: %{public}s", path.c_str(), errMsg);
90 REPORT_OS_ACCOUNT_FAIL(0, Constants::OPERATION_EVENT_PUBLISH, ERR_ACCOUNT_COMMON_DLOPEN_ERROR,
91 "Failed to dlopen, path: " + path + ", error: " + (errMsg ? std::string(errMsg) : ""));
92 return nullptr;
93 }
94 void *func = dlsym(handle, "OnOsAccountStateChanged");
95 if (func == nullptr) {
96 auto errMsg = dlerror();
97 ACCOUNT_LOGE("Failed to dlsym, path: %{public}s, error=%{public}s", path.c_str(), errMsg);
98 REPORT_OS_ACCOUNT_FAIL(0, Constants::OPERATION_EVENT_PUBLISH, ERR_ACCOUNT_COMMON_DLSYM_ERROR,
99 "Failed to dlsym, path: " + path + ", error: " + (errMsg ? std::string(errMsg) : ""));
100 dlclose(handle);
101 handle = nullptr;
102 return nullptr;
103 }
104 auto subscriber = std::make_shared<StaticSubscriber>();
105 subscriber->path = path;
106 subscriber->handle = handle;
107 subscriber->callback = func;
108 staticSubscribers_[path] = subscriber;
109 ACCOUNT_LOGI("Parse static subscriber successfully, path: %{public}s", path.c_str());
110 return subscriber;
111 }
112
PublishToSubscriber(const std::shared_ptr<StaticSubscriber> & subscriber,const COsAccountStateData & data)113 ErrCode OsAccountStaticSubscriberManager::PublishToSubscriber(
114 const std::shared_ptr<StaticSubscriber> &subscriber, const COsAccountStateData &data)
115 {
116 if (subscriber == nullptr || subscriber->callback == nullptr) {
117 ACCOUNT_LOGE("Invalid subscriber");
118 return ERR_ACCOUNT_COMMON_INVALID_PARAMETER;
119 }
120 ACCOUNT_LOGI("State: %{public}d, fromId: %{public}d, toId: %{public}d, subscriberPath: %{public}s",
121 data.state, data.fromId, data.toId, subscriber->path.c_str());
122 #ifdef HICOLLIE_ENABLE
123 AccountTimer timer;
124 #endif
125 // Callback will be invalid when the singleton destroyed (i.e. the process exits), so lock protection is not added,
126 // otherwise it will increase performance overhead
127 return (*reinterpret_cast<OnOsAccountStateChangedFunc>(subscriber->callback))(&data);
128 }
129
Publish(int32_t fromId,OsAccountState state,int32_t toId)130 ErrCode OsAccountStaticSubscriberManager::Publish(int32_t fromId, OsAccountState state, int32_t toId)
131 {
132 std::lock_guard<std::mutex> lock(mutex_);
133 auto it = state2Subscribers_.find(state);
134 if (it == state2Subscribers_.end()) {
135 ACCOUNT_LOGI("No subscriber, state: %{public}d", state);
136 return ERR_OK;
137 }
138 for (const std::shared_ptr<StaticSubscriber> &subscriber : it->second) {
139 auto task = [subscriber, state, fromId, toId] {
140 COsAccountStateData data;
141 data.fromId = fromId;
142 data.state = state;
143 data.toId = toId;
144 ErrCode errCode = PublishToSubscriber(subscriber, data);
145 if (errCode != ERR_OK) {
146 ACCOUNT_LOGE("Failed to publish to subscriber, path=%{public}s, state=%{public}d, fromId=%{public}d, "
147 "toId=%{public}d, errCode=%{public}d", subscriber->path.c_str(), state, fromId, toId, errCode);
148 REPORT_OS_ACCOUNT_FAIL(data.toId, Constants::OPERATION_EVENT_PUBLISH, errCode,
149 "Failed to publish to subscriber, path=" + subscriber->path + ", state=" + std::to_string(state) +
150 ", fromId=" + std::to_string(fromId) + ", toId=" + std::to_string(toId));
151 }
152 };
153 std::thread publishThread(task);
154 pthread_setname_np(publishThread.native_handle(), "StaticPublish");
155 publishThread.detach();
156 }
157 return ERR_OK;
158 }
159 } // AccountSA
160 } // OHOS
161