1 /*
2 **
3 ** Copyright 2017, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 ** http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17
18 #include "perfprofd_binder.h"
19
20 #include <cstdio>
21 #include <cstdlib>
22 #include <fstream>
23 #include <memory>
24 #include <mutex>
25 #include <string>
26 #include <thread>
27
28 #include <inttypes.h>
29 #include <unistd.h>
30
31 #include <android-base/logging.h>
32 #include <android-base/stringprintf.h>
33 #include <android-base/strings.h>
34 #include <binder/BinderService.h>
35 #include <binder/IResultReceiver.h>
36 #include <binder/Status.h>
37 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
38 #include <utils/String16.h>
39 #include <utils/String8.h>
40 #include <utils/Vector.h>
41
42 #include "android/os/BnPerfProfd.h"
43 #include "perfprofd_config.pb.h"
44 #include "perfprofd_record.pb.h"
45
46 #include "config.h"
47 #include "configreader.h"
48 #include "perfprofdcore.h"
49 #include "perfprofd_threaded_handler.h"
50
51 namespace android {
52 namespace perfprofd {
53 namespace binder {
54
55 namespace {
56
57 using Status = ::android::binder::Status;
58
59 class PerfProfdNativeService : public BinderService<PerfProfdNativeService>,
60 public ::android::os::BnPerfProfd,
61 public ThreadedHandler {
62 public:
63 static status_t start();
64 static int Main();
65
getServiceName()66 static char const* getServiceName() { return "perfprofd"; }
67
68 status_t dump(int fd, const Vector<String16> &args) override;
69
70 Status startProfiling(int32_t collectionInterval,
71 int32_t iterations,
72 int32_t process,
73 int32_t samplingPeriod,
74 int32_t samplingFrequency,
75 int32_t sampleDuration,
76 bool stackProfile,
77 bool useElfSymbolizer,
78 bool sendToDropbox) override;
79 Status startProfilingString(const String16& config) override;
80 Status startProfilingProtobuf(const std::vector<uint8_t>& config_proto) override;
81
82 Status stopProfiling() override;
83
84 // Override onTransact so we can handle shellCommand.
85 status_t onTransact(uint32_t _aidl_code,
86 const Parcel& _aidl_data,
87 Parcel* _aidl_reply,
88 uint32_t _aidl_flags = 0) override;
89
90 private:
91 status_t shellCommand(int /*in*/, int out, int err, Vector<String16>& args);
92
93 template <typename ProtoLoaderFn> Status StartProfilingProtobuf(ProtoLoaderFn fn);
94 Status StartProfilingProtobufFd(int fd);
95 };
96
start()97 status_t PerfProfdNativeService::start() {
98 IPCThreadState::self()->disableBackgroundScheduling(true);
99 status_t ret = BinderService<PerfProfdNativeService>::publish();
100 if (ret != android::OK) {
101 return ret;
102 }
103 sp<ProcessState> ps(ProcessState::self());
104 ps->startThreadPool();
105 ps->giveThreadPoolName();
106 return android::OK;
107 }
108
dump(int fd,const Vector<String16> & args)109 status_t PerfProfdNativeService::dump(int fd, const Vector<String16> &args) {
110 auto out = std::fstream(base::StringPrintf("/proc/self/fd/%d", fd));
111 auto print_config = [&out](bool is_profiling, const Config* config) {
112 if (is_profiling) {
113 out << "Profiling with config: " << ConfigReader::ConfigToString(*config);
114 } else {
115 out << "Not actively profiling.";
116 }
117 };
118 RunOnConfig(print_config);
119 out << std::endl;
120
121 return NO_ERROR;
122 }
123
startProfiling(int32_t collectionInterval,int32_t iterations,int32_t process,int32_t samplingPeriod,int32_t samplingFrequency,int32_t sampleDuration,bool stackProfile,bool useElfSymbolizer,bool sendToDropbox)124 Status PerfProfdNativeService::startProfiling(int32_t collectionInterval,
125 int32_t iterations,
126 int32_t process,
127 int32_t samplingPeriod,
128 int32_t samplingFrequency,
129 int32_t sampleDuration,
130 bool stackProfile,
131 bool useElfSymbolizer,
132 bool sendToDropbox) {
133 auto config_fn = [&](ThreadedConfig& config) {
134 config = ThreadedConfig(); // Reset to a default config.
135
136 if (collectionInterval >= 0) {
137 config.collection_interval_in_s = collectionInterval;
138 }
139 if (iterations >= 0) {
140 config.main_loop_iterations = iterations;
141 }
142 if (process >= 0) {
143 config.process = process;
144 }
145 if (samplingPeriod > 0) {
146 config.sampling_period = samplingPeriod;
147 }
148 if (samplingFrequency > 0) {
149 config.sampling_frequency = samplingFrequency;
150 }
151 if (sampleDuration > 0) {
152 config.sample_duration_in_s = sampleDuration;
153 }
154 config.stack_profile = stackProfile;
155 config.use_elf_symbolizer = useElfSymbolizer;
156 config.send_to_dropbox = sendToDropbox;
157 };
158 std::string error_msg;
159 if (!StartProfiling(config_fn, &error_msg)) {
160 return Status::fromExceptionCode(1, error_msg.c_str());
161 }
162 return Status::ok();
163 }
startProfilingString(const String16 & config)164 Status PerfProfdNativeService::startProfilingString(const String16& config) {
165 ConfigReader reader;
166 std::string error_msg;
167 // Split configuration along colon.
168 std::vector<std::string> args = base::Split(String8(config).string(), ":");
169 for (auto& arg : args) {
170 if (!reader.Read(arg, /* fail_on_error */ true, &error_msg)) {
171 std::string tmp = base::StringPrintf("Could not parse %s: %s",
172 arg.c_str(),
173 error_msg.c_str());
174 return Status::fromExceptionCode(1, tmp.c_str());
175 }
176 }
177 auto config_fn = [&](ThreadedConfig& config) {
178 config = ThreadedConfig(); // Reset to a default config.
179 reader.FillConfig(&config);
180 };
181 if (!StartProfiling(config_fn, &error_msg)) {
182 return Status::fromExceptionCode(1, error_msg.c_str());
183 }
184 return Status::ok();
185 }
startProfilingProtobuf(const std::vector<uint8_t> & config_proto)186 Status PerfProfdNativeService::startProfilingProtobuf(const std::vector<uint8_t>& config_proto) {
187 auto proto_loader_fn = [&config_proto](ProfilingConfig& proto_config) {
188 return proto_config.ParseFromArray(config_proto.data(), config_proto.size());
189 };
190 return StartProfilingProtobuf(proto_loader_fn);
191 }
192
193 template <typename ProtoLoaderFn>
StartProfilingProtobuf(ProtoLoaderFn fn)194 Status PerfProfdNativeService::StartProfilingProtobuf(ProtoLoaderFn fn) {
195 ProfilingConfig proto_config;
196 if (!fn(proto_config)) {
197 return binder::Status::fromExceptionCode(2, "Could not read protobuf");
198 }
199 auto config_fn = [&proto_config](ThreadedConfig& config) {
200 config = ThreadedConfig(); // Reset to a default config.
201 ConfigReader::ProtoToConfig(proto_config, &config);
202 };
203 std::string error_msg;
204 if (!StartProfiling(config_fn, &error_msg)) {
205 return Status::fromExceptionCode(1, error_msg.c_str());
206 }
207 return Status::ok();
208 }
209
StartProfilingProtobufFd(int fd)210 Status PerfProfdNativeService::StartProfilingProtobufFd(int fd) {
211 auto proto_loader_fn = [fd](ProfilingConfig& proto_config) {
212 struct IstreamCopyingInputStream : public google::protobuf::io::CopyingInputStream {
213 IstreamCopyingInputStream(int fd_in)
214 : stream(base::StringPrintf("/proc/self/fd/%d", fd_in),
215 std::ios::binary | std::ios::in) {
216 }
217
218 int Read(void* buffer, int size) override {
219 stream.read(reinterpret_cast<char*>(buffer), size);
220 size_t count = stream.gcount();
221 if (count > 0) {
222 return count;
223 }
224 return -1;
225 }
226
227 std::ifstream stream;
228 };
229 std::unique_ptr<IstreamCopyingInputStream> is(new IstreamCopyingInputStream(fd));
230 std::unique_ptr<google::protobuf::io::CopyingInputStreamAdaptor> is_adaptor(
231 new google::protobuf::io::CopyingInputStreamAdaptor(is.get()));
232 return proto_config.ParseFromZeroCopyStream(is_adaptor.get());
233 };
234 return StartProfilingProtobuf(proto_loader_fn);
235 }
236
stopProfiling()237 Status PerfProfdNativeService::stopProfiling() {
238 std::string error_msg;
239 if (!StopProfiling(&error_msg)) {
240 Status::fromExceptionCode(1, error_msg.c_str());
241 }
242 return Status::ok();
243 }
244
shellCommand(int in,int out,int err_fd,Vector<String16> & args)245 status_t PerfProfdNativeService::shellCommand(int in,
246 int out,
247 int err_fd,
248 Vector<String16>& args) {
249 if (android::base::kEnableDChecks) {
250 LOG(VERBOSE) << "Perfprofd::shellCommand";
251
252 for (size_t i = 0, n = args.size(); i < n; i++) {
253 LOG(VERBOSE) << " arg[" << i << "]: '" << String8(args[i]).string() << "'";
254 }
255 }
256
257 auto err_str = std::fstream(base::StringPrintf("/proc/self/fd/%d", err_fd));
258
259 if (args.size() >= 1) {
260 if (args[0] == String16("dump")) {
261 dump(out, args);
262 return OK;
263 } else if (args[0] == String16("startProfiling")) {
264 ConfigReader reader;
265 for (size_t i = 1; i < args.size(); ++i) {
266 std::string error_msg;
267 if (!reader.Read(String8(args[i]).string(), /* fail_on_error */ true, &error_msg)) {
268 err_str << "Could not parse '" << String8(args[i]).string() << "': " << error_msg
269 << std::endl;
270 return BAD_VALUE;
271 }
272 }
273 auto config_fn = [&](ThreadedConfig& config) {
274 config = ThreadedConfig(); // Reset to a default config.
275 reader.FillConfig(&config);
276 };
277 std::string error_msg;
278 if (!StartProfiling(config_fn, &error_msg)) {
279 err_str << error_msg << std::endl;
280 return UNKNOWN_ERROR;
281 }
282 return OK;
283 } else if (args[0] == String16("startProfilingProto")) {
284 if (args.size() < 2) {
285 return BAD_VALUE;
286 }
287 int fd = -1;
288 if (args[1] == String16("-")) {
289 fd = in;
290 } else {
291 // TODO: Implement reading from disk?
292 }
293 if (fd < 0) {
294 err_str << "Bad file descriptor " << args[1] << std::endl;
295 return BAD_VALUE;
296 }
297 binder::Status status = StartProfilingProtobufFd(fd);
298 if (status.isOk()) {
299 return OK;
300 } else {
301 err_str << status.toString8() << std::endl;
302 return UNKNOWN_ERROR;
303 }
304 } else if (args[0] == String16("stopProfiling")) {
305 Status status = stopProfiling();
306 if (status.isOk()) {
307 return OK;
308 } else {
309 err_str << status.toString8() << std::endl;
310 return UNKNOWN_ERROR;
311 }
312 }
313 }
314 return BAD_VALUE;
315 }
316
onTransact(uint32_t _aidl_code,const Parcel & _aidl_data,Parcel * _aidl_reply,uint32_t _aidl_flags)317 status_t PerfProfdNativeService::onTransact(uint32_t _aidl_code,
318 const Parcel& _aidl_data,
319 Parcel* _aidl_reply,
320 uint32_t _aidl_flags) {
321 switch (_aidl_code) {
322 case IBinder::SHELL_COMMAND_TRANSACTION: {
323 int in = _aidl_data.readFileDescriptor();
324 int out = _aidl_data.readFileDescriptor();
325 int err = _aidl_data.readFileDescriptor();
326 int argc = _aidl_data.readInt32();
327 Vector<String16> args;
328 for (int i = 0; i < argc && _aidl_data.dataAvail() > 0; i++) {
329 args.add(_aidl_data.readString16());
330 }
331 sp<IBinder> unusedCallback;
332 sp<IResultReceiver> resultReceiver;
333 status_t status;
334 if ((status = _aidl_data.readNullableStrongBinder(&unusedCallback)) != OK)
335 return status;
336 if ((status = _aidl_data.readNullableStrongBinder(&resultReceiver)) != OK)
337 return status;
338 status = shellCommand(in, out, err, args);
339 if (resultReceiver != nullptr) {
340 resultReceiver->send(status);
341 }
342 return OK;
343 }
344
345 default:
346 return ::android::os::BnPerfProfd::onTransact(
347 _aidl_code, _aidl_data, _aidl_reply, _aidl_flags);
348 }
349 }
350
351 } // namespace
352
Main()353 int Main() {
354 {
355 struct DummyConfig : public Config {
356 void Sleep(size_t seconds) override {}
357 bool IsProfilingEnabled() const override { return false; }
358 };
359 DummyConfig config;
360 GlobalInit(config.perf_path);
361 }
362
363 android::status_t ret;
364 if ((ret = PerfProfdNativeService::start()) != android::OK) {
365 LOG(ERROR) << "Unable to start InstalldNativeService: %d" << ret;
366 exit(1);
367 }
368
369 android::IPCThreadState::self()->joinThreadPool();
370
371 LOG(INFO) << "Exiting perfprofd";
372 return 0;
373 }
374
375 } // namespace binder
376 } // namespace perfprofd
377 } // namespace android
378