blob: a00ca142704dddc75b2ffbf88f502439fe804b1f [file] [log] [blame]
Andreas Gampec445aff2017-12-27 10:44:42 -08001/*
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
Andreas Gampe28e31382018-03-19 16:24:14 -070020#include <cstdio>
Andreas Gampec445aff2017-12-27 10:44:42 -080021#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>
Andreas Gampe9301b6f2018-04-27 15:15:34 -070033#include <android-base/strings.h>
Andreas Gampec445aff2017-12-27 10:44:42 -080034#include <binder/BinderService.h>
35#include <binder/IResultReceiver.h>
36#include <binder/Status.h>
Andreas Gampe9590c642017-12-27 10:57:34 -080037#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
Andreas Gampec445aff2017-12-27 10:44:42 -080038#include <utils/String16.h>
39#include <utils/String8.h>
40#include <utils/Vector.h>
41
42#include "android/os/BnPerfProfd.h"
Andreas Gampe9590c642017-12-27 10:57:34 -080043#include "perfprofd_config.pb.h"
Andreas Gampe0c09e0e2018-03-13 16:04:01 -070044#include "perfprofd_record.pb.h"
Andreas Gampec445aff2017-12-27 10:44:42 -080045
46#include "config.h"
Andreas Gampef73ddfa2018-03-29 14:52:57 -070047#include "configreader.h"
Andreas Gampec445aff2017-12-27 10:44:42 -080048#include "perfprofdcore.h"
Andreas Gampeb019ddc2018-04-02 10:58:32 -070049#include "perfprofd_threaded_handler.h"
Andreas Gampec445aff2017-12-27 10:44:42 -080050
51namespace android {
52namespace perfprofd {
53namespace binder {
54
Andreas Gampeb019ddc2018-04-02 10:58:32 -070055namespace {
56
Andreas Gampec445aff2017-12-27 10:44:42 -080057using Status = ::android::binder::Status;
58
Andreas Gampec445aff2017-12-27 10:44:42 -080059class PerfProfdNativeService : public BinderService<PerfProfdNativeService>,
Andreas Gampeb019ddc2018-04-02 10:58:32 -070060 public ::android::os::BnPerfProfd,
61 public ThreadedHandler {
Andreas Gampec445aff2017-12-27 10:44:42 -080062 public:
63 static status_t start();
64 static int Main();
65
66 static char const* getServiceName() { return "perfprofd"; }
67
68 status_t dump(int fd, const Vector<String16> &args) override;
69
Andreas Gampe5a7181b2018-04-20 17:11:22 -070070 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;
Andreas Gampe9301b6f2018-04-27 15:15:34 -070079 Status startProfilingString(const String16& config) override;
Andreas Gampe9590c642017-12-27 10:57:34 -080080 Status startProfilingProtobuf(const std::vector<uint8_t>& config_proto) override;
Andreas Gampec445aff2017-12-27 10:44:42 -080081
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
Andreas Gampe9590c642017-12-27 10:57:34 -080093 template <typename ProtoLoaderFn> Status StartProfilingProtobuf(ProtoLoaderFn fn);
94 Status StartProfilingProtobufFd(int fd);
Andreas Gampec445aff2017-12-27 10:44:42 -080095};
96
97status_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
109status_t PerfProfdNativeService::dump(int fd, const Vector<String16> &args) {
110 auto out = std::fstream(base::StringPrintf("/proc/self/fd/%d", fd));
111 out << "Nothing to log, yet!" << std::endl;
112
113 return NO_ERROR;
114}
115
Andreas Gampe5a7181b2018-04-20 17:11:22 -0700116Status PerfProfdNativeService::startProfiling(int32_t collectionInterval,
117 int32_t iterations,
118 int32_t process,
119 int32_t samplingPeriod,
120 int32_t samplingFrequency,
121 int32_t sampleDuration,
122 bool stackProfile,
123 bool useElfSymbolizer,
124 bool sendToDropbox) {
Andreas Gampeb019ddc2018-04-02 10:58:32 -0700125 auto config_fn = [&](ThreadedConfig& config) {
126 config = ThreadedConfig(); // Reset to a default config.
Andreas Gampe9590c642017-12-27 10:57:34 -0800127
Andreas Gampe5a7181b2018-04-20 17:11:22 -0700128 if (collectionInterval >= 0) {
129 config.collection_interval_in_s = collectionInterval;
130 }
131 if (iterations >= 0) {
132 config.main_loop_iterations = iterations;
133 }
134 if (process >= 0) {
135 config.process = process;
136 }
137 if (samplingPeriod > 0) {
138 config.sampling_period = samplingPeriod;
139 }
140 if (samplingFrequency > 0) {
141 config.sampling_frequency = samplingFrequency;
142 }
143 if (sampleDuration > 0) {
144 config.sample_duration_in_s = sampleDuration;
145 }
146 config.stack_profile = stackProfile;
147 config.use_elf_symbolizer = useElfSymbolizer;
148 config.send_to_dropbox = sendToDropbox;
Andreas Gampe9590c642017-12-27 10:57:34 -0800149 };
Andreas Gampeb019ddc2018-04-02 10:58:32 -0700150 std::string error_msg;
151 if (!StartProfiling(config_fn, &error_msg)) {
152 return Status::fromExceptionCode(1, error_msg.c_str());
153 }
154 return Status::ok();
Andreas Gampe9590c642017-12-27 10:57:34 -0800155}
Andreas Gampe9301b6f2018-04-27 15:15:34 -0700156Status PerfProfdNativeService::startProfilingString(const String16& config) {
157 ConfigReader reader;
158 std::string error_msg;
159 // Split configuration along colon.
160 std::vector<std::string> args = base::Split(String8(config).string(), ":");
161 for (auto& arg : args) {
Andreas Gampeac743a32018-05-24 09:43:37 -0700162 if (!reader.Read(arg, /* fail_on_error */ true, &error_msg)) {
163 std::string tmp = base::StringPrintf("Could not parse %s: %s",
164 arg.c_str(),
165 error_msg.c_str());
166 return Status::fromExceptionCode(1, tmp.c_str());
Andreas Gampe9301b6f2018-04-27 15:15:34 -0700167 }
168 }
169 auto config_fn = [&](ThreadedConfig& config) {
170 config = ThreadedConfig(); // Reset to a default config.
171 reader.FillConfig(&config);
172 };
173 if (!StartProfiling(config_fn, &error_msg)) {
174 return Status::fromExceptionCode(1, error_msg.c_str());
175 }
176 return Status::ok();
177}
Andreas Gampe9590c642017-12-27 10:57:34 -0800178Status PerfProfdNativeService::startProfilingProtobuf(const std::vector<uint8_t>& config_proto) {
179 auto proto_loader_fn = [&config_proto](ProfilingConfig& proto_config) {
180 return proto_config.ParseFromArray(config_proto.data(), config_proto.size());
181 };
182 return StartProfilingProtobuf(proto_loader_fn);
183}
184
Andreas Gampe9590c642017-12-27 10:57:34 -0800185template <typename ProtoLoaderFn>
186Status PerfProfdNativeService::StartProfilingProtobuf(ProtoLoaderFn fn) {
187 ProfilingConfig proto_config;
188 if (!fn(proto_config)) {
189 return binder::Status::fromExceptionCode(2);
190 }
Andreas Gampeb019ddc2018-04-02 10:58:32 -0700191 auto config_fn = [&proto_config](ThreadedConfig& config) {
192 config = ThreadedConfig(); // Reset to a default config.
Andreas Gampe9590c642017-12-27 10:57:34 -0800193
194 // Copy proto values.
195#define CHECK_AND_COPY_FROM_PROTO(name) \
196 if (proto_config.has_ ## name ()) { \
197 config. name = proto_config. name (); \
198 }
199 CHECK_AND_COPY_FROM_PROTO(collection_interval_in_s)
200 CHECK_AND_COPY_FROM_PROTO(use_fixed_seed)
201 CHECK_AND_COPY_FROM_PROTO(main_loop_iterations)
202 CHECK_AND_COPY_FROM_PROTO(destination_directory)
203 CHECK_AND_COPY_FROM_PROTO(config_directory)
204 CHECK_AND_COPY_FROM_PROTO(perf_path)
205 CHECK_AND_COPY_FROM_PROTO(sampling_period)
Andreas Gampe04ea5f62018-05-09 13:42:18 -0700206 CHECK_AND_COPY_FROM_PROTO(sampling_frequency)
Andreas Gampe9590c642017-12-27 10:57:34 -0800207 CHECK_AND_COPY_FROM_PROTO(sample_duration_in_s)
208 CHECK_AND_COPY_FROM_PROTO(only_debug_build)
209 CHECK_AND_COPY_FROM_PROTO(hardwire_cpus)
210 CHECK_AND_COPY_FROM_PROTO(hardwire_cpus_max_duration_in_s)
211 CHECK_AND_COPY_FROM_PROTO(max_unprocessed_profiles)
212 CHECK_AND_COPY_FROM_PROTO(stack_profile)
213 CHECK_AND_COPY_FROM_PROTO(collect_cpu_utilization)
214 CHECK_AND_COPY_FROM_PROTO(collect_charging_state)
215 CHECK_AND_COPY_FROM_PROTO(collect_booting)
216 CHECK_AND_COPY_FROM_PROTO(collect_camera_active)
Andreas Gampe92176812017-12-27 19:20:45 -0800217 CHECK_AND_COPY_FROM_PROTO(process)
Andreas Gampe95438542018-01-09 16:18:35 -0800218 CHECK_AND_COPY_FROM_PROTO(use_elf_symbolizer)
Andreas Gampe83476be2017-12-28 12:02:12 -0800219 CHECK_AND_COPY_FROM_PROTO(send_to_dropbox)
Andreas Gampe28a379f2018-03-28 15:51:33 -0700220 CHECK_AND_COPY_FROM_PROTO(compress)
Andreas Gampe9590c642017-12-27 10:57:34 -0800221#undef CHECK_AND_COPY_FROM_PROTO
222 };
Andreas Gampeb019ddc2018-04-02 10:58:32 -0700223 std::string error_msg;
224 if (!StartProfiling(config_fn, &error_msg)) {
225 return Status::fromExceptionCode(1, error_msg.c_str());
226 }
227 return Status::ok();
Andreas Gampe9590c642017-12-27 10:57:34 -0800228}
229
230Status PerfProfdNativeService::StartProfilingProtobufFd(int fd) {
231 auto proto_loader_fn = [fd](ProfilingConfig& proto_config) {
232 struct IstreamCopyingInputStream : public google::protobuf::io::CopyingInputStream {
233 IstreamCopyingInputStream(int fd_in)
234 : stream(base::StringPrintf("/proc/self/fd/%d", fd_in),
235 std::ios::binary | std::ios::in) {
236 }
237
238 int Read(void* buffer, int size) override {
239 stream.read(reinterpret_cast<char*>(buffer), size);
240 size_t count = stream.gcount();
241 if (count > 0) {
242 return count;
243 }
244 return -1;
245 }
246
247 std::ifstream stream;
248 };
249 std::unique_ptr<IstreamCopyingInputStream> is(new IstreamCopyingInputStream(fd));
250 std::unique_ptr<google::protobuf::io::CopyingInputStreamAdaptor> is_adaptor(
251 new google::protobuf::io::CopyingInputStreamAdaptor(is.get()));
252 return proto_config.ParseFromZeroCopyStream(is_adaptor.get());
253 };
254 return StartProfilingProtobuf(proto_loader_fn);
Andreas Gampec445aff2017-12-27 10:44:42 -0800255}
256
257Status PerfProfdNativeService::stopProfiling() {
Andreas Gampeb019ddc2018-04-02 10:58:32 -0700258 std::string error_msg;
259 if (!StopProfiling(&error_msg)) {
260 Status::fromExceptionCode(1, error_msg.c_str());
Andreas Gampec445aff2017-12-27 10:44:42 -0800261 }
Andreas Gampec445aff2017-12-27 10:44:42 -0800262 return Status::ok();
263}
264
Andreas Gampe9590c642017-12-27 10:57:34 -0800265status_t PerfProfdNativeService::shellCommand(int in,
Andreas Gampec445aff2017-12-27 10:44:42 -0800266 int out,
Andreas Gampef73ddfa2018-03-29 14:52:57 -0700267 int err_fd,
Andreas Gampec445aff2017-12-27 10:44:42 -0800268 Vector<String16>& args) {
269 if (android::base::kEnableDChecks) {
270 LOG(VERBOSE) << "Perfprofd::shellCommand";
271
272 for (size_t i = 0, n = args.size(); i < n; i++) {
273 LOG(VERBOSE) << " arg[" << i << "]: '" << String8(args[i]).string() << "'";
274 }
275 }
276
Andreas Gampef73ddfa2018-03-29 14:52:57 -0700277 auto err_str = std::fstream(base::StringPrintf("/proc/self/fd/%d", err_fd));
278
Andreas Gampec445aff2017-12-27 10:44:42 -0800279 if (args.size() >= 1) {
280 if (args[0] == String16("dump")) {
281 dump(out, args);
282 return OK;
283 } else if (args[0] == String16("startProfiling")) {
Andreas Gampef73ddfa2018-03-29 14:52:57 -0700284 ConfigReader reader;
285 for (size_t i = 1; i < args.size(); ++i) {
Andreas Gampeac743a32018-05-24 09:43:37 -0700286 std::string error_msg;
287 if (!reader.Read(String8(args[i]).string(), /* fail_on_error */ true, &error_msg)) {
288 err_str << "Could not parse '" << String8(args[i]).string() << "': " << error_msg
Andreas Gampef73ddfa2018-03-29 14:52:57 -0700289 << std::endl;
290 return BAD_VALUE;
291 }
Andreas Gampec445aff2017-12-27 10:44:42 -0800292 }
Andreas Gampeb019ddc2018-04-02 10:58:32 -0700293 auto config_fn = [&](ThreadedConfig& config) {
294 config = ThreadedConfig(); // Reset to a default config.
Andreas Gampef73ddfa2018-03-29 14:52:57 -0700295 reader.FillConfig(&config);
296 };
Andreas Gampeb019ddc2018-04-02 10:58:32 -0700297 std::string error_msg;
298 if (!StartProfiling(config_fn, &error_msg)) {
299 err_str << error_msg << std::endl;
Andreas Gampef73ddfa2018-03-29 14:52:57 -0700300 return UNKNOWN_ERROR;
Andreas Gampec445aff2017-12-27 10:44:42 -0800301 }
Andreas Gampeb019ddc2018-04-02 10:58:32 -0700302 return OK;
Andreas Gampe9590c642017-12-27 10:57:34 -0800303 } else if (args[0] == String16("startProfilingProto")) {
304 if (args.size() < 2) {
305 return BAD_VALUE;
306 }
307 int fd = -1;
308 if (args[1] == String16("-")) {
309 fd = in;
310 } else {
311 // TODO: Implement reading from disk?
312 }
313 if (fd < 0) {
Andreas Gampef73ddfa2018-03-29 14:52:57 -0700314 err_str << "Bad file descriptor " << args[1] << std::endl;
Andreas Gampe9590c642017-12-27 10:57:34 -0800315 return BAD_VALUE;
316 }
317 binder::Status status = StartProfilingProtobufFd(fd);
318 if (status.isOk()) {
319 return OK;
320 } else {
Andreas Gampef73ddfa2018-03-29 14:52:57 -0700321 err_str << status.toString8() << std::endl;
322 return UNKNOWN_ERROR;
Andreas Gampe9590c642017-12-27 10:57:34 -0800323 }
Andreas Gampec445aff2017-12-27 10:44:42 -0800324 } else if (args[0] == String16("stopProfiling")) {
325 Status status = stopProfiling();
326 if (status.isOk()) {
327 return OK;
328 } else {
Andreas Gampef73ddfa2018-03-29 14:52:57 -0700329 err_str << status.toString8() << std::endl;
330 return UNKNOWN_ERROR;
Andreas Gampec445aff2017-12-27 10:44:42 -0800331 }
332 }
333 }
334 return BAD_VALUE;
335}
336
337status_t PerfProfdNativeService::onTransact(uint32_t _aidl_code,
338 const Parcel& _aidl_data,
339 Parcel* _aidl_reply,
340 uint32_t _aidl_flags) {
341 switch (_aidl_code) {
342 case IBinder::SHELL_COMMAND_TRANSACTION: {
343 int in = _aidl_data.readFileDescriptor();
344 int out = _aidl_data.readFileDescriptor();
345 int err = _aidl_data.readFileDescriptor();
346 int argc = _aidl_data.readInt32();
347 Vector<String16> args;
348 for (int i = 0; i < argc && _aidl_data.dataAvail() > 0; i++) {
349 args.add(_aidl_data.readString16());
350 }
351 sp<IBinder> unusedCallback;
352 sp<IResultReceiver> resultReceiver;
353 status_t status;
354 if ((status = _aidl_data.readNullableStrongBinder(&unusedCallback)) != OK)
355 return status;
356 if ((status = _aidl_data.readNullableStrongBinder(&resultReceiver)) != OK)
357 return status;
358 status = shellCommand(in, out, err, args);
359 if (resultReceiver != nullptr) {
360 resultReceiver->send(status);
361 }
362 return OK;
363 }
364
365 default:
Andreas Gampe109780d2018-04-25 22:00:53 -0700366 return ::android::os::BnPerfProfd::onTransact(
367 _aidl_code, _aidl_data, _aidl_reply, _aidl_flags);
Andreas Gampec445aff2017-12-27 10:44:42 -0800368 }
369}
370
Andreas Gampeb019ddc2018-04-02 10:58:32 -0700371} // namespace
372
Andreas Gampec445aff2017-12-27 10:44:42 -0800373int Main() {
374 android::status_t ret;
375 if ((ret = PerfProfdNativeService::start()) != android::OK) {
376 LOG(ERROR) << "Unable to start InstalldNativeService: %d" << ret;
377 exit(1);
378 }
379
380 android::IPCThreadState::self()->joinThreadPool();
381
382 LOG(INFO) << "Exiting perfprofd";
383 return 0;
384}
385
386} // namespace binder
387} // namespace perfprofd
388} // namespace android