1 /*
2  * Copyright (C) 2024 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 "account_subscriber.h"
17 #include "bundle_info.h"
18 #include "common_event_manager.h"
19 #include "want.h"
20 #include "media_log.h"
21 
22 namespace OHOS {
23 namespace Media {
24 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_PLAYER, "AccountSubscriber"};
25 std::shared_ptr<AccountSubscriber> AccountSubscriber::instance_ = nullptr;
26 
GetInstance()27 std::shared_ptr<AccountSubscriber> AccountSubscriber::GetInstance()
28 {
29     if (instance_ == nullptr) {
30         static std::mutex instanceMutex;
31         std::lock_guard<std::mutex> lock(instanceMutex);
32         if (instance_ == nullptr) {
33             EventFwk::MatchingSkills matchingSkills;
34             matchingSkills.AddEvent(EventFwk::CommonEventSupport::COMMON_EVENT_USER_BACKGROUND);
35             EventFwk::CommonEventSubscribeInfo subscribeInfo(matchingSkills);
36             instance_ = std::make_shared<AccountSubscriber>(subscribeInfo);
37         }
38     }
39     return instance_;
40 }
41 
AccountSubscriber(const EventFwk::CommonEventSubscribeInfo & subscribeInfo)42 AccountSubscriber::AccountSubscriber(const EventFwk::CommonEventSubscribeInfo &subscribeInfo)
43     : EventFwk::CommonEventSubscriber(subscribeInfo)
44 {
45     MEDIA_LOGI("create instance");
46 }
47 
~AccountSubscriber()48 AccountSubscriber::~AccountSubscriber()
49 {
50     std::lock_guard<std::mutex> lock(userMutex_);
51     userMap_.clear();
52     MEDIA_LOGI("free instance");
53 }
54 
DispatchEvent(int32_t userId,const std::string & action)55 void AccountSubscriber::DispatchEvent(int32_t userId, const std::string &action)
56 {
57     std::lock_guard<std::mutex> lock(userMutex_);
58     auto mapIt = userMap_.find(userId);
59     if (mapIt == userMap_.end()) {
60         return;
61     }
62     for (auto receiver : mapIt->second) {
63         if (receiver) {
64             receiver->OnCommonEventReceived(action);
65         }
66     }
67 }
68 
OnReceiveEvent(const EventFwk::CommonEventData & eventData)69 void AccountSubscriber::OnReceiveEvent(const EventFwk::CommonEventData &eventData)
70 {
71     const AAFwk::Want& want = eventData.GetWant();
72     std::string action = want.GetAction();
73     int32_t userId = eventData.GetCode();
74     MEDIA_LOGI("receive action %{public}s, userId %{public}u", action.c_str(), userId);
75     if (action == EventFwk::CommonEventSupport::COMMON_EVENT_USER_BACKGROUND) {
76         // prevent dead lock caused by NewUnSubscribeCommonEvent and OnReceiveEvent run parallelly.
77         std::shared_ptr<AccountSubscriber> subscriber = shared_from_this();
78         std::thread([subscriber, userId, action]() -> void {
79             MEDIA_LOGI("dispatch event action %{public}s, userId %{public}d", action.c_str(), userId);
80             subscriber->DispatchEvent(userId, action);
81         }).detach();
82     }
83 }
84 
RegisterCommonEventReceiver(int32_t userId,const std::shared_ptr<CommonEventReceiver> & receiver)85 void AccountSubscriber::RegisterCommonEventReceiver(int32_t userId,
86     const std::shared_ptr<CommonEventReceiver> &receiver)
87 {
88     MEDIA_LOGI("receiver is 0x%{public}06" PRIXPTR ", userId %{public}d", FAKE_POINTER(receiver.get()), userId);
89     if (userId < 0 || receiver == nullptr) {
90         return;
91     }
92     std::lock_guard<std::mutex> lock(userMutex_);
93     if (userMap_.empty()) {
94         EventFwk::CommonEventManager::NewSubscribeCommonEvent(instance_);
95         MEDIA_LOGI("first register receiver, SubscribeCommonEvent");
96     }
97     auto mapIt = userMap_.find(userId);
98     if (mapIt == userMap_.end()) {
99         std::vector<std::shared_ptr<CommonEventReceiver>> vct;
100         vct.push_back(receiver);
101         userMap_[userId] = vct;
102         return;
103     }
104     auto receiverIt = std::find(mapIt->second.begin(), mapIt->second.end(),
105         receiver);
106     if (receiverIt != mapIt->second.end()) {
107         MEDIA_LOGI("register fail, receiver already exists");
108         return;
109     }
110     mapIt->second.push_back(receiver);
111 }
112 
UnregisterCommonEventReceiver(int32_t userId,const std::shared_ptr<CommonEventReceiver> & receiver)113 void AccountSubscriber::UnregisterCommonEventReceiver(int32_t userId,
114     const std::shared_ptr<CommonEventReceiver> &receiver)
115 {
116     MEDIA_LOGI("receiver is 0x%{public}06" PRIXPTR ", userId %{public}d", FAKE_POINTER(receiver.get()), userId);
117     if (userId < 0 || receiver == nullptr) {
118         return;
119     }
120     std::lock_guard<std::mutex> lock(userMutex_);
121     auto mapIt = userMap_.find(userId);
122     if (mapIt == userMap_.end()) {
123         MEDIA_LOGI("unregister fail, cannot find userId");
124         return;
125     }
126     auto receiverIt = std::find(mapIt->second.begin(), mapIt->second.end(),
127         receiver);
128     if (receiverIt == mapIt->second.end()) {
129         MEDIA_LOGI("unregister fail, cannot find receiver");
130         return;
131     }
132     mapIt->second.erase(receiverIt);
133     if (mapIt->second.empty()) {
134         userMap_.erase(mapIt);
135         MEDIA_LOGI("remove userId %{public}d, map size %{public}u", userId,
136             static_cast<uint32_t>(userMap_.size()));
137     }
138     if (userMap_.empty()) {
139         EventFwk::CommonEventManager::NewUnSubscribeCommonEvent(instance_);
140         MEDIA_LOGI("user map empty, UnSubscribeCommonEvent");
141     }
142 }
143 } // namespace Media
144 } // namespace OHOS