1 /*
2  * Copyright (c) 2022-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 "property/rs_property_trace.h"
17 
18 #include <climits>
19 #include <cstdarg>
20 #include <fstream>
21 #include <regex>
22 #include <securec.h>
23 #include <sys/time.h>
24 #include "directory_ex.h"
25 
26 #include "rs_trace.h"
27 #include "platform/common/rs_log.h"
28 
29 namespace OHOS {
30 namespace Rosen {
31 const std::string ANIMATION_LOG_PATH = "/etc/rosen/";
32 const std::string CONFIG_FILE_NAME = "property.config";
33 const std::string COLON_SEPARATOR = ":";
34 const std::string COMMA_SEPARATOR = ",";
35 const std::string SEMICOLON_SEPARATOR = ";";
36 const std::string NODE_ID_TAG = "ID";
37 const std::string NODE_NAME_TAG = "NODE_NAME:";
38 const std::string ALL_NEED_TAG = "all";
39 static constexpr int MIN_INFO_SIZE = 2;
40 RSPropertyTrace RSPropertyTrace::instance_;
41 
PropertiesDisplayByTrace(const NodeId & id,const std::shared_ptr<RSObjAbsGeometry> & boundsGeometry)42 void RSPropertyTrace::PropertiesDisplayByTrace(const NodeId& id,
43     const std::shared_ptr<RSObjAbsGeometry>& boundsGeometry)
44 {
45     if (IsNeedPropertyTrace(id)) {
46         auto rectI = boundsGeometry->GetAbsRect();
47         AddTraceFlag(std::to_string(id) + " Geometry Rect: " + rectI.ToString());
48     }
49 }
50 
TracePropertiesByNodeName(const NodeId & id,const std::string & nodeName,const RSProperties & properties)51 void RSPropertyTrace::TracePropertiesByNodeName(const NodeId& id, const std::string& nodeName,
52     const RSProperties& properties)
53 {
54     if (!IsNeedPropertyTrace(nodeName)) {
55         return;
56     }
57     std::string content = "NodeId:[" + std::to_string(id) + "], NodeName:[" + nodeName + "]" +
58         " Geometry Rect: " + (properties.GetBoundsGeometry())->GetAbsRect().ToString() +
59         " Bounds Rect: " + properties.GetBoundsRect().ToString() +
60         " Frame Rect: " + properties.GetFrameRect().ToString() +
61         " Alpha: " + std::to_string(properties.GetAlpha()) +
62         " Visible: " + std::to_string(properties.GetVisible());
63     AddTraceFlag(content);
64 }
65 
RefreshNodeTraceInfo()66 void RSPropertyTrace::RefreshNodeTraceInfo()
67 {
68     if (IsNeedRefreshConfig()) {
69         InitNodeAndPropertyInfo();
70     }
71 }
72 
AddTraceFlag(const std::string & str)73 void RSPropertyTrace::AddTraceFlag(const std::string& str)
74 {
75     ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, str.c_str());
76     ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
77 }
78 
SplitStringBySeparator(const std::string & str,const std::string & separator)79 std::vector<std::string> SplitStringBySeparator(const std::string& str,
80     const std::string& separator)
81 {
82     std::regex re(separator);
83     std::sregex_token_iterator pos(str.begin(), str.end(), re, -1);
84     std::sregex_token_iterator endPos;
85     std::vector<std::string> result;
86     while (pos != endPos) {
87         result.emplace_back(*pos++);
88     }
89     return result;
90 }
91 
InitNodeAndPropertyInfo()92 void RSPropertyTrace::InitNodeAndPropertyInfo()
93 {
94     std::string configFilePath = ANIMATION_LOG_PATH + CONFIG_FILE_NAME;
95     std::string newpath;
96     if (!PathToRealPath(configFilePath, newpath)) {
97         ROSEN_LOGE("Render node trace config file is nullptr!");
98         return;
99     }
100     std::ifstream configFile(newpath);
101     if (!configFile.is_open()) {
102         ROSEN_LOGE("Open render node trace config file failed!");
103         return;
104     }
105 
106     std::string info;
107     while (std::getline(configFile, info)) {
108         if (DealNodeNameConfig(info)) {
109             continue;
110         }
111         std::vector<std::string> infos = SplitStringBySeparator(info, SEMICOLON_SEPARATOR);
112         if (infos.empty()) {
113             continue;
114         }
115         DealConfigInputInfo(infos.front());
116     }
117     configFile.close();
118 }
119 
DealConfigInputInfo(const std::string & info)120 void RSPropertyTrace::DealConfigInputInfo(const std::string& info)
121 {
122     std::vector<std::string> splitResult = SplitStringBySeparator(info, COLON_SEPARATOR);
123     if (splitResult.size() != MIN_INFO_SIZE) {
124         ROSEN_LOGE("Render node trace config file size error!");
125         return;
126     }
127 
128     std::string tag = splitResult.front();
129     if (tag == NODE_ID_TAG) {
130         std::vector<std::string> nodeIds =
131             SplitStringBySeparator(splitResult.back(), COMMA_SEPARATOR);
132         for (std::string nodeId : nodeIds) {
133             if (nodeId == ALL_NEED_TAG) {
134                 needWriteAllNode_ = true;
135                 return;
136             }
137             auto id = atoll(nodeId.c_str());
138             nodeIdSet_.insert(id);
139         }
140     }
141 }
142 
DealNodeNameConfig(const std::string & info)143 bool RSPropertyTrace::DealNodeNameConfig(const std::string& info)
144 {
145     if (info.compare(0, NODE_NAME_TAG.size(), NODE_NAME_TAG) != 0) {
146         return false;
147     }
148 
149     if (info == NODE_NAME_TAG) {
150         needTraceAllNode_ = true;
151         return true;
152     }
153 
154     needTraceAllNode_ = false;
155     std::vector<std::string> nodeNames = SplitStringBySeparator(info.substr(NODE_NAME_TAG.size()), COMMA_SEPARATOR);
156     for (std::string nodeName : nodeNames) {
157         nodeNameSet_.insert(nodeName);
158     }
159     return true;
160 }
161 
ClearNodeAndPropertyInfo()162 void RSPropertyTrace::ClearNodeAndPropertyInfo()
163 {
164     nodeIdSet_.clear();
165     nodeNameSet_.clear();
166 }
167 
IsNeedRefreshConfig()168 bool RSPropertyTrace::IsNeedRefreshConfig()
169 {
170     struct stat configFileStatus = {};
171     std::string configFilePath = ANIMATION_LOG_PATH + CONFIG_FILE_NAME;
172     if (stat(configFilePath.c_str(), &configFileStatus)) {
173         return false;
174     }
175 
176     std::string curent(ctime(&configFileStatus.st_mtime));
177     if (curent != propertyFileLastModifyTime) {
178         propertyFileLastModifyTime = curent;
179         return true;
180     }
181     return false;
182 }
183 
IsNeedPropertyTrace(const NodeId & id)184 bool RSPropertyTrace::IsNeedPropertyTrace(const NodeId& id)
185 {
186     auto itrn = nodeIdSet_.find(id);
187     if (itrn == nodeIdSet_.end() && !needWriteAllNode_) {
188         return false;
189     }
190     return true;
191 }
192 
IsNeedPropertyTrace(const std::string & nodeName)193 bool RSPropertyTrace::IsNeedPropertyTrace(const std::string& nodeName)
194 {
195     if (nodeName == "") {
196         return false;
197     }
198     return needTraceAllNode_ || (nodeNameSet_.find(nodeName) != nodeNameSet_.end());
199 }
200 } // namespace Rosen
201 } // namespace OHOS
202