1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <android-base/file.h>
18 #include <android-base/logging.h>
19 #include <android-base/stringprintf.h>
20 
21 #include "AtraceDevice.h"
22 
23 namespace android {
24 namespace hardware {
25 namespace atrace {
26 namespace V1_0 {
27 namespace implementation {
28 
29 using ::android::hardware::atrace::V1_0::Status;
30 using ::android::hardware::atrace::V1_0::TracingCategory;
31 
32 struct TracingConfig {
33     std::string description;
34     // path and if error on failure
35     std::vector<std::pair<std::string, bool>> paths;
36 };
37 
38 // This is a map stores categories and their tracefs event name with required flags
39 const std::map<std::string, TracingConfig> kTracingMap = {
40         {
41                 "gfx",
42                 {"Graphics",
43                  {{"mdss", false},
44                   {"sde", false},
45                   {"dpu", false},
46                   {"g2d", false},
47                   {"mali", false}}},
48         },
49         {
50                 "memory",
51                 {"Memory", {{"fastrpc/fastrpc_dma_stat", false}, {"dmabuf_heap", false}}},
52         },
53         {
54                 "ion",
55                 {"ION Allocation", {{"kmem/ion_alloc_buffer_start", false}}},
56         },
57         {
58                 "sched",
59                 {"CPU Scheduling and Trustzone", {{"scm", false}, {"systrace", false}}},
60         },
61         {
62                 "freq",
63                 {"CPU Frequency and System Clock", {{"msm_bus", false}}},
64         },
65         {
66                 "thermal_tj",
67                 {"Tj power limits and frequency",
68                  {{"lmh/lmh_dcvs_freq", false},
69                   {"thermal_exynos", false},
70                   {"thermal_exynos_gpu", false}}},
71         },
72 };
73 
74 // Methods from ::android::hardware::atrace::V1_0::IAtraceDevice follow.
75 Return<void> AtraceDevice::listCategories(listCategories_cb _hidl_cb) {
76     hidl_vec<TracingCategory> categories;
77     categories.resize(kTracingMap.size());
78     std::size_t i = 0;
79     for (auto &c : kTracingMap) {
80         categories[i].name = c.first;
81         categories[i].description = c.second.description;
82         i++;
83     }
84     _hidl_cb(categories);
85     return Void();
86 }
87 
88 AtraceDevice::AtraceDevice() {
89     struct stat st;
90 
91     mTracefsEventRoot = "/sys/kernel/tracing/events/";
92     if (stat(mTracefsEventRoot.c_str(), &st) != 0) {
93         mTracefsEventRoot = "/sys/kernel/debug/tracing/events/";
94         CHECK(stat(mTracefsEventRoot.c_str(), &st) == 0) << "tracefs must be mounted at either"
95                                                             "/sys/kernel/tracing or "
96                                                             "/sys/kernel/debug/tracing";
97     }
98 }
99 
100 Return<::android::hardware::atrace::V1_0::Status> AtraceDevice::enableCategories(
101         const hidl_vec<hidl_string> &categories) {
102     if (!categories.size()) {
103         return Status::ERROR_INVALID_ARGUMENT;
104     }
105 
106     for (auto &c : categories) {
107         if (kTracingMap.count(c)) {
108             for (auto &p : kTracingMap.at(c).paths) {
109                 std::string tracefs_event_enable_path = android::base::StringPrintf(
110                         "%s%s/enable", mTracefsEventRoot.c_str(), p.first.c_str());
111                 if (!android::base::WriteStringToFile("1", tracefs_event_enable_path)) {
112                     LOG(ERROR) << "Failed to enable tracing on: " << tracefs_event_enable_path;
113                     if (p.second) {
114                         // disable before return
115                         disableAllCategories();
116                         return Status::ERROR_TRACING_POINT;
117                     }
118                 }
119             }
120         } else {
121             return Status::ERROR_INVALID_ARGUMENT;
122         }
123     }
124     return Status::SUCCESS;
125 }
126 
127 Return<::android::hardware::atrace::V1_0::Status> AtraceDevice::disableAllCategories() {
128     auto ret = Status::SUCCESS;
129 
130     for (auto &c : kTracingMap) {
131         for (auto &p : c.second.paths) {
132             std::string tracefs_event_enable_path = android::base::StringPrintf(
133                     "%s%s/enable", mTracefsEventRoot.c_str(), p.first.c_str());
134             if (!android::base::WriteStringToFile("0", tracefs_event_enable_path)) {
135                 LOG(ERROR) << "Failed to disable tracing on: " << tracefs_event_enable_path;
136                 if (p.second) {
137                     ret = Status::ERROR_TRACING_POINT;
138                 }
139             }
140         }
141     }
142     return ret;
143 }
144 
145 }  // namespace implementation
146 }  // namespace V1_0
147 }  // namespace atrace
148 }  // namespace hardware
149 }  // namespace android
150