1/*
2 * Copyright (c) 2023-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 "app_debug_manager.h"
17
18#include "hilog_tag_wrapper.h"
19#include "ipc_types.h"
20
21namespace OHOS {
22namespace AppExecFwk {
23int32_t AppDebugManager::RegisterAppDebugListener(const sptr<IAppDebugListener> &listener)
24{
25    TAG_LOGD(AAFwkTag::APPMGR, "called");
26    if (listener == nullptr) {
27        TAG_LOGE(AAFwkTag::APPMGR, "null listener");
28        return ERR_INVALID_DATA;
29    }
30
31    std::unique_lock<std::mutex> lock(mutex_);
32    const auto &finder =
33        std::find_if(listeners_.begin(), listeners_.end(), [&listener](const sptr<IAppDebugListener> &element) {
34            if (element != nullptr && listener != nullptr) {
35                return element->AsObject() == listener->AsObject();
36            }
37            return false;
38        });
39    if (finder == listeners_.end()) {
40        listeners_.emplace(listener);
41    }
42
43    if (!debugInfos_.empty()) {
44        listener->OnAppDebugStarted(debugInfos_);
45    }
46    return ERR_OK;
47}
48
49int32_t AppDebugManager::UnregisterAppDebugListener(const sptr<IAppDebugListener> &listener)
50{
51    TAG_LOGD(AAFwkTag::APPMGR, "called");
52    if (listener == nullptr) {
53        TAG_LOGE(AAFwkTag::APPMGR, "null listener");
54        return ERR_INVALID_DATA;
55    }
56
57    std::unique_lock<std::mutex> lock(mutex_);
58    const auto &finder =
59        std::find_if(listeners_.begin(), listeners_.end(), [&listener](const sptr<IAppDebugListener> &element) {
60            if (element != nullptr && listener != nullptr) {
61                return element->AsObject() == listener->AsObject();
62            }
63            return false;
64        });
65    if (finder != listeners_.end()) {
66        listeners_.erase(finder);
67    }
68    return ERR_OK;
69}
70
71void AppDebugManager::StartDebug(const std::vector<AppDebugInfo> &infos)
72{
73    TAG_LOGD(AAFwkTag::APPMGR, "called");
74    std::lock_guard<std::mutex> lock(mutex_);
75    std::vector<AppDebugInfo> incrementInfos;
76    GetIncrementAppDebugInfos(infos, incrementInfos);
77    if (incrementInfos.empty()) {
78        return;
79    }
80
81    for (const auto &listener : listeners_) {
82        if (listener == nullptr) {
83            continue;
84        }
85        listener->OnAppDebugStarted(incrementInfos);
86    }
87}
88
89void AppDebugManager::StopDebug(const std::vector<AppDebugInfo> &infos)
90{
91    TAG_LOGD(AAFwkTag::APPMGR, "called");
92    std::lock_guard<std::mutex> lock(mutex_);
93    std::vector<AppDebugInfo> debugInfos;
94    for (auto &it : infos) {
95        auto isExist = [this, it](const AppDebugInfo &info) {
96            return (info.bundleName == it.bundleName && info.pid == it.pid &&
97                info.uid == it.uid && info.isDebugStart == it.isDebugStart);
98        };
99
100        auto finder = std::find_if(debugInfos_.begin(), debugInfos_.end(), isExist);
101        if (finder != debugInfos_.end()) {
102            debugInfos_.erase(finder);
103            debugInfos.emplace_back(it);
104        }
105    }
106
107    if (!debugInfos.empty()) {
108        for (const auto &listener : listeners_) {
109            if (listener == nullptr) {
110                continue;
111            }
112            listener->OnAppDebugStoped(debugInfos);
113        }
114    }
115}
116
117bool AppDebugManager::IsAttachDebug(const std::string &bundleName)
118{
119    std::lock_guard<std::mutex> lock(mutex_);
120    for (auto &iter : debugInfos_) {
121        if (iter.bundleName == bundleName && !iter.isDebugStart) {
122            return true;
123        }
124    }
125    return false;
126}
127
128void AppDebugManager::GetIncrementAppDebugInfos(
129    const std::vector<AppDebugInfo> &infos, std::vector<AppDebugInfo> &incrementInfos)
130{
131    for (auto &it : infos) {
132        auto isExist = [this, it](const AppDebugInfo &info) {
133            return (info.bundleName == it.bundleName && info.pid == it.pid && info.uid == it.uid);
134        };
135
136        auto finder = std::find_if(debugInfos_.begin(), debugInfos_.end(), isExist);
137        if (finder == debugInfos_.end()) {
138            incrementInfos.emplace_back(it);
139        } else {
140            if (!finder->isDebugStart && it.isDebugStart) {
141                finder->isDebugStart = it.isDebugStart;
142            }
143        }
144    }
145
146    debugInfos_.insert(debugInfos_.end(), incrementInfos.begin(), incrementInfos.end());
147}
148
149void AppDebugManager::RemoveAppDebugInfo(const AppDebugInfo &info)
150{
151    TAG_LOGD(AAFwkTag::APPMGR, "called");
152    std::lock_guard<std::mutex> lock(mutex_);
153    auto isExist = [this, info](const AppDebugInfo &debugInfo) {
154        return (debugInfo.bundleName == info.bundleName && debugInfo.pid == info.pid &&
155                debugInfo.uid == info.uid && debugInfo.isDebugStart == info.isDebugStart);
156    };
157
158    auto finder = std::find_if(debugInfos_.begin(), debugInfos_.end(), isExist);
159    if (finder == debugInfos_.end()) {
160        return;
161    }
162    debugInfos_.erase(finder);
163
164    std::vector<AppDebugInfo> debugInfos;
165    debugInfos.emplace_back(info);
166    for (const auto &listener : listeners_) {
167        if (listener == nullptr) {
168            continue;
169        }
170        listener->OnAppDebugStoped(debugInfos);
171    }
172}
173} // namespace AppExecFwk
174} // namespace OHOS
175