1/*
2 * Copyright (c) 2023 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 "running_lock_impl.h"
17
18#include "hdf_base.h"
19#include "power_hdf_log.h"
20#include "system_operation.h"
21
22namespace OHOS {
23namespace HDI {
24namespace Power {
25namespace V1_2 {
26namespace {
27const std::string RUNNINGLOCK_TAG_BACKGROUND_INVALID = "OHOS.RunningLock.Background.Invalid";
28const std::string RUNNINGLOCK_TAG_BACKGROUND_PHONE = "OHOS.RunningLock.Background.Phone";
29const std::string RUNNINGLOCK_TAG_BACKGROUND_NOTIFICATION = "OHOS.RunningLock.Background.Notification";
30const std::string RUNNINGLOCK_TAG_BACKGROUND_AUDIO = "OHOS.RunningLock.Background.Audio";
31const std::string RUNNINGLOCK_TAG_BACKGROUND_SPORT = "OHOS.RunningLock.Background.Sport";
32const std::string RUNNINGLOCK_TAG_BACKGROUND_NAVIGATION = "OHOS.RunningLock.Background.Navigation";
33const std::string RUNNINGLOCK_TAG_BACKGROUND_TASK = "OHOS.RunningLock.Background.Task";
34const std::string RUNNINGLOCK_TAG_BACKGROUND_PHONEEXT = "OHOS.RunningLock.Background.PhoneExt";
35constexpr int32_t DEFAULT_TIMEOUT = 3000;
36} // namespace
37std::mutex RunningLockImpl::mutex_;
38int32_t RunningLockImpl::defaultTimeOutMs_ = DEFAULT_TIMEOUT;
39std::unique_ptr<RunningLockTimerHandler> RunningLockImpl::timerHandler_ = nullptr;
40std::map<RunningLockType, std::shared_ptr<RunningLockCounter>> RunningLockImpl::lockCounters_ = {};
41sptr<IPowerRunningLockCallback> g_iPowerRunningLockCallback = nullptr;
42
43int32_t RunningLockImpl::Hold(const RunningLockInfo &info, PowerHdfState state,
44    uint64_t lockid, const std::string &bundleName)
45{
46    std::lock_guard<std::mutex> lock(mutex_);
47    if (info.name.empty()) {
48        HDF_LOGW("Runninglock hold failed, name is empty");
49        return HDF_ERR_INVALID_PARAM;
50    }
51    RunningLockInfo filledInfo = FillRunningLockInfo(info);
52    if (!IsValidType(filledInfo.type, state)) {
53        HDF_LOGW("Runninglock hold failed, type=%{public}d or state=%{public}d is invalid", filledInfo.type, state);
54        return HDF_ERR_INVALID_PARAM;
55    }
56    auto iterator = lockCounters_.find(filledInfo.type);
57    if (iterator == lockCounters_.end()) {
58        auto pair = lockCounters_.emplace(filledInfo.type,
59            std::make_shared<RunningLockCounter>(filledInfo.type, GetRunningLockTag(filledInfo.type)));
60        if (pair.second == false) {
61            HDF_LOGW("Runninglock hold failed, type=%{public}d is not in lockCounters", filledInfo.type);
62            return HDF_FAILURE;
63        }
64        iterator = pair.first;
65    }
66    std::shared_ptr<RunningLockCounter> lockCounter = iterator->second;
67    if (lockCounter->Increase(filledInfo) != HDF_SUCCESS) {
68        return HDF_FAILURE;
69    }
70    if (filledInfo.timeoutMs > 0) {
71        if (timerHandler_ == nullptr) {
72            timerHandler_ = std::make_unique<RunningLockTimerHandler>();
73        }
74        std::function<void()> unholdFunc = std::bind(&RunningLockImpl::Unhold, filledInfo, lockid, bundleName);
75        timerHandler_->RegisterRunningLockTimer(filledInfo, unholdFunc);
76    }
77    RunningLockImpl::NotifyChanged(filledInfo, lockid, bundleName, "DUBAI_TAG_RUNNINGLOCK_ADD");
78    return HDF_SUCCESS;
79}
80
81int32_t RunningLockImpl::Unhold(const RunningLockInfo &info,
82    uint64_t lockid, const std::string &bundleName)
83{
84    std::lock_guard<std::mutex> lock(mutex_);
85    if (info.name.empty()) {
86        HDF_LOGW("Runninglock unhold failed, name is empty");
87        return HDF_ERR_INVALID_PARAM;
88    }
89    RunningLockInfo filledInfo = FillRunningLockInfo(info);
90    if (!IsValidType(filledInfo.type)) {
91        HDF_LOGW("Runninglock unhold failed, type=%{public}d is invalid", filledInfo.type);
92        return HDF_ERR_INVALID_PARAM;
93    }
94    auto iterator = lockCounters_.find(filledInfo.type);
95    if (iterator == lockCounters_.end()) {
96        HDF_LOGW("type=%{public}d is not in lockCounters, no need to unhold", filledInfo.type);
97        return HDF_ERR_NOT_SUPPORT;
98    }
99    if (timerHandler_ != nullptr) {
100        timerHandler_->UnregisterRunningLockTimer(filledInfo);
101    }
102    std::shared_ptr<RunningLockCounter> lockCounter = iterator->second;
103    int32_t status = lockCounter->Decrease(filledInfo);
104    if (status == HDF_SUCCESS) {
105        RunningLockImpl::NotifyChanged(filledInfo, lockid, bundleName, "DUBAI_TAG_RUNNINGLOCK_REMOVE");
106    }
107    return status;
108}
109
110int32_t RunningLockImpl::HoldLock(const RunningLockInfo &info, PowerHdfState state,
111    uint64_t lockid, const std::string &bundleName)
112{
113    std::lock_guard<std::mutex> lock(mutex_);
114    if (!IsValidType(info.type, state)) {
115        HDF_LOGW("HoldLock failed, type=%{public}d or state=%{public}d is invalid", info.type, state);
116        return HDF_ERR_INVALID_PARAM;
117    }
118    int32_t status = SystemOperation::WriteWakeLock(GetRunningLockTagInner(info.type));
119    return status;
120}
121
122int32_t RunningLockImpl::UnholdLock(const RunningLockInfo &info,
123    uint64_t lockid, const std::string &bundleName)
124{
125    std::lock_guard<std::mutex> lock(mutex_);
126    if (!IsValidType(info.type)) {
127        HDF_LOGW("UnholdLock failed, type=%{public}d is invalid", info.type);
128        return HDF_ERR_INVALID_PARAM;
129    }
130    int32_t status = SystemOperation::WriteWakeUnlock(GetRunningLockTagInner(info.type));
131    return status;
132}
133
134void RunningLockImpl::Clean()
135{
136    HDF_LOGI("start to clear running locks");
137    std::lock_guard<std::mutex> lock(mutex_);
138    if (timerHandler_ != nullptr) {
139        timerHandler_->Clean();
140    }
141
142    for (auto &iter : lockCounters_) {
143        HDF_LOGI("clear running lock type %{public}d", iter.first);
144        SystemOperation::WriteWakeUnlock(GetRunningLockTag(iter.first));
145        iter.second->Clean();
146    }
147    lockCounters_.clear();
148}
149
150uint32_t RunningLockImpl::GetCount(RunningLockType type)
151{
152    std::lock_guard<std::mutex> lock(mutex_);
153    uint32_t count = 0;
154    auto iterator = lockCounters_.find(type);
155    if (iterator != lockCounters_.end()) {
156        count = iterator->second->GetCount();
157    }
158    return count;
159}
160
161void RunningLockImpl::SetDefaultTimeOutMs(int32_t timeOutMs)
162{
163    std::lock_guard<std::mutex> lock(mutex_);
164    if (timeOutMs > 0) {
165        defaultTimeOutMs_ = timeOutMs;
166    }
167}
168
169bool RunningLockImpl::IsValidType(RunningLockType type, PowerHdfState state)
170{
171    switch (state) {
172        case PowerHdfState::SLEEP:
173        case PowerHdfState::INACTIVE:
174        case PowerHdfState::AWAKE:
175            return type == RUNNINGLOCK_BACKGROUND_PHONE || type == RUNNINGLOCK_BACKGROUND_NOTIFICATION ||
176                type == RUNNINGLOCK_BACKGROUND_AUDIO || type == RUNNINGLOCK_BACKGROUND_SPORT ||
177                type == RUNNINGLOCK_BACKGROUND_NAVIGATION || type == RUNNINGLOCK_BACKGROUND_TASK;
178        default:
179            break;
180    }
181    return false;
182}
183
184RunningLockInfo RunningLockImpl::FillRunningLockInfo(const RunningLockInfo &info)
185{
186    struct RunningLockInfo filledInfo {
187        .name = info.name,
188        .type = info.type,
189        .timeoutMs = info.timeoutMs,
190        .pid = info.pid,
191        .uid = info.uid,
192    };
193    if (static_cast<uint32_t>(filledInfo.type) == 0) {
194        filledInfo.type = RunningLockType::RUNNINGLOCK_BACKGROUND_TASK;
195    }
196    if (filledInfo.timeoutMs == 0) {
197        filledInfo.timeoutMs = defaultTimeOutMs_;
198    }
199    return filledInfo;
200}
201
202std::string RunningLockImpl::GetRunningLockTag(RunningLockType type)
203{
204    switch (type) {
205        case RunningLockType::RUNNINGLOCK_BACKGROUND_PHONE:
206            return RUNNINGLOCK_TAG_BACKGROUND_PHONEEXT;
207        case RunningLockType::RUNNINGLOCK_BACKGROUND_NOTIFICATION:
208            return RUNNINGLOCK_TAG_BACKGROUND_NOTIFICATION;
209        case RunningLockType::RUNNINGLOCK_BACKGROUND_AUDIO:
210            return RUNNINGLOCK_TAG_BACKGROUND_AUDIO;
211        case RunningLockType::RUNNINGLOCK_BACKGROUND_SPORT:
212            return RUNNINGLOCK_TAG_BACKGROUND_SPORT;
213        case RunningLockType::RUNNINGLOCK_BACKGROUND_NAVIGATION:
214            return RUNNINGLOCK_TAG_BACKGROUND_NAVIGATION;
215        case RunningLockType::RUNNINGLOCK_BACKGROUND_TASK:
216            return RUNNINGLOCK_TAG_BACKGROUND_TASK;
217        default: {
218            HDF_LOGE("type=%{public}d is invalid, there is no corresponding tag", type);
219            return RUNNINGLOCK_TAG_BACKGROUND_INVALID;
220        }
221    }
222}
223
224std::string RunningLockImpl::GetRunningLockTagInner(RunningLockType type)
225{
226    switch (type) {
227        case RunningLockType::RUNNINGLOCK_BACKGROUND_PHONE:
228            return RUNNINGLOCK_TAG_BACKGROUND_PHONE;
229        case RunningLockType::RUNNINGLOCK_BACKGROUND_NOTIFICATION:
230            return RUNNINGLOCK_TAG_BACKGROUND_NOTIFICATION;
231        case RunningLockType::RUNNINGLOCK_BACKGROUND_AUDIO:
232            return RUNNINGLOCK_TAG_BACKGROUND_AUDIO;
233        case RunningLockType::RUNNINGLOCK_BACKGROUND_SPORT:
234            return RUNNINGLOCK_TAG_BACKGROUND_SPORT;
235        case RunningLockType::RUNNINGLOCK_BACKGROUND_NAVIGATION:
236            return RUNNINGLOCK_TAG_BACKGROUND_NAVIGATION;
237        case RunningLockType::RUNNINGLOCK_BACKGROUND_TASK:
238            return RUNNINGLOCK_TAG_BACKGROUND_TASK;
239        default: {
240            HDF_LOGE("type=%{public}d is invalid, there is no corresponding tag", type);
241            return RUNNINGLOCK_TAG_BACKGROUND_INVALID;
242        }
243    }
244}
245
246void RunningLockImpl::RegisterRunningLockCallback(const sptr<IPowerRunningLockCallback>
247        &iPowerRunningLockCallback)
248{
249    std::lock_guard<std::mutex> lock(mutex_);
250    g_iPowerRunningLockCallback = iPowerRunningLockCallback;
251    HDF_LOGI("RegisterRunningLockCallback success");
252}
253
254void RunningLockImpl::UnRegisterRunningLockCallback()
255{
256    std::lock_guard<std::mutex> lock(mutex_);
257    g_iPowerRunningLockCallback = nullptr;
258    HDF_LOGI("UnRegisterRunningLockCallback success");
259}
260
261void RunningLockImpl::NotifyChanged(const RunningLockInfo &info,
262    const uint64_t &lockid, const std::string &bundleName, const std::string &tag)
263{
264    int32_t pid = info.pid;
265    int32_t uid = info.uid;
266    int32_t type = static_cast<int32_t>(info.type);
267    std::string name = info.name;
268    auto now = std::chrono::system_clock::now();
269    auto timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
270    std::string message;
271    message.append("LOCKID=").append(std::to_string(lockid))
272            .append(" PID=").append(std::to_string(pid))
273            .append(" UID=").append(std::to_string(uid))
274            .append(" TYPE=").append(std::to_string(type))
275            .append(" NAME=").append(name)
276            .append(" BUNDLENAME=").append(bundleName)
277            .append(" TAG=").append(tag)
278            .append(" TIMESTAMP=").append(std::to_string(timestamp));
279    HDF_LOGI("runninglock message: %{public}s, timeout: %{public}d", message.c_str(), info.timeoutMs);
280    if (g_iPowerRunningLockCallback != nullptr) {
281        g_iPowerRunningLockCallback->HandleRunningLockMessage(message);
282    }
283}
284
285} // namespace V1_2
286} // namespace Power
287} // namespace HDI
288} // namespace OHOS
289